function [uOutput] = import_gismo_catalog(nfunction, catalog)
    % import from a GISMO Catalog object
    % Catalog objects are part of the GISMO suite
    %
    % to get helptext:
    %   [helpstring] = import_gismo_catalog(0)
    %
    % to retrieve Catalog stored in file
    %   [uOutput] = import_gismo_catalog(1, filename)
    %
    % to convert Catalog stored in memory
    %   [uOutput] = import_gismo_catalog(1, catalog) % name will be name of variable

    % created by Celso G Reyes, 2017

    % ZMAP format is 10 columns: longitude, latitude, decimal year, month, day,
    % magnitude, depth, hour, minute, second
    uOutput = [];

    if nfunction==0   % Return info about filter
        uOutput = 'GISMO Catalog - import catalog from the GISMO suite';
        return
    end
    if nfunction ==2
        uOutput = 'gismo.html';
        return
    end

    if ~exist('Catalog','class')
        uOutput(['Cannot import catalog, since Catalog class (and probably GISMO) is not installed.',...
            'Last known whereabouts: https://github.com/geoscience-community-codes/GISMO']);
        return
    end
    if ischar(catalog)
        % filename
        if exist(catalog,'file')
            fn = catalog;
            catalog=load(fn);
        end
    end

    if exist('catalog','var') && isa(catalog,'Catalog')
        tb=table(datetime(datevec(catalog.otime)),...
            catalog.lat,...
            catalog.lon,...
            catalog.depth,...
            catalog.mag,...
            catalog.magtype,...
            'VariableNames',{'Date','Latitude','Longitude','Depth','Magnitude','MagnitudeType'});
        uOutput=ZmapCatalog.from(tb);

        uOutput.Name=inputname(2);

    else
        uOutput = 'unable to import Catalog';
    end
end


% pop_select() - given an input EEG dataset structure, output a new EEG data structure
%                retaining and/or excluding specified time/latency, data point, channel,
%                and/or epoch range(s).
% Usage:
%   >> OUTEEG = pop_select(INEEG, 'key1', value1, 'key2', value2 ...);
%
% Graphic interface:
%   "Time range" - [edit box] RETAIN only the indicated epoch latency or continuous data
%                  time range: [low high] in ms, inclusive. For continuous data, several
%                  time ranges may be specified, separated by semicolons.
%                  Example: "5 10; 12 EEG.xmax" will retain the indicated
%                  stretches of continuous data, and remove data portions outside
%                  the indicated ranges, e.g. from 0 s to 5 s and from 10 s to 12 s.
%                  Command line equivalent: 'time' (or 'notime' - see below)
%   "Time range" - [checkbox] EXCLUDE the indicated latency range(s) from the data.
%                  For epoched data, it is not possible to remove a range of latencies
%                  from the middle of the epoch, so either the low and/or the high values
%                  in the specified latency range (see above) must be at an epoch boundary
%                  (EEG.xmin, EEGxmax).  Command line equivalent: [if checked] 'notime'
%   "Point range" - [edit box] RETAIN the indicated data point range(s).
%                  Same options as for the "Time range" features (above).
%                  Command line equivalent: 'point' (or 'nopoint' - see below).
%   "Point range" - [checkbox] EXCLUDE the indicated point range(s).
%                  Command line equivalent: [if checked] 'nopoint'
%   "Epoch range" - [edit box] RETAIN the indicated data epoch indices in the dataset.
%                  This checkbox is only visible for epoched datasets.
%                  Command line equivalent: 'trial' (or 'notrial' - see below)
%   "Epoch range" - [checkbox] EXCLUDE the specified data epochs.
%                   Command line equivalent: [if checked] 'notrial'
%   "Channel range" - [edit box] RETAIN the indicated vector of data channels
%                  Command line equivalent: 'channel' (or 'nochannel' - see below)
%   "Channel range" - [checkbox] EXCLUDE the indicated channels.
%                  Command line equivalent: [if checked] 'nochannel'
%   "..." - [button] select channels by name.
%   "Scroll dataset" - [button] call the eegplot() function to scroll the
%                  channel activities in a new window for visual inspection.
%                  Commandline equivalent: eegplot() - see its help for details.
% Inputs:
%   INEEG         - input EEG dataset structure
%
% Optional inputs
%   'time'        - [min max] in seconds. Epoch latency or continuous data time range
%                   to retain in the new dataset, (Note: not ms, as in the GUI text entry
%                   above). For continuous data (only), several time ranges can be specified,
%                   separated by semicolons. Example: "5 10; 12 EEG.xmax" will retain
%                   the indicated times ranges, removing data  outside the indicated ranges
%                   e.g. here from 0 to 5 s and from 10 s to 12 s. (See also, 'notime')
%   'notime'      - [min max] in seconds. Epoch latency or continuous dataset time range
%                   to exclude from the new dataset. For continuous data, may be
%                   [min1 max1; min2 max2; ...] to exclude several time ranges. For epoched
%                   data, the latency range must include an epoch boundary, as latency
%                   ranges in the middle of epochs cannot be removed from epoched data.
%   'point'       - [min max] epoch or continuous data point range to retain in the new
%                   dataset. For continuous datasets, this may be [min1 max1; min2 max2; ...]
%                   to retain several point ranges. (Notes: If both 'point'/'nopoint' and
%                   'time' | 'notime' are specified, the 'point' limit values take precedence.
%                   The 'point' argument was originally a point vector, now deprecated).
%   'nopoint'     - [min max] epoch or continuous data point range to exclude in the new dataset.
%                   For epoched data, the point range must include either the first (0)
%                   or the last point (EEG.pnts), as a central point range cannot be removed.
%   'trial'       - array of trial indices to retain in the new dataset
%   'notrial'     - array of trial indices to exclude from the new dataset
%   'sorttrial'   - ['on'|'off'] sort trial indices before extracting them (default: 'on').
%   'channel'     - vector of channel indices to retain in the new
%                   dataset. Can also be a cell array of channel names.
%   'nochannel'   - vector of channel indices to exclude from the new
%                   dataset. Can also be a cell array of channel names.
%   'newname'     - name for the new dataset (OUTEEG)
%
% Outputs:
%   OUTEEG        - new EEG dataset structure
%
% Note: This function performs a conjunction (AND) of all its optional inputs.
%       Using negative counterparts of all options, any logical combination is
%       possible.
%
% Author: Arnaud Delorme, CNL/Salk Institute, 2001; SCCN/INC/UCSD, 2002-
%
% see also: eeglab()

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

% 01-25-02 reformated help & license -ad
% 01-26-02 changed the format for events and trial conditions -ad
% 02-04-02 changed display format and allow for negation of inputs -ad
% 02-17-02 removed the event removal -ad
% 03-17-02 added channel info subsets selection -ad
% 03-21-02 added event latency recalculation -ad

function [EEG, com] = pop_select( EEG, varargin);

com = '';
if nargin < 1
    help pop_select;
    return;
end;

if nargin < 2
   geometry = { [1 1 1] [1 1 0.25 0.23 0.51] [1 1 0.25 0.23 0.51] [1 1 0.25 0.23 0.51] ...
           [1 1 0.25 0.23 0.51] [1] [1 1 1]};
   uilist = { ...
         { 'Style', 'text', 'string', 'Select data in:', 'fontweight', 'bold'  }, ...
         { 'Style', 'text', 'string', 'Input desired range', 'fontweight', 'bold'  }, ...
         { 'Style', 'text', 'string', 'on->remove these', 'fontweight', 'bold'  }, ...
         { 'Style', 'text', 'string', 'Time range [min max] (s)', 'fontangle', fastif(length(EEG)>1, 'italic', 'normal') }, ...
         { 'Style', 'edit', 'string', '', 'enable', fastif(length(EEG)>1, 'off', 'on') }, ...
         { }, { 'Style', 'checkbox', 'string', '    ', 'enable', fastif(length(EEG)>1, 'off', 'on') },{ }, ...
         ...
         { 'Style', 'text', 'string', 'Point range (ex: [1 10])', 'fontangle', fastif(length(EEG)>1, 'italic', 'normal') }, ...
         { 'Style', 'edit', 'string', '', 'enable', fastif(length(EEG)>1, 'off', 'on') }, ...
         { }, { 'Style', 'checkbox', 'string', '    ', 'enable', fastif(length(EEG)>1, 'off', 'on') },{ }, ...
         ...
         { 'Style', 'text', 'string', 'Epoch range (ex: 3:2:10)', 'fontangle', fastif(length(EEG)>1, 'italic', 'normal') }, ...
         { 'Style', 'edit', 'string', '', 'enable', fastif(length(EEG)>1, 'off', 'on') }, ...
         { }, { 'Style', 'checkbox', 'string', '    ', 'enable', fastif(length(EEG)>1, 'off', 'on') },{ }, ...
         ...
         { 'Style', 'text', 'string', 'Channel range' }, ...
         { 'Style', 'edit', 'string', '', 'tag', 'chans' }, ...
         { }, { 'Style', 'checkbox', 'string', '    ' }, ...
         { 'style' 'pushbutton' 'string'  '...', 'enable' fastif(isempty(EEG.chanlocs), 'off', 'on') ...
           'callback' 'tmpchanlocs = EEG(1).chanlocs; [tmp tmpval] = pop_chansel({tmpchanlocs.labels}, ''withindex'', ''on''); set(findobj(gcbf, ''tag'', ''chans''), ''string'',tmpval); clear tmp tmpchanlocs tmpval' }, ...
           { }, { }, { 'Style', 'pushbutton', 'string', 'Scroll dataset', 'enable', fastif(length(EEG)>1, 'off', 'on'), 'callback', ...
                          'eegplot(EEG.data, ''srate'', EEG.srate, ''winlength'', 5, ''limits'', [EEG.xmin EEG.xmax]*1000, ''position'', [100 300 800 500], ''xgrid'', ''off'', ''eloc_file'', EEG.chanlocs);' } {}};
   results = inputgui( geometry, uilist, 'pophelp(''pop_select'');', 'Select data -- pop_select()' );
   if length(results) == 0, return; end;

   % decode inputs
   % -------------
   args = {};
   if ~isempty( results{1} )
       if ~results{2}, args = { args{:}, 'time', eval( [ '[' results{1} ']' ] ) };
       else            args = { args{:}, 'notime', eval( [ '[' results{1} ']' ] ) }; end;
   end;

   if ~isempty( results{3} )
       if ~results{4}, args = { args{:}, 'point', eval( [ '[' results{3} ']' ] ) };
       else            args = { args{:}, 'nopoint', eval( [ '[' results{3} ']' ] ) }; end;
   end;

   if ~isempty( results{5} )
       if ~results{6}, args = { args{:}, 'trial', eval( [ '[' results{5} ']' ] ) };
       else            args = { args{:}, 'notrial', eval( [ '[' results{5} ']' ] ) }; end;
   end;

   if ~isempty( results{7} )
       [ chaninds chanlist ] = eeg_decodechan(EEG.chanlocs, results{7});
       if isempty(chanlist), chanlist = chaninds; end;
       if ~results{8}, args = { args{:}, 'channel'  , chanlist };
       else            args = { args{:}, 'nochannel', chanlist }; end;
   end;

else
    args = varargin;
end;

%----------------------------AMICA---------------------------------
if isfield(EEG.etc,'amica') && isfield(EEG.etc.amica,'prob_added')
    for index = 1:2:length(args)
       if strcmpi(args{index}, 'channel')
           args{index+1} = [ args{index+1} EEG.nbchan-(0:2*EEG.etc.amica.num_models-1)];

       end;

    end;
end;
%--------------------------------------------------------------------

% process multiple datasets
% -------------------------
if length(EEG) > 1
    [ EEG com ] = eeg_eval( 'pop_select', EEG, 'warning', 'on', 'params', args);
    return;
end;

if isempty(EEG.chanlocs), chanlist = [1:EEG.nbchan];
else                      chanlocs = EEG.chanlocs; chanlist = { chanlocs.labels };
end;
g = hlp_microcache('popselect',@finputcheck,args, { 'time'    'real'      []         []; ...
                        'notime'  'real'      []         []; ...
                        'trial'   'integer'   []         [1:EEG.trials]; ...
                        'notrial' 'integer'   []         []; ...
                        'point'   'integer'   []         []; ...
                        'nopoint' 'integer'   []         []; ...
                        'channel'   { 'integer' 'cell' }  []  chanlist;
                        'nochannel' { 'integer' 'cell' }   []  [];
                        'trialcond'   'integer'   []         []; ...
                        'notrialcond' 'integer'   []         []; ...
                        'sorttrial'   'string'    { 'on' 'off' } 'on' }, 'pop_select');
if isstr(g), error(g); end;

if strcmpi(g.sorttrial, 'on')
    g.trial = sort(setdiff( g.trial, g.notrial ));
else
    g.trial(ismember(g.trial,g.notrial)) = [];
    % still warn about & remove duplicate trials (may be removed in the future)
    [p,q] = unique(g.trial);
    if length(p) ~= length(g.trial)
        disp('Warning: trial selection contained duplicated elements, which were removed.');
    end
    g.trial = g.trial(sort(q));
end

if isempty(g.channel) && ~iscell(g.nochannel) && ~iscell(chanlist)
    g.channel = [1:EEG.nbchan];
end;

if iscell(g.channel) && ~iscell(g.nochannel) && ~isempty(EEG.chanlocs)
     noChannelAsCell = {};
     for nochanId = 1:length(g.nochannel)
         noChannelAsCell{nochanId} = EEG.chanlocs(g.nochannel(nochanId)).labels;
     end;
     g.nochannel =   noChannelAsCell;
end;

if strcmpi(g.sorttrial, 'on')
    g.channel = sort(setdiff( lower(g.channel), lower(g.nochannel) ));
else
    g.channel(ismember(lower(g.channel),lower(g.nochannel))) = [];
    % still warn about & remove duplicate channels (may be removed in the future)
    [p,q] = unique(g.channel);
    if length(p) ~= length(g.channel)
        disp('Warning: channel selection contained duplicated elements, which were removed.');
    end
    g.channel = g.channel(sort(q));
end

if ~isempty(EEG.chanlocs)
    if strcmpi(g.sorttrial, 'on')
        g.channel = eeg_decodechan(EEG.chanlocs, g.channel);
    else
        % we have to protect the channel order against changes by eeg_decodechan
        if iscell(g.channel)
            % translate channel names into indices
            [inds,names] = eeg_decodechan(EEG.chanlocs, g.channel);
            % and sort the indices back into the original order of channel names
            [tmp,I] = ismember(lower(g.channel),lower(names));
            g.channel = inds(I);
        end
    end
end;

if ~isempty(g.time) & (g.time(1) < EEG.xmin*1000) & (g.time(2) > EEG.xmax*1000)
   error('Wrong time range');
end;
if min(g.trial) < 1 | max( g.trial ) > EEG.trials
   error('Wrong trial range');
end;
if min(g.channel) < 1 | max( g.channel ) > EEG.nbchan
   error('Wrong channel range');
end;

if size(g.point,2) > 2,
    g.point = [g.point(1) g.point(end)];
    disp('Warning: vector format for point range is deprecated');
end;
if size(g.nopoint,2) > 2,
    g.nopoint = [g.nopoint(1) g.nopoint(end)];
    disp('Warning: vector format for point range is deprecated');
end;
if ~isempty( g.point )
    g.time = zeros(size(g.point));
    for index = 1:length(g.point(:))
        g.time(index) = eeg_point2lat(g.point(index), 1, EEG.srate, [EEG.xmin EEG.xmax]);
    end;
    g.notime = [];
end;
if ~isempty( g.nopoint )
    g.notime = zeros(size(g.nopoint));
    for index = 1:length(g.nopoint(:))
        g.notime(index) = eeg_point2lat(g.nopoint(index), 1, EEG.srate, [EEG.xmin EEG.xmax]);
    end;
    g.time = [];
end;
if ~isempty( g.notime )
    if size(g.notime,2) ~= 2
        error('Time/point range must contain 2 columns exactly');
    end;
    if g.notime(2) == EEG.xmax
        g.time = [EEG.xmin g.notime(1)];
    else
        if g.notime(1) == EEG.xmin
            g.time = [g.notime(2) EEG.xmax];
        elseif EEG.trials > 1
            error('Wrong notime range. Remember that it is not possible to remove a slice of time for data epochs.');
        end;
    end;
    if floor(max(g.notime(:))) > EEG.xmax || min(g.notime(:)) < EEG.xmin
        error('Time/point range out of data limits');
    end;
end;
if ~isempty(g.time)
    if size(g.time,2) ~= 2
        error('Time/point range must contain 2 columns exactly');
    end;
    for index = 1:length(g.time)
        if g.time(index) > EEG.xmax
            g.time(index) = EEG.xmax;
            disp('Upper time limits exceed data, corrected');
        elseif g.time(index) < EEG.xmin
            g.time(index) = EEG.xmin;
            disp('Lower time limits exceed data, corrected');
        end;
    end;
end;

% select trial values
%--------------------
if ~isempty(g.trialcond)
   try, tt = struct( g.trialcond{:} ); catch
      error('Trial conditions format error');
   end;
   ttfields = fieldnames (tt);
   for index = 1:length(ttfields)
        if ~isfield( EEG.epoch, ttfields{index} )
            error([ ttfields{index} 'is not a field of EEG.epoch' ]);
        end;
        tmpepoch = EEG.epoch;
	    eval( [ 'Itriallow  = find( [ tmpepoch(:).' ttfields{index} ' ] >= tt.' ttfields{index} '(1) );' ] );
	    eval( [ 'Itrialhigh = find( [ tmpepoch(:).' ttfields{index} ' ] <= tt.' ttfields{index} '(end) );' ] );
	    Itrialtmp = intersect(Itriallow, Itrialhigh);
	    g.trial = intersect( g.trial(:)', Itrialtmp(:)');
   end;
end;

if isempty(g.trial)
   error('Empty dataset, no trial');
end;
if length(g.trial) ~= EEG.trials
	fprintf('Removing %d trial(s)...\n', EEG.trials - length(g.trial));
end;
if length(g.channel) ~= EEG.nbchan
	fprintf('Removing %d channel(s)...\n', EEG.nbchan - length(g.channel));
end;

% For AMICA probabilities...
%-----------------------------------------------------
if isfield(EEG.etc, 'amica') && ~isempty(EEG.etc.amica) && isfield(EEG.etc.amica, 'v_smooth') && ~isempty(EEG.etc.amica.v_smooth) && ~isfield(EEG.etc.amica,'prob_added')
    if isfield(EEG.etc.amica, 'num_models') && ~isempty(EEG.etc.amica.num_models)
        if size(EEG.data,2) == size(EEG.etc.amica.v_smooth,2) && size(EEG.data,3) == size(EEG.etc.amica.v_smooth,3) && size(EEG.etc.amica.v_smooth,1) == EEG.etc.amica.num_models

            EEG = eeg_formatamica(EEG);

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

            [EEG com] = pop_select(EEG,args{:});

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

            EEG = eeg_reformatamica(EEG);
            EEG = eeg_checkamica(EEG);
            return;
        else
            disp('AMICA probabilities not compatible with size of data, probabilities cannot be rejected')

            disp('Resuming rejection...')
        end
    end

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

% recompute latency and epoch number for events
% ---------------------------------------------
if length(g.trial) ~= EEG.trials & ~isempty(EEG.event)
    if ~isfield(EEG.event, 'epoch')
        disp('Pop_epoch warning: bad event format with epoch dataset, removing events');
        EEG.event = [];
    else
		if isfield(EEG.event, 'epoch')
			keepevent = [];
			for indexevent = 1:length(EEG.event)
				newindex = find( EEG.event(indexevent).epoch == g.trial );
				if ~isempty(newindex)
					keepevent = [keepevent indexevent];
					if isfield(EEG.event, 'latency')
						EEG.event(indexevent).latency = EEG.event(indexevent).latency - (EEG.event(indexevent).epoch-1)*EEG.pnts + (newindex-1)*EEG.pnts;
					end;
					EEG.event(indexevent).epoch = newindex;
				end;
			end;
            diffevent = setdiff([1:length(EEG.event)], keepevent);
			if ~isempty(diffevent)
				disp(['Pop_select: removing ' int2str(length(diffevent)) ' unreferenced events']);
				EEG.event(diffevent) = [];
			end;
		end;
    end;
end;

% performing removal
% ------------------
if ~isempty(g.time) | ~isempty(g.notime)
    if EEG.trials > 1
        % select new time window
        % ----------------------
        try,   tmpevent = EEG.event;
               tmpeventlatency = [ tmpevent.latency ];
        catch, tmpeventlatency = [];
        end;
        alllatencies = 1-(EEG.xmin*EEG.srate); % time 0 point
        alllatencies = linspace( alllatencies, EEG.pnts*(EEG.trials-1)+alllatencies, EEG.trials);
        [EEG.data tmptime indices epochevent]= epoch(EEG.data, alllatencies, ...
                                                     [g.time(1) g.time(2)]*EEG.srate, 'allevents', tmpeventlatency);
        tmptime = tmptime/EEG.srate;
        if g.time(1) ~= tmptime(1) & g.time(2)-1/EEG.srate ~= tmptime(2)
            fprintf('pop_select(): time limits have been adjusted to [%3.3f %3.3f] to fit data points limits\n', tmptime(1), tmptime(2)+1/EEG.srate);
        end;
        EEG.xmin = tmptime(1);
        EEG.xmax = tmptime(2);
        EEG.pnts = size(EEG.data,2);
        alllatencies = alllatencies(indices);

        % modify the event structure accordingly (latencies and add epoch field)
        % ----------------------------------------------------------------------
        allevents = [];
        newevent = [];
        count = 1;
        if ~isempty(epochevent)
            newevent = EEG.event(1);
            for index=1:EEG.trials
                for indexevent = epochevent{index}
                    newevent(count)         = EEG.event(indexevent);
                    newevent(count).epoch   = index;
                    newevent(count).latency = newevent(count).latency - alllatencies(index) - tmptime(1)*EEG.srate + 1 + EEG.pnts*(index-1);
                    count = count + 1;
                end;
            end;
        end;
        EEG.event = newevent;

        % erase event-related fields from the epochs
        % ------------------------------------------
        if ~isempty(EEG.epoch)
            fn = fieldnames(EEG.epoch);
            EEG.epoch = rmfield(EEG.epoch,{fn{strmatch('event',fn)}});
        end;
    else
        if isempty(g.notime)
            if length(g.time) == 2 && EEG.xmin < 0
                disp('Warning: negative minimum time; unchanged to ensure correct latency of initial boundary event');
            end;
            g.notime = g.time';
            g.notime = g.notime(:);
            if g.notime(1) ~= 0, g.notime = [EEG.xmin g.notime(:)'];
            else                 g.notime = [g.notime(2:end)'];
            end;
            if g.time(end) == EEG.xmax, g.notime(end) = [];
            else                        g.notime(end+1) = EEG.xmax;
            end;

            for index = 1:length(g.notime)
                if g.notime(index) ~= 0  & g.notime(index) ~= EEG.xmax
                    if mod(index,2), g.notime(index) = g.notime(index) + 1/EEG.srate;
                    else             g.notime(index) = g.notime(index) - 1/EEG.srate;
                    end;
                end;
            end;
            g.notime = reshape(g.notime, 2, length(g.notime)/2)';
        end;

        nbtimes = length(g.notime(:));
        points = eeg_lat2point(g.notime(:)', ones(1,nbtimes), EEG.srate, [EEG.xmin EEG.xmax]);
        points = reshape(points, size(g.notime));
        EEG = eeg_eegrej(EEG, points);
    end
end;

% performing removal
% ------------------
if ~isequal(g.channel,1:size(EEG.data,1)) || ~isequal(g.trial,1:size(EEG.data,3))
    EEG.data  = EEG.data(g.channel, :, g.trial);
    if isfield(EEG,'srcpot') && ~isempty(EEG.srcpot)
        EEG.srcpot = EEG.srcpot(:, :, g.trial);  % TODO: this is an ugly hack
    end
end
if ~isempty(EEG.icaact), EEG.icaact = EEG.icaact(:,:,g.trial); end;
EEG.trials    = length(g.trial);
EEG.pnts      = size(EEG.data,2);
EEG.nbchan    = length(g.channel);
if ~isempty(EEG.chanlocs)
    EEG.chanlocs = EEG.chanlocs(g.channel);
end;
if ~isempty(EEG.epoch)
   EEG.epoch = EEG.epoch( g.trial );
end;
if ~isempty(EEG.specdata)
	if length(g.point) == EEG.pnts
   		EEG.specdata = EEG.specdata(g.channel, :, g.trial);
   	else
   		EEG.specdata = [];
   		fprintf('Warning: spectral data were removed because of the change in the numner of points\n');
   	end;
end;

% ica specific
% ------------
if ~isempty(EEG.icachansind)

    rmchans = setdiff( EEG.icachansind, g.channel ); % channels to remove

    % channel sub-indices
    % -------------------
    icachans = 1:length(EEG.icachansind);
    for index = length(rmchans):-1:1
        chanind           = find(EEG.icachansind == rmchans(index));
        icachans(chanind) = [];
    end;

    % new channels indices
    % --------------------
    count   = 1;
    newinds = [];
    for index = 1:length(g.channel)
        if any(EEG.icachansind == g.channel(index))
            newinds(count) = index;
            count          = count+1;
        end;
    end;
    EEG.icachansind = newinds;

else
    icachans = 1:size(EEG.icasphere,2);
end;

if ~isempty(EEG.icasphere)
    EEG.icasphere = EEG.icasphere(:,icachans);
end;
if ~isempty(EEG.icawinv)
    EEG.icawinv = EEG.icawinv(icachans,:);
end;
if ~isempty(EEG.specicaact)
    if length(g.point) == EEG.pnts
        EEG.specicaact = EEG.specicaact(icachans, :, g.trial);
    else
        EEG.specicaact = [];
        fprintf('Warning: spectral ICA data were removed because of the change in the numner of points\n');
    end;
end;

% for stats, can adapt remove the selected trials and electrodes
% in the future to gain time -----------------------------------
EEG.reject = struct('rejmanual',{[]});
EEG.stats = struct('jp',{[]});
EEG = eeg_checkset(EEG, 'eventconsistency');

% generate command
% ----------------
if nargout > 1
com = sprintf('EEG = pop_select( %s,%s);', inputname(1), vararg2str(args));
end

return;

% ********* OLD, do not remove any event any more
% ********* in the future maybe do a pack event to remove events not in the time range of any epoch

if ~isempty(EEG.event)
    % go to array format if necessary
    if isstruct(EEG.event), format = 'struct';
    else                     format = 'array';
    end;
    switch format, case 'struct', EEG = eventsformat(EEG, 'array'); end;

    % keep only events related to the selected trials
    Indexes = [];
    Ievent  = [];
    for index = 1:length( g.trial )
        currentevents = find( EEG.event(:,2) == g.trial(index));
        Indexes = [ Indexes ones(1, length(currentevents))*index ];
        Ievent  = union( Ievent, currentevents );
    end;
    EEG.event = EEG.event( Ievent,: );
    EEG.event(:,2) = Indexes(:);

    switch format, case 'struct', EEG = eventsformat(EEG, 'struct'); end;
end;


function [vertex,face,edge,mesh] = mesh_emse2matlab(file,options)

% mesh_emse2matlab - Convert EMSE mesh (.wfr) to matlab format
%
% USEAGE: [vertices,faces,edges,meshtype] = mesh_emse2matlab(file,[options])
%
% All values returned are in meters.  With the returned structures,
% create a vertex & face matrix:
%
%   vertex_matrix = [vertices.x; vertices.y; vertices.z]';
%   face_matrix = [faces.vertex1;faces.vertex2;faces.vertex3]';
%
% These can be input to the patch command:
%
%    Hpatch = patch('Vertices',vertex_matrix,'Faces',face_matrix,...
%                   'EdgeColor',[.6 .6 .6],'FaceColor',[0.9 0.9 0.9]);
%
% See the patch and light commands to colour this object.
%
% 'options' ... a cell array of strings.  By default it contains
% options = {'vertex','face','edge'}.  By default, this routine
% reads all available data from the emse file.  If 'options' is given
% and it doesn't contain one of these strings, that data will not be
% read or returned.
%
% meshtype is: 'unknown','scalp','outer skull','inner skull', or 'cortex'
%

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

% Licence:  GNU GPL, no implied or express warranties
% History:  10/98 Abbas Kouzani (egazk@flinders.edu.au)
%           09/01 Darren.Weber_at_radiology.ucsf.edu
%                 - created function, rather than script
%                 - added functionality to handle different
%                   minor revisions.
%           03/02 Darren.Weber_at_radiology.ucsf.edu
%                 - optimised fscanf processes for matlab, the
%                   function now operates in less than 1/2 time,
%                   especially for revision 3 data.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if ~exist('options','var'),
    options = {'vertex','face','edge'};
end

[path,name,ext] = fileparts(file);
file = fullfile(path,[name ext]);

[fid,msg] = fopen(file,'r');
if ~isempty(msg), error(msg); end

tic;

% Read prolog
version   =fscanf(fid,'%f',1);
file_type =fscanf(fid,'%f',1);
minor_rev =fscanf(fid,'%f',1);

fprintf('...WFR Version = %d, Minor_Revision = %d, File-Type = %d\n',...
    version,minor_rev,file_type);

if ~(file_type==8000 | file_type==4000)
    S=sprintf('Could not convert WFR file type: %d',file_type);
    error(S);
end

% Read header (format depends on minor revision)
if(minor_rev==3)
    type      =fscanf(fid,'%f',1);
else
	radius    =fscanf(fid,'%f',1);
	vertex_no =fscanf(fid,'%d',1);
	face_no   =fscanf(fid,'%d',1);
	edge_no   =fscanf(fid,'%d',1);

    fprintf('...Radius = %f meters\n',radius);
    %...Vertices = %d\n...Patches = %d\n...Edges = %d\n',...
    %    vertex_no,face_no,edge_no);

    if(minor_rev==1), type = 0;
    else,             type = fscanf(fid,'%f',1);
    end
end

if(minor_rev==1)
    mesh = 'unknown';
else
	switch type
        case 0,             mesh = 'unknown';
        case { 64,  40},    mesh = 'scalp';
        case {128,  80},    mesh = 'outer skull';
        case {256, 100},    mesh = 'inner skull';
        case {512, 200},    mesh = 'cortex';
        otherwise,          mesh = 'unknown';
	end
end

fprintf('...Mesh type: %s\n',mesh);

% Read data (format depends on minor revision)
vertex = struct([]);
face = struct([]);
edge = struct([]);

if(minor_rev==3)

    % Read the whole file
    fprintf('...Reading Minor Revision 3 Data File');
    Tmp = fscanf(fid,'%s%f%f%f',[4,inf]);
    fprintf('...done\n');

    % Vertices
    if(max(strcmp('vertex',options)) > 0),
        fprintf('...Creating Vertices Struct');
        % first get the numeric code for 'v'
        vcode = Tmp(1,1);
        % now find all columns of Tmp with vcode in 1st row
        vindex = find(Tmp(1,:) == vcode);

        tmp = Tmp(2:4,vindex);
        tmp = num2cell(tmp);
        vertex = struct(...
            'index', [1:length(vindex)],...
            'x',     tmp( 1,:),...
            'y',     tmp( 2,:),...
            'z',     tmp( 3,:));
        clear tmp;
        fprintf('...done\n');
    else
        fprintf('...Skipping Vertices Struct\n');
    end

    % Faces
    if(max(strcmp('face',options)) > 0),
        fprintf('...Creating Faces Struct');
        % first get the numeric code for 't'
        tcode = Tmp(1,length(vindex)+1);
        % now find all columns of Tmp with tcode in 1st row
        tindex = find(Tmp(1,:) == tcode);

        % matlab vertex indices start at one,
        % not zero, so we add one to these emse values
        tmp = Tmp(2:4,tindex) + 1;

        tmp = num2cell(tmp);
        face = struct(...
            'index',   [1:length(tindex)],...
            'vertex1', tmp( 1,:),...
            'vertex2', tmp( 2,:),...
            'vertex3', tmp( 3,:));
        clear tmp;
        fprintf('...done\n');
    else
        fprintf('...Skipping Faces Struct\n');
    end

    % Edges
    fprintf('...No edges for minor revision 3\n');
    clear Tmp;

elseif(minor_rev~=4)
    % minor revision 1 & 2 format
    disp('...Reading Minor Revision 1 or 2 Data');
    if(max(strcmp('vertex',options)) > 0),
        fprintf('...Reading %d Vertices',vertex_no);

        tmp = zeros(13,vertex_no);
        tmp = fscanf(fid,'%d%x%d%d%g%g%g%g%g%g%g%g%g',[13,vertex_no]);

        tmp(1,:) = tmp(1,:) + 1;
        tmp      = num2cell(tmp);
        vertex   = struct(...
            'index',        tmp( 1,:),...
            'address',      tmp( 2,:),...
            'channel_index',tmp( 3,:),...
            'x',            tmp( 5,:),...
            'y',            tmp( 6,:),...
            'z',            tmp( 7,:),...
            'xnormal',      tmp( 9,:),...
            'ynormal',      tmp(10,:),...
            'znormal',      tmp(11,:),...
            'potential',    tmp(12,:),...
            'curvature',    tmp(13,:));
        clear tmp;
        fprintf('...done\n');
    else
        fprintf('...Skipping %d Vertices\n',vertex_no);
        tmp = zeros(13,vertex_no);
        tmp = fscanf(fid,'%d%x%d%d%g%g%g%g%g%g%g%g%g',[13,vertex_no]);
        clear tmp;
    end
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if(max(strcmp('face',options)) > 0),
        fprintf('...Reading %d Faces',face_no);

        tmp = zeros(18,face_no);
        tmp = fscanf(fid,'%d%x%g%g%g%g%g%g%g%g%g%g%x%x%x%x%x%x',[18,face_no]);
        tmp(1,:) = tmp(1,:) + 1;
        tmp      = num2cell(tmp);
        face     = struct(...
            'index',        tmp( 1,:),...
            'address',      tmp( 2,:),...
            'solid_angle',  tmp( 3,:),...
            'magnitude',    tmp( 4,:),...
            'potential',    tmp( 5,:),...
            'area',         tmp( 6,:),...
            'center_x',     tmp( 7,:),...
            'center_y',     tmp( 8,:),...
            'center_z',     tmp( 9,:),...
            'normal_x',     tmp(10,:),...
            'normal_y',     tmp(11,:),...
            'normal_z',     tmp(12,:),...
            'vertex1',      tmp(13,:),...
            'vertex2',      tmp(14,:),...
            'vertex3',      tmp(15,:),...
            'edge1',        tmp(16,:),...
            'edge2',        tmp(17,:),...
            'edge3',        tmp(18,:));
        clear tmp;
        fprintf('...done\n');

        % In minor rev4, the face vertex and edges
        % refer to the vertex.address field, so this
        % is corrected here.  Not sure how to avoid 'for'
        fprintf('...Converting Face vertices from address to index (this takes a while)');
        for i=1:face_no,
            face(i).vertex1 = find([vertex.address] == face(i).vertex1);
            face(i).vertex2 = find([vertex.address] == face(i).vertex2);
            face(i).vertex3 = find([vertex.address] == face(i).vertex3);
        end
        fprintf('...done\n');
        if(max(strcmp('edge',options)) > 0),
            fprintf('...Converting Face edges from address to index (this takes a while)');
            for i=1:face_no,
                face(i).edge1 = find([vertex.address] == face(i).edge1);
                face(i).edge2 = find([vertex.address] == face(i).edge2);
                face(i).edge3 = find([vertex.address] == face(i).edge3);
            end
            fprintf('...done\n');
        end
    else
        disp('...Skipping Faces');
        tmp = zeros(18,face_no);
        tmp = fscanf(fid,'%d%x%g%g%g%g%g%g%g%g%g%g%x%x%x%x%x%x',[18,face_no]);
        clear tmp;
    end
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if(max(strcmp('edge',options)) > 0),
        fprintf('...Reading %d Edges',edge_no);

        tmp = zeros(4,edge_no);
        tmp = fscanf(fid,'%d%x%x%x',[4,edge_no]);

        tmp(1,:) = tmp(1,:) + 1;
        tmp      = num2cell(tmp);
        edge     = struct(...
            'index',        tmp(1,:),...
            'address',      tmp(2,:),...
            'vertex1',      tmp(3,:),...
            'vertex2',      tmp(4,:));
        clear tmp;
        fprintf('...done\n');
        fprintf('...Converting Edge vertices from address to index (this takes a while)');
        for i=1:edge_no,
            edge(i).vertex1 = find([vertex.address] == edge(i).vertex1);
            edge(i).vertex2 = find([vertex.address] == edge(i).vertex2);
        end
        fprintf('...done\n');
    else
        disp('...Skipping Edges');
        %for i=1:edge_no,
        %    tmp=fscanf(fid,'%*d',1);
        %    tmp=fscanf(fid,'%*x',3);
        %end
    end
else
    % minor revision 4 format
    disp('...Reading Minor Revision 4 Data');
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if(max(strcmp('vertex',options)) > 0),
        fprintf('...Reading %d Vertices',vertex_no);

        index = meshgrid(1:1:vertex_no,1);
        index = num2cell(index);

        tmp = zeros(11,vertex_no);
        tmp = fscanf(fid,'%d%d%g%g%g%d%g%g%g%g%g',[11,vertex_no]);

        tmp      = num2cell(tmp);
        vertex   = struct(...
            'index',        index,...
            'channel_index',tmp( 1,:),...
            'x',            tmp( 3,:),...
            'y',            tmp( 4,:),...
            'z',            tmp( 5,:),...
            'xnormal',      tmp( 7,:),...
            'ynormal',      tmp( 8,:),...
            'znormal',      tmp( 9,:),...
            'potential',    tmp(10,:),...
            'curvature',    tmp(11,:));
        clear tmp index;
        fprintf('...done\n');
    else
        disp('...Skipping Vertices');
        tmp = zeros(11,vertex_no);
        tmp = fscanf(fid,'%d%d%g%g%g%d%g%g%g%g%g',[11,vertex_no]);
    end
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if(max(strcmp('face',options)) > 0),
        fprintf('...Reading %d Faces',face_no);

        index = meshgrid(1:1:face_no,1);
        index = num2cell(index);

        tmp = zeros(16,face_no);
        tmp = fscanf(fid,'%g%g%g%g%g%g%g%g%g%g%d%d%d%d%d%d',[16,face_no]);

        tmp(11:16,:) = tmp(11:16,:) + 1;

        tmp      = num2cell(tmp);
        face     = struct(...
            'index',        index,...
            'solid_angle',  tmp( 1,:),...
            'magnitude',    tmp( 2,:),...
            'potential',    tmp( 3,:),...
            'area',         tmp( 4,:),...
            'center_x',     tmp( 5,:),...
            'center_y',     tmp( 6,:),...
            'center_z',     tmp( 7,:),...
            'normal_x',     tmp( 8,:),...
            'normal_y',     tmp( 9,:),...
            'normal_z',     tmp(10,:),...
            'vertex1',      tmp(11,:),...
            'vertex2',      tmp(12,:),...
            'vertex3',      tmp(13,:),...
            'edge1',        tmp(14,:),...
            'edge2',        tmp(15,:),...
            'edge3',        tmp(16,:));
        clear tmp index;
        fprintf('...done\n');
    else
        disp('...Skipping Faces');
        tmp = zeros(16,face_no);
        tmp = fscanf(fid,'%g%g%g%g%g%g%g%g%g%g%d%d%d%d%d%d',[16,face_no]);
    end
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if(max(strcmp('edge',options)) > 0),
        fprintf('...Reading %d Edges',edge_no);

        index = meshgrid(1:1:edge_no,1);
        address = num2cell(index * 0);
        index = num2cell(index);

        tmp = zeros(2,edge_no);
        tmp = fscanf(fid,'%d%d',[2,edge_no]);
        tmp = tmp + 1;
        tmp = num2cell(tmp);

        edge = struct(...
            'index',   index,...
            'address', address,...
            'vertex1', tmp(1,:),...
            'vertex2', tmp(2,:));
        clear tmp index address;
        fprintf('...done\n');
    else
        fprintf('...Skipping Edges\n');
        %tmp=fscanf(fid,'%*d',2*edge_no);
    end
end

fclose(fid);
t=toc;
fprintf('...done (%5.2f sec)\n',t);

return


classdef SingleTargetMeasurementSimulatorX < MeasurementSimulatorX
% SingleTargetMeasurementSimulatorX class
%
% Summary of SingleTargetMeasurementSimulatorX:
%   Class implementation of a single-target measurement simulator
%
% SingleTargetMeasurementSimulatorX Properties:
%   + Model - A StateSpaceModelX object defining the base models used by the simulator
%
% SingleTargetMeasurementSimulatorX Methods:
%   + SingleTargetMeasurementSimulatorX - Constructor method
%   + simulate() - Generate measurements from ground-truth data
%
% (+) denotes puplic properties/methods
%
% See also MeasurementModelX and ClutterModelX template classes

    methods
        function this = SingleTargetMeasurementSimulatorX(varargin)
        % SingleTargetMeasurementSimulatorX Construct a measurement simulator object
        %
        % Parameters
        % ----------
        % Model: StateSpaceModelX object
        %   A state-space model that should define the following models:
        %       + Measurement - Object handle to MeasurementModelX SubClass
        %       + Clutter - Object handle to ClutterModelX SubClass
        %       + Detection - Object handle to DetectionModelX SubClass

            % Call super-class
            this@MeasurementSimulatorX(varargin{:});

        end

        function MeasurementScans = simulate(this, Track, varargin)
        % simulate Simulate measurements given a set of ground truth data
        %
        % Parameters
        % ----------
        % Track: GroundTruthTrackX
        %   An object containing ground-truth information for a single-target.
        %   Detections will be generated on the basis of the Trajectory
        %   property for each track.
        %
        % Returns
        % -------
        % MeasurementScans: (1 x NumScans) MeasurementListX array
        %   An object array, whose elements contain the simulated measurement
        %   scan at each timestep.

            % Dummy Detection probability
            MeasurementScans = MeasurementListX.empty();

            % Initialise storage
            numTimesteps = numel(Track.Trajectory);

            for k = 1:numTimesteps

                targetState = Track.Trajectory(k);
                timestamp = targetState.Timestamp;

                % Compute number of tracks and clutter measurements
                detectionProbability = 1;
                if ~isempty(this.Model.Clutter)
                    detectionProbability = this.Model.Detection.pdf(targetState.Vector);
                end

                targetDetected = binornd(1,detectionProbability);
                numClutter = 0;
                if ~isempty(this.Model.Clutter)
                    numClutter = this.Model.Clutter.random('cardinality');
                end
                numMeasurements = targetDetected + numClutter;

                % Empty MeasurementX array
                measurements = MeasurementX.empty(0, numMeasurements);

                % Generate true measurement
                if targetDetected
                    measurementVector = this.Model.Measurement.feval(targetState.Vector,true);
                    measurements(end+1) = MeasurementX(measurementVector, timestamp, this.Model);
                end

                % Generate clutter measurements
                if(numClutter>0)
                    clutterVectors = this.Model.Clutter.random(numClutter);
                    for clutterVector = clutterVectors
                        measurements(end+1) = MeasurementX(clutterVector, timestamp, this.Model);
                    end
                end

                MeasurementScans(k) = MeasurementListX(measurements);
            end

        end
    end
end


function [fname] = gtopo30s(latlim,lonlim)

    %GTOPO30S (30-arc-sec resolution) DEM file names
    %
    % fname = GTOPO30S(LATLIM,LONLIM) returns a cellarray of the file
    % names covering the geographic region for GTOPO30 digital elevation maps
    % (also referred to as "30-arc second" DEMs).  The region is specified by
    % scalar latitude and longitude points, or two element vectors of latitude
    % and longitude limits in units of degrees.
    %
    % The data is available over the Internet via anonymous ftp from
    % <ftp://edcftp.cr.usgs.gov/pub/data/gtopo30/global>. The data and
    % some documentation is also available over the World-Wide-Web from
    % <http://edcwww.cr.usgs.gov/landdaac/gtopo30/gtopo30.html> and
    % <http://edcwww.cr.usgs.gov/landdaac/gtopo30/README.html>.
    %
    % See also: GTOPO30

    %  Written by:  A. Kim, W. Stumpf, L. Job
    %  Copyright 1996-2000 Systems Planning and Analysis, Inc. and The MathWorks, Inc.
    %  $Revision: 1399 $ $Date: 2006-08-11 11:19:27 +0200 (Fr, 11 Aug 2006) $

    % ensure row vectors
    latlim = latlim(:)';
    lonlim = lonlim(:)';

    if nargin~=2
        error('Incorrect number of arguments')
    end

    if  isequal(size(latlim),[1 1])
        latlim = latlim*[1 1];
    elseif ~isequal(size(latlim),[1 2])
        error('Latitude limit input must be a scalar or 2 element vector')
    end

    if isequal(sort(size(lonlim)),[1 1])
        lonlim = lonlim*[1 1];
    elseif ~isequal(sort(size(lonlim)),[1 2])
        error('Longitude limit input must be a scalar or 2 element vector')
    end

    fid = fopen('gtopo30s.dat','r');
    if fid==-1
        error('Couldn''t open gtopo30s.dat')
    end

    % preallocate bounding rectangle data for speed

    YMIN = zeros(1,33); YMAX = YMIN;
    XMIN = YMIN; XMAX = YMIN;

    % read names and bounding rectangle limits

    for n=1:33
        fnames{n,1} = fscanf(fid,'%s',1);
        YMIN(n) = fscanf(fid,'%d',1);
        YMAX(n) = fscanf(fid,'%d',1);
        XMIN(n) = fscanf(fid,'%d',1);
        XMAX(n) = fscanf(fid,'%d',1);
    end
    fclose(fid);

    % case where dateline is not crossed
    if lonlim(1) <= lonlim(2)
        do = ...
            find( ...
            (...
            (latlim(1) <= YMIN & latlim(2) >= YMAX) | ... % tile is completely within region
            (latlim(1) >= YMIN & latlim(2) <= YMAX) | ... % region is completely within tile
            (latlim(1) >  YMIN & latlim(1) <  YMAX) | ... % min of region is on tile
            (latlim(2) >  YMIN & latlim(2) <  YMAX)   ... % max of region is on tile
            ) ...
            &...
            (...
            (lonlim(1) <= XMIN & lonlim(2) >= XMAX) | ... % tile is completely within region
            (lonlim(1) >= XMIN & lonlim(2) <= XMAX) | ... % region is completely within tile
            (lonlim(1) >  XMIN & lonlim(1) <  XMAX) | ... % min of region is on tile
            (lonlim(2) >  XMIN & lonlim(2) <  XMAX)   ... % max of region is on tile
            )...
            );
    end

    % case where the dateline is crossed
    if lonlim(1) > lonlim(2)
        lmin = lonlim(1); lmax = lonlim(2);
        lonlim(2) = 180;
        % do eastern side of the dateline first
        doEAST = ...
            find( ...
            (...
            (latlim(1) <= YMIN & latlim(2) >= YMAX) | ... % tile is completely within region
            (latlim(1) >= YMIN & latlim(2) <= YMAX) | ... % region is completely within tile
            (latlim(1) >  YMIN & latlim(1) <  YMAX) | ... % min of region is on tile
            (latlim(2) >  YMIN & latlim(2) <  YMAX)   ... % max of region is on tile
            ) ...
            &...
            (...
            (lonlim(1) <= XMIN & lonlim(2) >= XMAX) | ... % tile is completely within region
            (lonlim(1) >= XMIN & lonlim(2) <= XMAX) | ... % region is completely within tile
            (lonlim(1) >  XMIN & lonlim(1) <  XMAX) | ... % min of region is on tile
            (lonlim(2) >  XMIN & lonlim(2) <  XMAX)   ... % max of region is on tile
            )...
            );
        % do western side of the dateline second
        lonlim(1) = -180; lonlim(2) = lmax;
        doWEST = ...
            find( ...
            (...
            (latlim(1) <= YMIN & latlim(2) >= YMAX) | ... % tile is completely within region
            (latlim(1) >= YMIN & latlim(2) <= YMAX) | ... % region is completely within tile
            (latlim(1) >  YMIN & latlim(1) <  YMAX) | ... % min of region is on tile
            (latlim(2) >  YMIN & latlim(2) <  YMAX)   ... % max of region is on tile
            ) ...
            &...
            (...
            (lonlim(1) <= XMIN & lonlim(2) >= XMAX) | ... % tile is completely within region
            (lonlim(1) >= XMIN & lonlim(2) <= XMAX) | ... % region is completely within tile
            (lonlim(1) >  XMIN & lonlim(1) <  XMAX) | ... % min of region is on tile
            (lonlim(2) >  XMIN & lonlim(2) <  XMAX)   ... % max of region is on tile
            )...
            );
        % concatenate indices
        do = [doEAST doWEST];
    end

    if ~isempty(do)
        fname = fnames(do);
    else
        fname = [];
    end


% std_selsubject() - Helper function for std_erpplot(), std_specplot()
%                    and std_erspplot() to select specific subject when
%                    plotting channel data.
% Usage:
%  >> data = std_selsubject( data, subject, setinds, allsubjects);
%
% Inputs:
%  data  -  [cell array] mean data for each subject group and/or data
%           condition. For example, to compute mean ERPs statistics from a
%           STUDY for epochs of 800 frames in two conditions from three
%           groups of 12 subjects,
%           >> data = { [800x12] [800x12] [800x12];... % 3 groups, cond 1
%                       [800x12] [800x12] [800x12] };  % 3 groups, cond 2
% subject - [string] subject name
% setinds - [cell array] set indices for each of the last dimension of the
%           data cell array.
%           >> setinds = { [12] [12] [12];... % 3 groups, cond 1
%                          [12] [12] [12] };  % 3 groups, cond 2
% allsubject - [cell array] all subjects (same order as in
%              STUDY.datasetinfo)
%
% Output:
%  data       - [cell array] data array with the subject or component selected
%
% Author: Arnaud Delorme, CERCO, CNRS, 2006-
%
% See also: std_erpplot(), std_specplot() and std_erspplot()

function [data] = std_selsubject(data, subject, setinds, allsubjects, optndims);

if nargin < 2
    help std_selsubject;
    return;
end;

optndims = max(optndims, ndims(data{1}));
if isempty(strmatch(lower(subject), lower(allsubjects)))
    error(sprintf('Cannot select subject %s in list %s', subject, vararg2str({ allsubjects })));
end;

% plot specific subject
% ---------------------
if size(setinds{1},1) > 1 && size(setinds{1},2) > 1 % single trials
    % possible subject indices
    selectInds = strmatch(lower(subject), lower(allsubjects));
    for c = 1:size(data,1)
        for g = 1:size(data,2)
            selectCol = [];
            for ind = 1:length(selectInds)
                selectCol = [ selectCol find(setinds{c,g}  == selectInds') ];
            end;
            if optndims == 2
                data{c,g} = data{c,g}(:,selectCol); %2-D
            elseif optndims == 3
                data{c,g} = data{c,g}(:,:,selectCol); %3-D
            else
                data{c,g} = data{c,g}(:,:,:,selectCol); %4-D
            end;
        end;
    end;
else
    for c = 1:size(data,1)
        for g = 1:size(data,2)
            subjectind = strmatch(lower(subject), lower(allsubjects));
            l = zeros(size(setinds{c,g}));
            for iSubj = 1:length(subjectind), l = l | setinds{c,g} == subjectind(iSubj); end;
            if optndims == 2
                data{c,g}(:,~l) = []; %2-D
            elseif optndims == 3
                data{c,g}(:,:,~l) = []; %3-D
            else
                data{c,g}(:,:,:,~l) = []; %4-D
            end;
        end;
    end;
end;


function [headmodel] = ft_datatype_headmodel(headmodel, varargin)

% FT_DATATYPE_HEADMODEL describes the FieldTrip MATLAB structure for a volume
% conduction model of the head that can be used for forward computations of
% the EEG potentials or the MEG fields. The volume conduction model represents
% the geometrical and the conductive properties of the head. These determine
% how the secondary (or impressed) currents flow and how these contribute to
% the model potential or field.
%
% A large number of forward solutions for the EEG and MEG are supported
% in FieldTrip, each with its own specification of the MATLAB structure that
% describes the volume conduction model of th ehead. It would be difficult to
% list all the possibilities here. One common feature is that the volume
% conduction model should specify its type, and that preferably it should
% specify the geometrical units in which it is expressed (e.g. mm, cm or m).
%
% An example of an EEG volume conduction model with 4 concentric spheres is:
%
% headmodel =
%        r: [86 88 94 100]
%        c: [0.33 1.00 0.042 0.33]
%        o: [0 0 0]
%     type: 'concentricspheres'
%     unit: 'mm'
%
% An example of an MEG volume conduction model with a single sphere fitted to
% the scalp with its center 4 cm above the line connecting the ears is:
%
% headmodel =
%        r: [12]
%        o: [0 0 4]
%     type: 'singlesphere'
%     unit: 'cm'
%
% For each of the methods XXX for the volume conduction model, a corresponding
% function FT_HEADMODEL_XXX exists that contains all specific details and
% references to literature that describes the implementation.
%
% Required fields:
%   - type
%
% Optional fields:
%   - unit
%
% Deprecated fields:
%   - inner_skull_surface, source_surface, skin_surface, source, skin
%
% Obsoleted fields:
%   - <none specified>
%
% Revision history:
%
% (2015/latest) Use the field name "pos" instead of "pnt" for vertex positions.
%
% (2014) All numeric values are represented in double precision.
%
% (2013) Always use the field "cond" for conductivity.
%
% (2012) Use consistent names for the volume conductor type in the structure, the
% documentation and for the actual implementation, e.g. bem_openmeeg -> openmeeg,
% fem_simbio -> simbio, concentric -> concentricspheres. Deprecated the fields
% that indicate the index of the innermost and outermost surfaces.
%
% See also FT_PREPARE_HEADMODEL, FT_DATATYPE, FT_DATATYPE_COMP, FT_DATATYPE_DIP,
% FT_DATATYPE_FREQ, FT_DATATYPE_MVAR, FT_DATATYPE_RAW, FT_DATATYPE_SOURCE,
% FT_DATATYPE_SPIKE, FT_DATATYPE_TIMELOCK, FT_DATATYPE_VOLUME

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

% get the optional input arguments, which should be specified as key-value pairs
version = ft_getopt(varargin, 'version', 'latest');

if strcmp(version, 'latest')
  version = '2015';
end

if isempty(headmodel)
  return;
end

if iscell(headmodel)
  % this might represent combined EEG, ECoG and/or MEG
  for i=1:numel(headmodel)
    % call recursively
    headmodel{i} = ft_datatype_headmodel(headmodel{i}, varargin{:});
  end
  return
end

switch version

  case '2015'
    % first make it consistent with the 2014 version
    headmodel = ft_datatype_headmodel(headmodel, 'version', '2013');

    % rename pnt into pos
    headmodel = fixpos(headmodel);

  case '2014'
    % first make it consistent with the 2013 version
    headmodel = ft_datatype_headmodel(headmodel, 'version', '2013');

    % ensure that all numbers are represented in double precision
    headmodel = ft_struct2double(headmodel);

  case '2013'
    % first make it consistent with the 2012 version
    headmodel = ft_datatype_headmodel(headmodel, 'version', '2012');

    % then rename (if necessary the c into cond
    if isfield(headmodel, 'c') && ~isfield(headmodel, 'cond')
      headmodel.cond = headmodel.c;
      headmodel = rmfield(headmodel, 'c');
    elseif isfield(headmodel, 'cond') && isfield(headmodel, 'c') && isequal(headmodel.cond, headmodel.c)
      headmodel = rmfield(headmodel, 'c');
    elseif isfield(headmodel, 'cond') && isfield(headmodel, 'c') && ~isequal(headmodel.cond, headmodel.c)
      ft_error('inconsistent specification of conductive properties for %s model', headmodel.type);
    end

  case '2012'
    % the following will be determined on the fly in ft_prepare_vol_sens
    if isfield(headmodel, 'skin_surface'),        headmodel = rmfield(headmodel, 'skin_surface');        end
    if isfield(headmodel, 'source_surface'),      headmodel = rmfield(headmodel, 'source_surface');      end
    if isfield(headmodel, 'inner_skull_surface'), headmodel = rmfield(headmodel, 'inner_skull_surface'); end
    if isfield(headmodel, 'skin'),                headmodel = rmfield(headmodel, 'skin');                end
    if isfield(headmodel, 'source'),              headmodel = rmfield(headmodel, 'source');              end

    % ensure a consistent naming of the volume conduction model types
    % these should match with the FT_HEADMODEL_XXX functions
    if isfield(headmodel, 'type')
      if strcmp(headmodel.type, 'concentric')
        headmodel.type = 'concentricspheres';
      elseif strcmp(headmodel.type, 'nolte')
        headmodel.type = 'singleshell';
      elseif strcmp(headmodel.type, 'multisphere')
        headmodel.type = 'localspheres';
      elseif strcmp(headmodel.type, 'bem_cp')
        headmodel.type = 'bemcp';
      elseif strcmp(headmodel.type, 'bem_dipoli')
        headmodel.type = 'dipoli';
      elseif strcmp(headmodel.type, 'bem_asa')
        headmodel.type = 'asa';
      elseif strcmp(headmodel.type, 'bem_openmeeg')
        headmodel.type = 'openmeeg';
      elseif strcmp(headmodel.type, 'fem_simbio')
        headmodel.type = 'simbio';
      elseif strcmp(headmodel.type, 'fdm_fns')
        headmodel.type = 'fns';
      elseif strcmp(headmodel.type, 'bem')
        ft_error('not able to convert the original ''bem'' volume type, try using headmodel.type=''dipoli''');
      elseif strcmp(headmodel.type, 'avo')
        ft_error('this format is not supported anymore');
      end
    end

    if isfield(headmodel, 'sens')
      % this applies to type=interpolate, ensure that the sensor description is up to date
      headmodel.sens = ft_datatype_sens(headmodel.sens);
    end

    if isfield(headmodel, 'type') && any(strcmp(headmodel.type, {'concentricspheres', 'singlesphere'}))
      if isfield(headmodel, 'cond') && ~isfield(headmodel, 'c')
        headmodel.c = headmodel.cond;
        headmodel = rmfield(headmodel, 'cond');
      elseif isfield(headmodel, 'cond') && isfield(headmodel, 'c') && isequal(headmodel.cond, headmodel.c)
        headmodel = rmfield(headmodel, 'cond');
      elseif isfield(headmodel, 'cond') && isfield(headmodel, 'c') && ~isequal(headmodel.cond, headmodel.c)
        ft_error('inconsistent specification of conductive properties for %s model', headmodel.type);
      end
    end

    % ensure that the geometrical units are specified
    headmodel = ft_determine_units(headmodel);

  otherwise
    ft_error('converting to version "%s" is not supported', version);
end


% Author: Guosheng Lin (guosheng.lin@gmail.com)

% this is a simpler demo file for testing on your own images.

function demo_test_simple_voc()

rng('shuffle');
addpath('./my_utils');
dir_matConvNet='../libs/matconvnet/matlab';
run(fullfile(dir_matConvNet, 'vl_setupnn.m'));

run_config=[];

run_config.use_gpu=true;
% run_config.use_gpu=false;
run_config.gpu_idx=1;

% result dir:
result_name=['runner_result_dir' datestr(now, 'YYYYmmDDHHMMSS')];
result_dir=fullfile('../cache_data', 'test_examples_voc', result_name);
mkdir_notexist(result_dir);

% the folder that contains testing images:
img_data_dir='../datasets/example_imgs_voc';

% using a trained model which is trained on VOC 2012
run_config.trained_model_path='../model_trained/refinenet_res101_voc2012.mat';
run_config.class_info=gen_class_info_voc();

% for trained model, control the size of input images
run_config.input_img_short_edge_min=450;
run_config.input_img_short_edge_max=600;

runner_info=prepare_runner_test_simple(run_config);

img_filenames=my_list_file(img_data_dir);
img_num=length(img_filenames);
for img_idx=1:img_num
    task_info=[];
    task_info.img_dir=img_data_dir;
    task_info.img_filename=img_filenames{img_idx};
    task_result=runner_info.run_task_fn(runner_info, task_info);

    [~, img_name]=fileparts(task_info.img_filename);
    one_cache_file=fullfile(result_dir, [img_name '.png']);
    fprintf('save predict mask:%s\n', one_cache_file);
    imwrite(task_result.mask_data, run_config.class_info.mask_cmap, one_cache_file);
end

end


function [iSourceRows, iRegionScouts, iVertices] = bst_convert_indices(iVertices, nComponents, GridAtlas, isSurfaceInd)
% BST_CONVERT_INDICES: Convert scout indices (in GridLoc or Vertices matrix) to indices in ImageGridAmp/ImagingKernel
%
% USAGE:  [iSourceRows, iRegionScouts, iVertices] = bst_convert_indices(iVertices, nComponents, GridAtlas, isSurfaceInd)
%
% INPUT:
%    - iVertices    : Array of vertex indices of the source space, to reference to rows in Results.GridLoc (volume) or Surface.Vertices (surface)
%                     If empty, use all the vertices
%    - nComponents  : Number of entries per vertex in SourceValues (1,2,3)
%                     If 0, the number varies, the properties of each region are defined in input GridAtlas
%    - GridAtlas    : Set of scouts that defines the properties of the source space regions, when nComponents=0
%                     GridAtlas.Scouts(i).Region(2) is the source type (V=volume, S=surface, D=dba, X=exclude)
%                     GridAtlas.Scouts(i).Region(3) is the orientation constrain (U=unconstrained, C=contrained, L=loose)
%    - isSurfaceInd : If 1, the indices iVertices are referring to Surface.Vertices, and require a conversion in the case of mixed models
%                     If 0, the indices iVertices are referring to Results.GridLoc
%
% OUTPUT:
%    - iSourceRows   : Array of vertex indices of the source space, to reference to rows in Results.GridLoc (volume)
%    - iRegionScouts : List of the scout indices in GridAtlas that are involved in the list of vertices iGridLoc
%    - iVertices     : Modified list of vertices (when some are removed, compared with the initial iVertices)

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

% Check inputs
if (nargin ~= 4) || isempty(iVertices) || isempty(nComponents) || ((nComponents == 0) && isempty(GridAtlas))
	error('Invalid call');
end
iRegionScouts = [];

% Make sure iVertices is a row vector
iVertices = iVertices(:)';
% Get row numbers corresponding to the selected vertices
switch (nComponents)
    case 0
        % Convert indices from Surface.Vertices to Results.GridLoc
        if isSurfaceInd
            % Remove the vertices that are outside the list of vertices in Vert2Grid
            iVertices(iVertices > size(GridAtlas.Vert2Grid,2)) = [];
            % Surface.Vertices => Results.GridLoc
            iVertices = find(any(GridAtlas.Vert2Grid(:,iVertices), 2))';
        end
        % Get indices in the ImageGridAmp/ImagingKernel matrix
        iSourceRows = find(any(GridAtlas.Grid2Source(:,iVertices), 2))';
        % Find over which regions this vertex selection spans
        if (nargout >= 2)
            iRegionScouts = find(~cellfun(@(c)isempty(intersect(c,iVertices)), {GridAtlas.Scouts.GridRows}));
        end
    case 1
        iSourceRows = sort(iVertices);
    case 2
        iSourceRows = sort([2*iVertices-1, 2*iVertices]);
    case 3
        iSourceRows = sort([3*iVertices-2, 3*iVertices-1, 3*iVertices]);
end


function pascal_car_grammar(dotrainval, testyear)

% AUTORIGHTS
% -------------------------------------------------------
% Copyright (C) 2011-2012 Ross Girshick
%
% This file is part of the voc-releaseX code
% (http://people.cs.uchicago.edu/~rbg/latent/)
% and is available under the terms of an MIT-like license
% provided in COPYING. Please retain this notice and
% COPYING if you use this file (or a portion of it) in
% your project.
% -------------------------------------------------------

% Set configuration override
global VOC_CONFIG_OVERRIDE;
if isempty(VOC_CONFIG_OVERRIDE)
  VOC_CONFIG_OVERRIDE = @voc_config_car_grammar;
end

cls = 'car';
conf = voc_config();
cachedir = conf.paths.model_dir;
testset = conf.eval.test_set;

if nargin < 1
  dotrainval = false;
end

if nargin < 2
  % which year to test on -- a string, e.g., '2007'.
  testyear = conf.pascal.year;
end

timestamp = datestr(datevec(now()), 'dd.mmm.yyyy:HH.MM.SS');

% set the note to the training time if none is given
if nargin < 3
  note = timestamp;
end

% record a log of the training and test procedure
diary(conf.training.log([cls '-' timestamp]));

th = tic;
model = pascal_train_car_grammar(note);
toc(th);
% Free feature vector cache memory
fv_cache('free');

% lower threshold to get high recall
model.thresh = min(conf.eval.max_thresh, model.thresh);
model.interval = conf.eval.interval;

ds = pascal_test(model, testset, testyear, testyear);
ap1 = pascal_eval(cls, ds, testset, testyear, testyear);
%[ap1, ap2] = bboxpred_rescore(cls, testset, testyear);

fprintf('AP = %.4f (without bounding box prediction)\n', ap1)
%fprintf('AP = %.4f (with bounding box prediction)\n', ap2)

% Clear the override
clearvars -global VOC_CONFIG_OVERRIDE;


%
% Work in progress.  Needs to be written to pay heed to sparsity.
%
function [x] = Back_Solve(A,b)
x = A\b;


%  Copyright (c) 2014, Karen Simonyan
%  All rights reserved.
%  This code is made available under the terms of the BSD license (see COPYING file).

function result = evaluate(config, scores, gt)

    scores = reshape(scores, 1, []);

    switch config
        case 'ap'
            [res, extra] = evaluation.ap.eval(config, scores, gt);
        case 'roc'
            [res, extra] = evaluation.roc.eval(config, scores, gt);
        case 'accuracy'
            [res, extra] = evaluation.accuracy.eval(config, scores, gt);
    end

        % measure name
        result.meas_name = config;

        % measure value (a scalar)
        result.measure = res;

        % extra data in a struct (e.g. optimal thresh), or empty
        result.extra = extra;

end


function [ meta ] = read_ceos_img_meta( filename )
%READ_CEOS_IMG_META Read CEOS SAR image file
%
% Written by: Wade Schwartzkopf, NGA/R
%
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////

% Open file
fid=fopen(filename,'r','b');

% Read volume descriptor records
meta.rec_num=fread(fid,1,'uint32'); % Record sequence number
meta.rec_subtype1=fread(fid,1,'uint8'); % Record subtype code
meta.rec_type=fread(fid,1,'uint8'); % Record type
meta.rec_subtype2=fread(fid,1,'uint8'); % Record subtype code
meta.rec_subtype3=fread(fid,1,'uint8'); % Record subtype code
meta.rec_length=fread(fid,1,'uint32'); % Record length
meta.ascii_ebcdic=fread(fid,2,'uint8=>char').'; % Record length
fseek(fid,2,'cof'); % Blanks
meta.doc_id=fread(fid,12,'uint8=>char').'; % Superstructure format control document ID
meta.doc_rev=fread(fid,2,'uint8=>char').'; % Superstructure format control document revision level
meta.rec_rev=fread(fid,2,'uint8=>char').'; % Superstructure record format revision level
meta.soft_rel_rev=fread(fid,12,'uint8=>char').'; % Software release and revision level
meta.file_num=fread(fid,4,'uint8=>char').'; % File number
meta.file_id=fread(fid,16,'uint8=>char').'; % File ID
meta.rec_seq_loc_type_flag=fread(fid,4,'uint8=>char').'; % Record sequency and location type flag
meta.seq_num_loc=fread(fid,8,'uint8=>char').'; % Sequence number of location
meta.fld_len_seq=fread(fid,4,'uint8=>char').'; % Field length of sequence number
meta.rec_code_loc_type_flag=fread(fid,4,'uint8=>char').'; % Records code and location type flag
meta.loc_rec_code=fread(fid,8,'uint8=>char').'; % Location of record code
meta.fld_len_code=fread(fid,4,'uint8=>char').'; % Field length of record code
meta.rec_len_loc_type_flag=fread(fid,4,'uint8=>char').'; % Record length and location type flag
meta.loc_rec_len=fread(fid,8,'uint8=>char').'; % Location of record length
meta.len_rec_len=fread(fid,4,'uint8=>char').'; % Location of record length
fseek(fid,68,'cof'); % Blanks
meta.num_data_rec=str2double(fread(fid,6,'uint8=>char')); % Number of data set records
meta.data_len=str2double(fread(fid,6,'uint8=>char')); % Data set summary record length
fseek(fid,24,'cof'); % Blanks
% Sample group data
meta.sample_len=str2double(fread(fid,4,'uint8=>char')); % Bit length per sample
meta.num_samples=str2double(fread(fid,4,'uint8=>char')); % Number of samples per data group
meta.num_bytes=str2double(fread(fid,4,'uint8=>char')); % Number of bytes per data group
meta.just_order=fread(fid,4,'uint8=>char').'; % Justification and order of samples
% SAR related data
meta.num_chan=str2double(fread(fid,4,'uint8=>char')); % Number of SAR channels
meta.num_lines=str2double(fread(fid,8,'uint8=>char')); % Number of lines per data set
meta.num_left=str2double(fread(fid,4,'uint8=>char')); % Number of left border pixels per line
meta.num_pixels=str2double(fread(fid,8,'uint8=>char')); % Number of data groups (or pixels) per line
meta.num_right=str2double(fread(fid,4,'uint8=>char')); % Number of right border pixels per line
meta.num_top=str2double(fread(fid,4,'uint8=>char')); % Number of top border lines
meta.num_bottom=str2double(fread(fid,4,'uint8=>char')); % Number of bottom border lines
meta.interleave=fread(fid,4,'uint8=>char').'; % Interleaving ID
% Record data
meta.phys_rec_line=str2double(fread(fid,2,'uint8=>char')); % Number of physical records per line
meta.phys_rec_multi_chan=str2double(fread(fid,2,'uint8=>char')); % Number of physical records per multi-channel line
meta.prefix_bytes=str2double(fread(fid,4,'uint8=>char')); % Number of bytes of prefix per record
meta.sar_data_bytes=str2double(fread(fid,8,'uint8=>char')); % Number of bytes of SAR data per record
meta.suffix_bytes=str2double(fread(fid,4,'uint8=>char')); % Number of bytes of suffix data per record
meta.pre_suf_rpt_flg=fread(fid,4,'uint8=>char').'; % Prefix/suffix repeat flag
% Prefix/suffix data locations
meta.loc_sar_data=fread(fid,8,'uint8=>char').'; % Sample data line number locator
meta.loc_sar_chan_num=fread(fid,8,'uint8=>char').'; % SAR channel number locator
meta.loc_time=fread(fid,8,'uint8=>char').'; % Time of SAR data line locator
meta.loc_leftfill=fread(fid,8,'uint8=>char').'; % Left-fill count locator
meta.loc_rightfill=fread(fid,8,'uint8=>char').'; % Right-fill count locator
meta.pad_pixels=fread(fid,4,'uint8=>char').'; % Pad pixels present indictor
fseek(fid,28,'cof'); % Blanks
meta.loc_data_qual=fread(fid,8,'uint8=>char').'; % SAR data line quality code locator
meta.loc_cal_info=fread(fid,8,'uint8=>char').'; % Calibration information field locator
meta.loc_gain=fread(fid,8,'uint8=>char').'; % Gain values field locator
meta.loc_bias=fread(fid,8,'uint8=>char').'; % Bias values field lcoator
meta.sar_datatype=fread(fid,28,'uint8=>char').'; % SAR data format type indicator
meta.sar_datatype_code=fread(fid,4,'uint8=>char').'; % SAR data format type code
meta.num_leftfill=fread(fid,4,'uint8=>char').'; % Number of left fill bits within pixel
meta.num_rightfill=fread(fid,4,'uint8=>char').'; % Number of right fill bits within pixel
meta.max_data_range=fread(fid,8,'uint8=>char').'; % Maximum data range of pixel
meta.scansar_num_bursts=fread(fid,4,'uint8=>char').'; % ScanSAR, number of burst data in this file
meta.scansar_num_lines=fread(fid,4,'uint8=>char').'; % ScanSAR, number of lines per one burst
meta.scansar_num_overlap=fread(fid,4,'uint8=>char').'; % ScanSAR, number of overlap lines with adjacent bursts
fseek(fid,260,'cof'); % Blanks
sig_start = ftell(fid);

% Pixel data
switch meta.file_id(8)
    case 'B'
        % Signal data records
        % recs = 1:meta.num_data_rec;
        % Only need the first (and maybe last) record, since these
        % per-record fields are mostly all identical except for a few
        % fields we don't need.
        recs = [1, meta.num_data_rec];
        for i = 1:numel(recs)
            fseek(fid, sig_start + (meta.prefix_bytes + ...
                (meta.num_pixels*meta.num_bytes)) * (recs(i)-1), 'bof');
            meta.signal(i).rec_num=fread(fid,1,'uint32'); % Record sequence number
            meta.signal(i).rec_subtype1=fread(fid,1,'uint8'); % Record subtype code
            meta.signal(i).rec_type=fread(fid,1,'uint8'); % Record type
            meta.signal(i).rec_subtype2=fread(fid,1,'uint8'); % Record subtype code
            meta.signal(i).rec_subtype3=fread(fid,1,'uint8'); % Record subtype code
            meta.signal(i).rec_length=fread(fid,1,'uint32'); % Record length
            % Prefix data-general information
            meta.signal(i).line_num=fread(fid,1,'uint32'); % SAR image data line number
            meta.signal(i).sar_rec_ind=fread(fid,1,'uint32'); % SAR image data record index
            meta.signal(i).left_fill=fread(fid,1,'uint32'); % Actual count of left-fill pixels
            meta.signal(i).num_pixels=fread(fid,1,'uint32'); % Actual count of data pixels
            meta.signal(i).right_fill=fread(fid,1,'uint32'); % Actual count of right-fill pixels
            % Prefix data-sensor parameters
            meta.signal(i).update_flg=fread(fid,1,'uint32'); % Sensor parameters update flag
            meta.signal(i).year=fread(fid,1,'uint32'); % Sensor acquisition year
            meta.signal(i).day=fread(fid,1,'uint32'); % Sensor acquisition day of year
            meta.signal(i).msec=fread(fid,1,'uint32'); % Sensor acquisition milli-seconds of day
            meta.signal(i).chan_id=fread(fid,1,'uint16'); % SAR channel ID
            meta.signal(i).chan_code=fread(fid,1,'uint16'); % SAR channel code
            meta.signal(i).tx_pol=fread(fid,1,'uint16'); % Transmitted polarization
            meta.signal(i).rcv_pol=fread(fid,1,'uint16'); % Received polarization
            meta.signal(i).prf=fread(fid,1,'uint32'); % PRF [mHz]
            meta.signal(i).scan_id=fread(fid,1,'uint32'); % Scan ID
            meta.signal(i).rng_comp_flg=fread(fid,1,'uint16'); % Onboard range compressed flag
            meta.signal(i).chirp_type=fread(fid,1,'uint16'); % Chirp type designator
            meta.signal(i).chirp_length=fread(fid,1,'uint32'); % Chirp length (pulse width) [nsec]
            meta.signal(i).chirp_const=fread(fid,1,'int32'); % Chirp constant coefficient [Hz]
            meta.signal(i).chirp_lin=fread(fid,1,'int32'); % Chirp linear coefficient [Hz/usec]
            meta.signal(i).chirp_quad=fread(fid,1,'int32'); % Chirp quadratic coefficient [Hz/usec^2]
            meta.signal(i).usec=fread(fid,1,'uint64'); % Sensor acquisition micro-second of day (rounded or floored)
            meta.signal(i).gain=fread(fid,1,'uint32'); % Receiver gain [dB]
            meta.signal(i).invalid_flg=fread(fid,1,'uint32'); % Invalid line flag
            meta.signal(i).elec_ele=fread(fid,1,'int32'); % Electronic elevation angle at nadir of antenna [deg]
            meta.signal(i).mech_ele=fread(fid,1,'int32'); % Mechanical elevation angle at nadir of antenna [deg]
            meta.signal(i).elec_squint=fread(fid,1,'int32'); % Electronic antenna squint angle [deg]
            meta.signal(i).mech_squint=fread(fid,1,'int32'); % Mechanical antenna squint angle [deg]
            meta.signal(i).slant_rng=fread(fid,1,'uint32'); % Slant range to 1st data sample [m]
            meta.signal(i).wind_pos=fread(fid,1,'uint32'); % Data record window position (SAMPLE DELAY [nsec])
            fseek(fid,4,'cof'); % Blanks
            % Prefix data-platform reference information
            meta.signal(i).pos_update_flg=fread(fid,1,'uint32'); % Platform position parameters update flag
            meta.signal(i).plat_lat=fread(fid,1,'int32'); % Platform latitude [1/1,000,000 deg]
            meta.signal(i).plat_lon=fread(fid,1,'int32'); % Platform longitude [1/1,000,000 deg]
            meta.signal(i).plat_alt=fread(fid,1,'int32'); % Platform altitude [m]
            meta.signal(i).grnd_spd=fread(fid,1,'int32'); % Platform ground speed [cm/sec]
            meta.signal(i).vel_x=fread(fid,1,'int32'); % Platform velocity X [cm/sec]
            meta.signal(i).vel_y=fread(fid,1,'int32'); % Platform velocity Y [cm/sec]
            meta.signal(i).vel_z=fread(fid,1,'int32'); % Platform velocity Z [cm/sec]
            meta.signal(i).acc_x=fread(fid,1,'int32'); % Platform acceleration X [cm/sec^2]
            meta.signal(i).acc_y=fread(fid,1,'int32'); % Platform acceleration X [cm/sec^2]
            meta.signal(i).acc_z=fread(fid,1,'int32'); % Platform acceleration X [cm/sec^2]
            meta.signal(i).track=fread(fid,1,'int32'); % Platform track angle [1/1,000,000 deg]
            meta.signal(i).true_track=fread(fid,1,'int32'); % Platform rue track angle [1/1,000,000 deg]
            meta.signal(i).pitch=fread(fid,1,'int32'); % Platform pitch angle [1/1,000,000 deg]
            meta.signal(i).roll=fread(fid,1,'int32'); % Platform roll angle [1/1,000,000 deg]
            meta.signal(i).yaw=fread(fid,1,'int32'); % Platform yaw angle [1/1,000,000 deg]
            % Prefix data-sensor/facility specific auxiliary data
            meta.signal(i).lat_first=fread(fid,1,'int32'); % Latitude of 1st pixel [1/1,000,000 deg]
            meta.signal(i).lat_center=fread(fid,1,'int32'); % Latitude of center pixel [1/1,000,000 deg]
            meta.signal(i).lat_last=fread(fid,1,'int32'); % Latitude of last pixel [1/1,000,000 deg]
            meta.signal(i).lon_first=fread(fid,1,'int32'); % Longitude of 1st pixel [1/1,000,000 deg]
            meta.signal(i).lon_center=fread(fid,1,'int32'); % Longitude of center pixel [1/1,000,000 deg]
            meta.signal(i).lon_last=fread(fid,1,'int32'); % Longitude of last pixel [1/1,000,000 deg]
            % ScanSAR burst data parameters
            meta.signal(i).burst_num=fread(fid,1,'uint32'); % ScanSAR, burst number
            meta.signal(i).line_num=fread(fid,1,'uint32'); % ScanSAR, line number in this burst
            fseek(fid,60,'cof'); % Blanks
            meta.signal(i).frame_num=fread(fid,1,'uint32'); % ALOS2 frame number
            % fseek(fid,256,'cof'); % PALSAR auxiliary data
            % fseek(fid,meta.num_pixels*meta.num_bytes,'cof'); % SAR data
        end
    case {'C','D'}
        % Processed data records
        disp('Processed data');
end

% Close file
fclose(fid);

end

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