function test_suite = test_surficial_io_gifti
% tests for GIFTI input/output
%
% #   For CoSMoMVPA's copyright information and license terms,   #
% #   see the COPYING file distributed with CoSMoMVPA.           #
    try % assignment of 'localfunctions' is necessary in Matlab >= 2016
        test_functions=localfunctions();
    catch % no problem; early Matlab versions can use initTestSuite fine
    end
    initTestSuite;

function test_gifti_dataset_io()
    if cosmo_skip_test_if_no_external('gifti')
        return;
    end

    ds=cosmo_synthetic_dataset('ntargets',2,'nchunks',1,...
                        'type','surface');
    ds.a.fdim.values{1}=1+[1 4 7 8 5 3];

    encodings=get_gifti_encodings();
    orders=get_indexing_orders();

    fn=cosmo_make_temp_filename('_tmp','.gii');
    cleaner=onCleanup(@()delete(fn));

    % only test subset
    ntest=2;

    n_encodings=numel(encodings);
    n_orders=numel(orders);

    rp=randperm(n_encodings*n_orders);
    test_idxs=rp(1:ntest);

    counter=0;
    for k=1:numel(encodings)
        encoding=encodings{k};
        for j=1:numel(orders)
            counter=counter+1;
            if ~any(test_idxs==counter)
                continue;
            end

            order=orders{j};

            cosmo_map2surface(ds,fn,'encoding',encoding);
            ds2=cosmo_surface_dataset(fn);
            assert_dataset_equal(ds,ds2);

            g_str=get_gifti_string(encoding, order);
            fid=fopen(fn,'w');
            fprintf(fid,'%s',g_str);
            fclose(fid);

            ds3=cosmo_surface_dataset(fn);
            assert_dataset_equal(ds,ds3);

            g=gifti(fn);
            assertElementsAlmostEqual(double(g.cdata)',ds.samples,...
                                            'absolute',1e-5);
            node_indices=ds.a.fdim.values{1}(ds.fa.node_indices);
            assertEqual(double(g.indices)',node_indices);

            g2=cosmo_map2surface(ds,'-gii');
            assertElementsAlmostEqual(g.cdata,g2.cdata,...
                                            'absolute',1e-5);
            assertEqual(g.indices,g2.indices);
        end
    end

function assert_dataset_equal(x,y)
    assertElementsAlmostEqual(x.samples,y.samples,'absolute',1e-5);
    assertEqual(sort(fieldnames(x)),sort(fieldnames(y)));
    assertEqual(x.fa,y.fa);
    assertEqual(x.a,y.a);

function string=get_gifti_string(encoding, indexing_order)
    header=get_header();
    body=get_data_arrays(encoding, indexing_order);
    footer=get_footer();

    string=[header body footer];

function string=get_header()
    string=sprintf(['<?xml version="1.0" encoding="UTF-8"?>\n'...
                '<!DOCTYPE GIFTI SYSTEM "http://gifti.projects.nitr'...
                        'c.org/gifti.dtd">\n'...
                '<GIFTI Version="1.0"  NumberOfDataArrays="3">\n'...
                '   <MetaData>\n'...
                '      <MD>\n'...
                '         <Name><![CDATA[UniqueID]]></Name>\n'...
                '         <Value><![CDATA[XYZ_Uj6iYZUAV3HKbGirxcn-c'...
                        'A]]></Value>\n'...
                '      </MD>\n'...
                '   </MetaData>\n'...
                '   <LabelTable/>\n'...
                ]);

function string=get_footer()
    string='</GIFTI>';

function encodings=get_gifti_encodings()
    encodings={'ASCII','Base64Binary','GZipBase64Binary'};

function orders=get_indexing_orders()
    orders={'ColumnMajorOrder','RowMajorOrder'};

function string=get_data_array_helper(data_str, encoding, data_type, ...
                                               indexing_order, intent)
    check_one('encoding',encoding,...
                    get_gifti_encodings());
    check_one('data_type',data_type,...
                    {'NIFTI_TYPE_INT32','NIFTI_TYPE_FLOAT32'});
    check_one('indexing_order',indexing_order,...
                    get_indexing_orders());

    string=sprintf([...
                '   <DataArray Intent="%s"\n'...
                '              DataType="%s"\n'...
                '              ArrayIndexingOrder="%s"\n'...
                '              Dimensionality="1"\n'...
                '              Dim0="6"\n'...
                '              Encoding="%s"\n'...
                '              Endian="LittleEndian"\n'...
                '              ExternalFileName=""\n'...
                '              ExternalFileOffset="">\n'...
                '      <MetaData>\n'...
                '         <MD>\n'...
                '            <Name><![CDATA[Name]]></Name>\n'...
                '            <Value><![CDATA[numeric]]></Value>\n'...
                '         </MD>\n'...
                '      </MetaData>\n'...
                '      <Data>\n%s'...
                '      </Data>\n'...
                '   </DataArray>\n'...
                ], intent, data_type, indexing_order, encoding, data_str);

function string=get_data_arrays(encoding, indexing_order)
    switch encoding
        case 'ASCII'
            data={sprintf([ '        2.031686\n'...
                            '        -3.684948\n'...
                            '        -1.050449\n'...
                            '        1.349442\n'...
                            '        -0.261723\n'...
                            '        -0.203955\n'...
                  ]),...
                  sprintf([ '        0.583806\n'...
                            '        1.723501\n'...
                            '        -1.326491\n'...
                            '        -0.397334\n'...
                            '        2.338657\n'...
                            '        0.482345\n'...
                  ]),...
                  sprintf([ '         1 \n'...
                            '         4  \n'...
                            '         7 \n'...
                            '         8 \n'...
                            '         5 \n'...
                            '         3 \n'...
                  ])};
        case 'Base64Binary'
            data={'JQcCQDDWa8AddYa/hLqsP48Ahr6U2VC+',...
                  'T3QVP66b3D91yqm/XW/Lvo6sFUDt9fY+',...
                  'AQAAAAQAAAAHAAAACAAAAAUAAAADAAAA',...
                  };
        case 'GZipBase64Binary'
            data={  'eAEBGADn/yUHAkAw1mvAHXWGv4S6rD+PAIa+lNlQvnPfCu4=',...
                    'eAEBGADn/090FT+um9w/dcqpv11vy76OrBVA7fX2PpcYDR0=',...
                    'eAEBGADn/wEAAAAEAAAABwAAAAgAAAAFAAAAAwAAAAGEAB0='...
                    };
    end

    narrays=numel(data);
    arrays_cell=cell(1,narrays);

    data_types={'NIFTI_TYPE_FLOAT32',...
                'NIFTI_TYPE_FLOAT32',...
                'NIFTI_TYPE_INT32',...
                };
    intents={'NIFTI_INTENT_NONE',...
                'NIFTI_INTENT_NONE',...
                'NIFTI_INTENT_NODE_INDEX'};

    assert(numel(data_types)==narrays);
    assert(numel(intents)==narrays);

    for k=1:narrays
        arrays_cell{k}=get_data_array_helper(data{k}, encoding, ...
                                            data_types{k}, ...
                                            indexing_order, intents{k});
    end

    string=cat(2,arrays_cell{:});

function check_one(label, value, allowed)
    if isempty(strmatch(value, allowed))
        error('illegal value for %s: %s', label, value);
    end


function [present]  = isReactionInSubSystem(model,reactions,subSystem)
% Determine whether a reaction is in a given subSystem.
%
% USAGE:
%
%    [subSystems]  = getModelSubSystems(model)
%
% INPUT:
%    model:                 A COBRA model struct with at least rxns and
%                           subSystems fields
%    reactions:             Either a string identifying a reaction, or a
%                           cell array of strings identifying multiple
%                           reactions, or a double vector identifying the
%                           positions.
%    subSystem:             A String identifying a subsystem.
% OUTPUT:
%    present:               a boolean vector for each provided reaction.
%
% USAGE:
%    %Get all subSystems present in the model.
%    [subSystems]  = getModelSubSystems(model)
%
% .. Author: - Thomas Pfau Nov 2017

if ischar(reactions)
    reactions = {reactions};
end

if iscell(reactions)
    [~,reactions] = ismember(reactions,model.rxns);
end

if isfield(model, 'subSystems')
    present = cellfun(@(x) any(ismember(x,subSystem)),model.subSystems(reactions));
else
    present = false(numel(reactions));
end


function [err,v, typ] = BrikInfo_SectionValue (BRIKinfo, sSection)
%
%   [err,s, typ] = BrikInfo_SectionValue (sHead, sSection)
%
%Purpose:
%   Get the values of a section in the .HEAD string
%   This function is dedicated for BrikInfo function
%
%Input Parameters:
%   sHead, a string vector containing the .HEAD info
%   sSection, the section name such as: 'DATASET_DIMENSIONS'
%
%
%Output Parameters:
%   err : 0 No Problem
%       : 1 Mucho Problems
%   v a vector (or a string) containing the values in that section
%     v is empty (and err = 1) if the section can't be found
%   typ : is a string to indicate the type of parameter (string or number)
%      that v is
%
%Key Terms:
%
%More Info :
%  see also BrikInfo
%
%
%
%     Author : Ziad Saad
%     Date : Mon Oct 18 13:46:28 CDT 1999

%Define the function name for easy referencing
FuncName = 'BrikInfo_SectionValue';

%Debug Flag
DBG = 1;

%initailize return variables
err = 1;

N_BRIKinfo = length(BRIKinfo);

%itmp = findstr (BRIKinfo, sSection); This fails if sSection appears in places
%like History note and history note appears first.
%Nick OOsterhof suggested the following fix:
htmp = regexp (BRIKinfo, ['name\s*=\s*' sSection]);
if isempty(htmp) | length(htmp) > 1, v = []; return; end
itmp = findstr(BRIKinfo(htmp:N_BRIKinfo),sSection)+htmp-1;
if isempty(itmp), v = []; return; end

%findout where this section ends
inxt = strfind(BRIKinfo(itmp:N_BRIKinfo),'type');
inxt = setdiff(inxt, strfind(BRIKinfo(itmp:N_BRIKinfo),'_type')+1); %JM added to avoid getting stuck on data_type
if isempty(inxt), inxt = N_BRIKinfo; else inxt = inxt(1) + itmp -2; end

%Get the count value
[err,sn, jnk, strt,stp] = GetNextLine(BRIKinfo(itmp:inxt),2);
ic = findstr(sn,'count'); %watch it, spacing sensitive section
if ~isempty(ic)
  %skip the = sign
  sn = sn(ic+5:length(sn));
  ic = findstr(sn, '=');
  sn = sn(ic+1:length(sn));
else
  err = ErrEval(FuncName,'Err_could not find count field');
  return;
end
%get the count value
n = str2num(sn);
if ~n %empty field
  v = [];
  typ = '';
  return;
end

%advance to the next line, after count
itmp = itmp + stp + 1;

%read all values
Svals = BRIKinfo(itmp:inxt); %that's where the values are
inl = find(char(Svals) == 10 | char(Svals) == 13); %find any new lines left in Svals (13 was added to work in DOS (CR and LF))

if (~isempty(inl))
  Svals(inl) = ' '; %replace them by space characters
end

%if (sum(isletter(Svals))), %isletter fails when you have numbers such as 1.4e-3
v = zdeblank(Svals);
if isempty(v)
  typ = 'string';
elseif strcmp(v(1),'''') && strcmp(v(length(v)),'~')
  %This parameter is a string, do not change to numbers
  %remove first and last chars
  v = v(2:length(v)-1);
  typ = 'string';
else
  v = str2num(Svals);
  typ = 'number';
end

%pause

err = 0;
return;


function Labels = mri_getlabels_svreg()
% ATLAS     : BrainSuite SVREG (Brainsuite1, USCBrain)
% REFERENCE : http://brainsuite.org/uscbrain-description/

% @=============================================================================
% 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.
% =============================================================================@

Labels = {...
       0, 'Background',                                         [    0    0    0]; ...
       1, 'CSF',                                                [  255    0    0]; ...
       2, 'GM',                                                 [    0  255    0]; ...
       3, 'WM',                                                 [  255  255    0]; ...
       4, 'GM/CSF',                                             [    0    0  255]; ...
       5, 'GM/WM',                                              [  255    0  255]; ...
       6, 'CSF/other',                                          [  255  255  255]; ...
      16, 'Scalp',                                              [  122  157  221]; ...
      17, 'Skull',                                              [  176  176  176]; ...
      18, 'Space',                                              [    0    0  255]; ...
      19, 'Brain',                                              [  128    0   64]; ...
     100, 'Frontal lobe R',                                     [  149   46  145]; ...
     101, 'Frontal lobe L',                                     [  242   56  240]; ...
     110, 'Lateral frontal lobe R',                             [  175  236   13]; ...
     111, 'Lateral frontal lobe L',                             [   80   19  242]; ...
     120, 'Superior frontal gyrus R',                           [    0  255  127]; ...
     121, 'Superior frontal gyrus L',                           [  255    0  128]; ...
     130, 'Middle frontal gyrus R',                             [  128  255  255]; ...
     131, 'Middle frontal gyrus L',                             [  127    0    0]; ...
     140, 'Inferior frontal gyrus R',                           [  175  236   13]; ...
     141, 'Inferior frontal gyrus L',                           [   80   19  242]; ...
     142, 'Pars opercularis R',                                 [  255  255    0]; ...
     143, 'Pars opercularis L',                                 [    0    0  255]; ...
     144, 'Pars triangularis R',                                [  127    0  128]; ...
     145, 'Pars triangularis L',                                [  128  255  127]; ...
     146, 'Pars orbitalis R',                                   [  255  255    0]; ...
     147, 'Pars orbitalis L',                                   [    0    0  255]; ...
     150, 'Pre-central gyrus R',                                [  128  255    0]; ...
     151, 'Pre-central gyrus L',                                [  127    0  255]; ...
     160, 'Pole/orbital frontal lobe R',                        [  175  236   13]; ...
     161, 'Pole/orbital frontal lobe L',                        [   80   19  242]; ...
     162, 'Transvers frontal gyrus R',                          [  255  255    0]; ...
     163, 'Transvers frontal gyrus L',                          [    0    0  255]; ...
     164, 'Gyrus rectus R',                                     [  255    0  255]; ...
     165, 'Gyrus rectus L',                                     [    0  255    0]; ...
     166, 'Middle orbito-frontal gyrus R',                      [  128  255    0]; ...
     167, 'Middle orbito-frontal gyrus L',                      [  127    0  255]; ...
     168, 'Anterior orbito-frontal gyrus R',                    [  255    0  128]; ...
     169, 'Anterior orbito-frontal gyrus L',                    [    0  255  127]; ...
     170, 'Posterior orbito-frontal gyrus R',                   [  128  255  255]; ...
     171, 'Posterior orbito-frontal gyrus L',                   [  127    0    0]; ...
     172, 'Lateral orbitofrontal gyrus R',                      [  128    0  255]; ...
     173, 'Lateral orbitofrontal gyrus L',                      [  127  255    0]; ...
     180, 'Mesial frontal lobe R',                              [  175  236   13]; ...
     181, 'Mesial frontal lobe L',                              [   80   19  242]; ...
     182, 'Paracentral lobule R',                               [  255    0    0]; ...
     183, 'Paracentral lobule L',                               [    0  255  255]; ...
     184, 'Cingulate gyrus R',                                  [  255  255  128]; ...
     185, 'Cingulate gyrus L',                                  [    0    0  127]; ...
     186, 'Subcallosal gyrus R',                                [  255    0    0]; ...
     187, 'Subcallosal gyrus L',                                [    0  255  255]; ...
     200, 'Parietal lobe R',                                    [  117  236   61]; ...
     201, 'Parietal lobe L',                                    [  171  242   49]; ...
     220, 'Lateral parietal lobe R',                            [  175  236   13]; ...
     221, 'Lateral parietal lobe L',                            [   80   19  242]; ...
     222, 'Post-central gyrus R',                               [  128  127    0]; ...
     223, 'Post-central gyrus L',                               [  127  128  255]; ...
     224, 'Supramarginal gyrus R',                              [    0  128  127]; ...
     225, 'Supramarginal gyrus L',                              [  255  127  128]; ...
     226, 'Angular gyrus R',                                    [  255  255  127]; ...
     227, 'Angular gyrus L',                                    [    0    0  128]; ...
     228, 'Superior parietal gyrus R',                          [    0  128  255]; ...
     229, 'Superior parietal gyrus L',                          [  255  127    0]; ...
     240, 'Mesial parietal lobe R',                             [  175  236   13]; ...
     241, 'Mesial parietal lobe L',                             [   80   19  242]; ...
     242, 'Pre-cuneus R',                                       [    0  255    0]; ...
     243, 'Pre-cuneus L',                                       [  255    0  255]; ...
     300, 'Temporal lobe R',                                    [   50  132  236]; ...
     301, 'Temporal lobe L',                                    [   93  239  242]; ...
     310, 'Temporal pole R',                                    [  255    0    0]; ...
     311, 'Temporal pole L',                                    [    0  255  255]; ...
     320, 'Lateral/superior temporal lobe R',                   [  128  255  127]; ...
     321, 'Lateral/superior temporal lobe R',                   [  127    0  128]; ...
     322, 'Superior temporal gyrus R',                          [  128  255  127]; ...
     323, 'Superior temporal gyrus L',                          [  127    0  128]; ...
     324, 'Transverse temporal gyrus R',                        [  255    0  128]; ...
     325, 'Transverse temporal gyrus L',                        [    0  255  127]; ...
     326, 'Middle temporal gyrus R',                            [  255    0  255]; ...
     327, 'Middle temporal gyrus L',                            [    0  255    0]; ...
     328, 'Inferior temporal gyrus R',                          [  128  255  255]; ...
     329, 'Inferior temporal gyrus L',                          [  127    0    0]; ...
     330, 'Fusiforme gyrus R',                                  [  255  255    0]; ...
     331, 'Fusiforme gyrus L',                                  [    0    0  255]; ...
     340, 'Infero/mesial temporal lobe R',                      [    0    0  255]; ...
     341, 'Infero/mesial temporal lobe L',                      [  255  255    0]; ...
     342, 'Parahippocampal gyrus R',                            [    0    0  255]; ...
     343, 'Parahippocampal gyrus L',                            [  255  255    0]; ...
     344, 'Hippocampus R',                                      [  255  128  127]; ...
     345, 'Hippocampus L',                                      [    0  127  128]; ...
     346, 'Amygdala R',                                         [  255  128    0]; ...
     347, 'Amygdala L',                                         [    0  127  255]; ...
     370, 'Hippocampus R',                                      [  255  128  127]; ...
     371, 'Hippocampus L',                                      [    0  127  128]; ...
     400, 'Occipital lobe R',                                   [  255  252  122]; ...
     401, 'Occipital lobe L',                                   [  242  225   42]; ...
     420, 'Lateral occipital lobe R',                           [  175  236   13]; ...
     421, 'Lateral occipital lobe L',                           [   80   19  242]; ...
     422, 'Superior occipital gyrus R',                         [  128  127    0]; ...
     423, 'Superior occipital gyrus L',                         [  127  128  255]; ...
     424, 'Middle occipital gyrus R',                           [  128  255    0]; ...
     425, 'Middle occipital gyrus L',                           [  127    0  255]; ...
     440, 'Infero/mesial occipital lobe R',                     [  175  236   13]; ...
     441, 'Infero/mesial occipital lobe L',                     [   80   19  242]; ...
     442, 'Inferior occipital gyrus R',                         [  127    0  255]; ...
     443, 'Inferior occipital gyrus L',                         [  128  255    0]; ...
     444, 'Lingual gyrus R',                                    [  127    0  127]; ...
     445, 'Lingual gyrus L',                                    [  128  255  128]; ...
     446, 'Cuneus R',                                           [  255  128  255]; ...
     447, 'Cuneus L',                                           [    0  127    0]; ...
     500, 'Insula R',                                           [  127  255  128]; ...
     501, 'Insula L',                                           [  128    0  127]; ...
     600, 'Central gray structures R',                          [  175  236   13]; ...
     601, 'Central gray structures L',                          [   80   19  242]; ...
     610, 'Basal ganglia R',                                    [  175  236   13]; ...
     611, 'Basal ganglia L',                                    [   80   19  242]; ...
     612, 'Caudate nucleus R',                                  [  127  128  255]; ...
     613, 'Caudate nucleus L',                                  [  128  127    0]; ...
     614, 'Putamen R',                                          [  255  255    0]; ...   % OLD: 630
     615, 'Putamen L',                                          [    0    0  255]; ...   % OLD: 631
     616, 'Pallidum R',                                         [  128    0  127]; ...   % OLD: 640
     617, 'Pallidum L',                                         [  127  255  128]; ...   % OLD: 641
     620, 'Accumbens R',                                        [    0  255  255]; ...
     621, 'Accumbens L',                                        [  255    0    0]; ...
     630, 'Claustrum R',                                        [  255    0    0]; ...
     631, 'Claustrum L',                                        [    0  255  255]; ...
     640, 'Thalamus R',                                         [    0  255  255]; ...   % OLD: 660
     641, 'Thalamus L',                                         [  255    0    0]; ...   % OLD: 661
     650, 'Basal forebrain R',                                  [    0  128    0]; ...
     651, 'Basal forebrain L',                                  [  255  127  255]; ...
     660, 'Lateral geniculate nucleus R',                       [  128    0    0]; ...
     661, 'Lateral geniculate nucleus L',                       [  127  255  255]; ...
     662, 'Medial geniculate nucleus R',                        [  127  127  255]; ...
     663, 'Medial geniculate nucleus L',                        [  128  128    0]; ...
     670, 'Superior colliculus R',                              [  255  128    0]; ...
     671, 'Superior colliculus L',                              [    0  127  255]; ...
     680, 'Inferior colliculus R',                              [  255    0  128]; ...
     681, 'Inferior colliculus L',                              [    0  255  127]; ...
     690, 'Mamillary body R',                                   [  127  255  127]; ...
     691, 'Mamillary body L',                                   [  128    0  128]; ...
     700, 'Ventricular system R',                               [  175  236   13]; ...
     701, 'Ventricular system L',                               [   80   19  242]; ...
     710, 'Pineal gland',                                       [  255  255    0]; ...
     720, 'Lateral ventricle R',                                [  255  255    0]; ...
     721, 'Lateral ventricle L',                                [    0    0  255]; ...
     740, 'Third ventricle',                                    [    0    0  127]; ...
     760, 'Fourth ventricle',                                   [    0    0  255]; ...
     780, 'Cerebral aqueduct',                                  [  175  236   13]; ...
     800, 'Brainstem',                                          [  127    0  127]; ...
     850, 'Corpus Callosum',                                    [  255    0    0]; ...
     900, 'Cerebellum',                                         [  128   64   64]; ...
    4000, 'Central sulcus R',                                   [   18    0  242]; ...
    4001, 'Central sulcus L',                                   [   18    0  242]; ...
    4002, 'Precentral sulcus R',                                [   35  235   61]; ...
    4003, 'Precentral sulcus L',                                [   35  235   61]; ...
    4004, 'Superior frontal sulcus R',                          [  245  125  249]; ...
    4005, 'Superior frontal sulcus L',                          [  245  125  249]; ...
    4006, 'Inferio frontal sulcus R',                           [    0  255  255]; ...
    4007, 'Inferio frontal sulcus L',                           [    0  255  255]; ...
    4008, 'Ascending branch of the Sylvian fissure R',          [  236   55  173]; ...
    4009, 'Ascending branch of the Sylvian fissure L',          [  236   55  173]; ...
    4010, 'Horizontal branch of the Sylvian fissure R',         [    0  122  244]; ...
    4011, 'Horizontal branch of the Sylvian fissure L',         [    0  122  244]; ...
    4012, 'Diagonal sulcus R',                                  [  192  128  255]; ...
    4013, 'Diagonal sulcus L',                                  [  192  128  255]; ...
    4014, 'Lateral orbital sulcus R',                           [   17  238  193]; ...
    4015, 'Lateral orbital sulcus L',                           [   17  238  193]; ...
    4016, 'Frontomarginal sulcus R',                            [  125  190  255]; ...
    4017, 'Frontomarginal sulcus L',                            [  125  190  255]; ...
    4018, 'Cingulate sulcus R',                                 [  170  253  251]; ...
    4019, 'Cingulate sulcus L',                                 [  170  253  251]; ...
    4020, 'Paracentral sulcus R',                               [   52  180   78]; ...
    4021, 'Paracentral sulcus L',                               [   52  180   78]; ...
    4022, 'Superior supra orbital sulcus R',                    [  255  255    0]; ...
    4023, 'Superior supra orbital sulcus L',                    [  255  255    0]; ...
    4024, 'Inferior supra orbital sulcus R',                    [  255  255    0]; ...
    4025, 'Inferior supra orbital sulcus L',                    [  255  255    0]; ...
    4026, 'Olfactory or medial orbital sulcus R',               [  125  190  255]; ...
    4027, 'Olfactory or medial orbital sulcus L',               [  125  190  255]; ...
    4028, 'H shaped sulci, mesial R',                           [  255    0    0]; ...
    4029, 'H shaped sulci, mesial L',                           [  255    0    0]; ...
    4030, 'H shaped sulci, lateral R',                          [  255    0    0]; ...
    4031, 'H shaped sulci, lateral L',                          [  255    0    0]; ...
    4032, 'H shaped sulci, transverse R',                       [  255    0    0]; ...
    4033, 'H shaped sulci, transverse L',                       [  255    0    0]; ...
    4034, 'Sylvian fissure terminal split R',                   [  255  255    0]; ...
    4035, 'Sylvian fissure terminal split L',                   [  255  255    0]; ...
    4036, 'Superior temporal sulcus R',                         [   17  238  193]; ...
    4037, 'Superior temporal sulcus L',                         [   17  238  193]; ...
    4038, 'Inferior temporal sulcus R',                         [  245  152   90]; ...
    4039, 'Inferior temporal sulcus L',                         [  245  152   90]; ...
    4040, 'Occipito temporal sulcus R',                         [   92    0  185]; ...
    4041, 'Occipito temporal sulcus L',                         [   92    0  185]; ...
    4042, 'Collateral or medial occipito temporal sulcus R',    [  217    0  255]; ...
    4043, 'Collateral or medial occipito temporal sulcus L',    [  217    0  255]; ...
    4044, 'Transverse temporal sulcus R',                       [   35  235   61]; ...
    4045, 'Transverse temporal sulcus L',                       [   35  235   61]; ...
    4046, 'Circular sulcus R',                                  [  217    0  255]; ...
    4047, 'Circular sulcus L',                                  [  217    0  255]; ...
    4048, 'Postcentral sulcus R',                               [   35  235   61]; ...
    4049, 'Postcentral sulcus L',                               [   35  235   61]; ...
    4050, 'Intraparietal sulcus R',                             [  245  125  249]; ...
    4051, 'Intraparietal sulcus L',                             [  245  125  249]; ...
    4052, 'Primary sulcus of Jensen R',                         [    0  255  255]; ...
    4053, 'Primary sulcus of Jensen L',                         [    0  255  255]; ...
    4054, 'Secondary sulcus of Jensen R',                       [    0  255  255]; ...
    4055, 'Secondary sulcus of Jensen L',                       [    0  255  255]; ...
    4056, 'Parieto occipital sulcus R',                         [  128  128    0]; ...
    4057, 'Parieto occipital sulcus L',                         [  128  128    0]; ...
    4058, 'Subparietal sulcus R',                               [    0  255  255]; ...
    4059, 'Subparietal sulcus L',                               [    0  255  255]; ...
    4060, 'Calcarine sulcus R',                                 [   18    0  242]; ...
    4061, 'Calcarine sulcus L',                                 [   18    0  242]; ...
    4062, 'Calcarine sulcus terminal T R',                      [  255    0  255]; ...
    4063, 'Calcarine sulcus terminal T L',                      [  255    0  255]; ...
    4064, 'Transverse occipital sulcus superior R',             [   17  238  193]; ...
    4065, 'Transverse occipital sulcus superior L',             [   17  238  193]; ...
    4066, 'Superior lateral occipital sulcus R',                [   92    0  185]; ...
    4067, 'Superior lateral occipital sulcus L',                [   92    0  185]; ...
    4068, 'Inferior lateral occipital sulcus R',                [   92    0  185]; ...
    4069, 'Inferior lateral occipital sulcus L',                [   92    0  185]; ...
    4070, 'Anterior occipital sulcus R',                        [    0  122  244]; ...
    4071, 'Anterior occipital sulcus L',                        [    0  122  244]; ...
};

% Duplicate labels < 1000:  GM=1000+label, WM=2000+label
iDup = find([Labels{:,1}] < 1000);
Labels = cat(1, Labels, ...
    cat(2, cellfun(@(c)plus(1000, c), Labels(iDup,1), 'UniformOutput', 0), cellfun(@(c)cat(2, 'GM ', c), Labels(iDup,2), 'UniformOutput', 0), Labels(iDup,3)), ...
    cat(2, cellfun(@(c)plus(2000, c), Labels(iDup,1), 'UniformOutput', 0), cellfun(@(c)cat(2, 'WM ', c), Labels(iDup,2), 'UniformOutput', 0), Labels(iDup,3)));


function barycentric_interp_1d_test ( )

%*****************************************************************************80
%
%% BARYCENTRIC_INTERP_1D_TEST tests the BARYCENTRIC_INTERP_1D library.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 October 2012
%
%  Author:
%
%    John Burkardt
%
  addpath ( '../r8lib' )
  addpath ( '../test_interp_1d' )

  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'BARYCENTRIC_INTERP_1D_TEST:\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Test the BARYCENTRIC_INTERP_1D library.\n' );
  fprintf ( 1, '  The R8LIB library is needed.\n' );
  fprintf ( 1, '  These test needs the TEST_INTERP_1D library.\n' );

  prob_num = p00_prob_num ( );
  for prob = 1 : prob_num
    for nd = [ 4, 8, 16, 32, 64, 1000 ]
      barycentric_interp_1d_test01 ( prob, nd );
    end
  end

  prob_num = p00_prob_num ( );
  for prob = 1 : prob_num
    for nd = [ 4, 8, 16, 32, 64, 1000 ]
      barycentric_interp_1d_test02 ( prob, nd );
    end
  end

  prob_num = p00_prob_num ( );
  for prob = 1 : prob_num
    for nd = [ 4, 8, 16, 32, 64, 1000 ]
      barycentric_interp_1d_test03 ( prob, nd );
    end
  end
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'BARYCENTRIC_INTERP_1D_TEST:\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  rmpath ( '../r8lib' )
  rmpath ( '../test_interp_1d' )

  return
end


function mrUtilMakeColorbar(cmap, labels, desc, fileName, figNum, axisHandle)
% Simple utility to make and save a stand-alone colorbar.
% mrUtilMakeColorbar(cmap, labels, desc, [fileName = no file saved], [figNum=figure], [axisHandle=gca])
%
% labels can be a simple cell-array of stings. You'll get one tick mark per
% label and they will be evenly distributed along the colorbar.
%
% If you specify a file name, the figure will be 'print'ed to that file.
% Valid file name extensions are '.tif' (300 dpi), '.png' (120 dpi), and
% '.eps'. If you don't provide an extension (eg. just specify
% '/path/to/some/file'), then both a png (good for powerpoint) and an eps
% will be saved.
%
% EXAMPLE:
% mrUtilMakeColorbar(autumn(256),{'0','0.5','1.0'},'Data','DataLegend')
%
% To change the font and line color to white:
% mrUtilMakeColorbar(autumn(256),{'0','0.5','1.0'},'Data')
% set(gcf,'InvertHardCopy','off','color','k');
% set(gca,'ycolor','w','xcolor','w','color', 'k');
% set(get(gca,'XLabel'),'color','w');
% mrUtilPrintFigure(gcf, 'DataLegend');
%
% HISTORY:
% 2005.08.20 RFD: wrote it.

fontSize = 12;
fontName = 'Helvetica';

if(~exist('desc','var'))
    desc = '';
end
if(~exist('fileName','var'))
  fileName = '';
  figName = desc;
else
  [p,f,e] = fileparts(fileName);
  figName = f;
end
if(~exist('figNum','var')||isempty(figNum))
    figNum = figure;
    set(figNum,'Name',figName);
    figExists = false;
else
    figExists = true;
end
if(~exist('axisHandle','var')||isempty(axisHandle))
    figure(figNum);
    axisHandle = gca;
else
  axes(axisHandle);
end

if(size(labels,1)>size(labels,2))
    vert = true;
else
    vert = false;
end

nColors = size(cmap,1);
nLabels = length(labels);

figure(figNum); axes(axisHandle); cla(axisHandle);
height = ceil(nColors.*0.04);
if(vert)
    image(repmat([1:nColors]', 1, height));
    axis xy;
    set(axisHandle,'ytick',linspace(1,nColors,nLabels),'xtick',[],'FontSize',fontSize,'FontName',fontName);
    set(axisHandle,'yticklabel',labels,'xticklabel',[],'YAxisLocation','right');
    sz = [70 300];
    apos = [-0.2 0.055 0.945 0.88];
else
    image(repmat([1:nColors], height, 1));
    set(axisHandle,'xtick',linspace(1,nColors,nLabels),'ytick',[],'FontSize',fontSize,'FontName',fontName);
    set(axisHandle,'xticklabel',labels,'yticklabel',[]);
    sz = [300 70];
    apos = [0.055 0.35 0.88 0.945];
end
axis equal tight on;

if(~figExists)
   pos = get(gcf,'Position');
   set(figNum,'Position',[pos(1) pos(2) sz], 'PaperPositionMode', 'auto');
   set(axisHandle,'Position',apos);
   colormap(cmap);
end
if(vert)
    ylabel(desc,'FontSize',fontSize,'FontName',fontName);
else
    xlabel(desc,'FontSize',fontSize,'FontName',fontName);
end
if(~isempty(fileName))
    [p,f,e] = fileparts(fileName);
    if(isempty(e))
      print(figNum, '-depsc', '-tiff', '-cmyk', [fileName '.eps']);
      print(figNum, '-dpng', '-r120', [fileName '.png']);
    elseif(strcmp(e,'.eps'))
        print(figNum, '-depsc', '-tiff', '-cmyk', fileName);
    elseif(strcmp(e,'.tif'))
        print(figNum, '-dtiff', '-r300', fileName);
    else
        print(figNum, '-dpng', '-r120', fileName);
    end
end
return;


function st_io_test ( )

%*****************************************************************************80
%
%% ST_IO_TEST tests the ST_IO library.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    01 November 2008
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'ST_IO_TEST:\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Test the ST_IO library.\n' );

  st_io_test01 ( );
  st_io_test02 ( );
  st_io_test03 ( );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'ST_IO_TEST:\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


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

% Pascal database
params.database = 'pascal2012';

% GT sets for training
params.gt_set_pareto  = 'train2012';
params.gt_set_ranking = 'train2012';

% GT set for testing
params.gt_set_test = 'val2012';

% String identifying the raw hierarchy files
params.raw_hiers = 'sf_mUCM';

% String identifying the current setup (hiers and n_r_cand)
% to use at different file names
params.hiers_id = 'multi_3sc_u_4r';  % multi and 3 scales 'up'

% String identifying the current Pareto chosen point
params.pareto_id = '12k';

% Maximum number of regions per candidate
params.n_r_cand = 4;

% Hierarchies to combine
params.hiers    = {'multi','scale_0.50','scale_1.00','scale_2.00'};

% Level of overlap to erase duplicates
params.J_th = 0.95;

% Number of samples per image that the ranking training will get
params.n_samples = 30;

% Max margin parameter
params.theta = 0.7;

%% Do not edit the lines below
% Where to find the hierarchies
for ii=1:length(params.hiers)
    params.hier_dirs{ii} = fullfile(root_dir,'datasets',params.database,params.raw_hiers,params.hiers{ii});
end

% String identifying the current final global setup at MCG
params.mcg_id = [params.raw_hiers '_' params.hiers_id '_' params.pareto_id];

% ----- Results files -----
% Global Pareto file
params.files.pareto_full = fullfile(root_dir,'datasets',params.database,'pareto',[params.raw_hiers '_' params.hiers_id '_nr_' num2str(params.n_r_cand) '_' params.gt_set_pareto '_pareto_full.mat']);

% Single-scale results
for ii=1:length(params.hiers)
    params.files.pareto_singles{ii} = fullfile(root_dir,'results',params.database,'pareto',[params.raw_hiers '_' params.hiers{ii} '_nr_' num2str(params.n_r_cand) '_' params.gt_set_pareto '_pareto_single.mat']);
end

% Parameters of chosen Pareto point
params.files.pareto_point = fullfile(root_dir,'datasets',params.database,'pareto',[params.mcg_id '_' params.gt_set_pareto '_pareto_point.mat']);

% File where full features will be stored
params.files.features_file = fullfile(root_dir,'datasets',params.database,'features',[params.mcg_id '_features_' params.gt_set_ranking  '.mat']);

% File where the trained classifier will be stored
params.files.trained_classifier = fullfile(root_dir,'datasets',params.database,'classifiers',[params.mcg_id '_rand_forest_' params.gt_set_ranking  '.mat']);

% ---- Ensure needed folders ----
if ~exist(fullfile(root_dir,'results',params.database,'pareto'),'dir')
    mkdir(fullfile(root_dir,'results',params.database,'pareto'))
end
if ~exist(fullfile(root_dir,'results',params.database,'cands'),'dir')
    mkdir(fullfile(root_dir,'results',params.database,'cands'))
end
if ~exist(fullfile(root_dir,'datasets',params.database,'classifiers'),'dir')
    mkdir(fullfile(root_dir,'datasets',params.database,'classifiers'));
end
if ~exist(fullfile(root_dir,'datasets',params.database,'features'),'dir')
    mkdir(fullfile(root_dir,'datasets',params.database,'features'));
end


function [handles,msh] = dtiMrMeshAddImages(handles,msh,imOrigin,xIm,yIm,zIm,textures)
%   Add the images to the mrMesh window
%
%   [handles,msh] = ...
%      dtiMrMeshAddImages(handles,msh,imOrigin,xIm,yIm,zIm,textures)
%
% HISTORY:
% Authors: Dougherty, Wandell
% 2005.01.17 RFD: fixed minor inefficiency in how mrMesh params were
% passed.
%
% Stanford VISTA Team

if ieNotDefined('handles'), error('dtiFiberUI handles required.'); end
if ieNotDefined('msh'), msh = dtiGet(handles,'mrMesh'); end
if ieNotDefined('imOrigin'), error('imOrigin required.'); end
if ~exist('xIm','var'), error('xIm required.'); end
if ~exist('yIm','var'), error('yIm required.'); end
if ~exist('zIm','var'), error('zIm required.'); end
if ieNotDefined('textures'), textures = []; end

if ~isempty(xIm) && ~iscell(xIm), tmp{1} = xIm; clear xIm; xIm = tmp; end
if ~isempty(yIm) && ~iscell(yIm), tmp{1} = yIm; clear yIm; yIm = tmp;  end
if ~isempty(zIm) && ~iscell(zIm), tmp{1} = zIm; clear zIm; zIm = tmp; end
if ~iscell(imOrigin), tmp = imOrigin; clear imOrigin; imOrigin{1} = tmp; end

xSize = length(xIm);
ySize = length(yIm);
zSize = length(zIm);

if xSize + ySize + zSize == 0, return, end
if xSize == 0, xSize = max([xSize,ySize,zSize]); end
if ySize == 0, ySize = max([xSize,ySize,zSize]); end
if zSize == 0, zSize = max([xSize,ySize,zSize]); end

if (xSize ~= ySize) || (xSize ~= zSize) || (ySize ~= zSize)
    error('You should have to same number of images to display');
end

nImages = xSize;

if (length(imOrigin) ~= nImages)
    error('You should have an origin specified for each image');
end

% sbOffset = 10;

% imSize must be 2^n (openGL requirement)
%
imSize = 0;
for i = 1:nImages
    if ~isempty(xIm), imSize = max([imSize,2.^ceil(log2(size(xIm{i}')))]); end;
    if ~isempty(yIm), imSize = max([imSize,2.^ceil(log2(size(yIm{i})))]); end;
    if ~isempty(zIm), imSize = max([imSize,2.^ceil(log2(size(zIm{i}')))]); end;
end

imSize = [imSize imSize];
imTemplate.class = 'image';
imTemplate.width = imSize(1);
imTemplate.height = imSize(2);
imTemplate.tex_width = imSize(2);
imTemplate.tex_height = imSize(1);

% 1 is opaque. 0 is completely transparent.
% We need to set this parameter in the GUI at some point.  Leave it like
% this for now so Bob and Michal see the effect and comment.
imTemplate.transparency = msh.transparency;

if ~isempty(xIm)
    for i = 1:nImages
        im = imTemplate;
        [id,s,r] = mrMesh(msh.host, msh.id, 'add_actor', im);
        msh.imgActors(3*i) = r.actor;
        im.actor = r.actor;
        sz = size(xIm{i}');
        pos = floor((imSize-sz)./2)+1;
        imData = zeros(imSize);
        imData(pos(1):pos(1)+sz(1)-1, pos(2):pos(2)+sz(2)-1) = xIm{i}';
        im.texture = repmat(imData(:)', 4, 1);

        if isempty(textures)
            im.texture(4,:) = im.transparency*ones(size(im.texture(1,:)));
        else
            textures.xIm{i} = textures.xIm{i}';
            if(any(size(textures.xIm{i})~=imSize))
                imData = zeros(imSize);
                imData(pos(1):pos(1)+sz(1)-1, pos(2):pos(2)+sz(2)-1) = textures.xIm{i};
                im.texture(4,:) = imData(:);
            else
                im.texture(4,:) = textures.xIm{i}(:);
            end
        end

        im.rotation = [0 0 1; 0 1 0; 1 0 0];
        im.origin = imOrigin{i}.x;
        [id,s,r] = mrMesh(msh.host, msh.id, 'set', im);
    end
end

if~isempty(yIm)
    for i = 1:nImages
        im = imTemplate;
        [id,s,r] = mrMesh(msh.host, msh.id, 'add_actor', im);
        msh.imgActors(2 + 3*(i - 1)) = r.actor;
        im.actor = r.actor;
        sz = size(yIm{i});
        pos = floor((imSize-sz)./2)+1;
        imData = zeros(imSize);
        imData(pos(1):pos(1)+sz(1)-1, pos(2):pos(2)+sz(2)-1) = yIm{i};
        im.texture = repmat(imData(:)', 4, 1);

        if isempty(textures)
            im.texture(4,:) = im.transparency*ones(size(im.texture(1,:)));
        else
            %textures.yIm{i} = textures.yIm{i}';
            if(any(size(textures.yIm{i})~=imSize))
                imData = zeros(imSize);
                imData(pos(1):pos(1)+sz(1)-1, pos(2):pos(2)+sz(2)-1) = textures.yIm{i};
                im.texture(4,:) = imData(:);
            else
                im.texture(4,:) = textures.yIm{i}(:);
            end
        end

        im.rotation = [1 0 0; 0 0 1; 0 1 0];
        im.origin = imOrigin{i}.y;
        [id,s,r] = mrMesh(msh.host, msh.id, 'set', im);
    end
end

if ~isempty(zIm)
    for i = 1:nImages
        im = imTemplate;
        [id,s,r] = mrMesh(msh.host, msh.id, 'add_actor', im);
        msh.imgActors(1 + 3*(i - 1)) = r.actor;
        im.actor = r.actor;
        sz = size(zIm{i}');        pos = floor((imSize-sz)./2)+1;
        imData = zeros(imSize);
        imData(pos(1):pos(1)+sz(1)-1, pos(2):pos(2)+sz(2)-1) = zIm{i}';
        im.texture = repmat(imData(:)', 4, 1);

        if isempty(textures)
            im.texture(4,:) = im.transparency*ones(size(im.texture(1,:)));
        else
            textures.zIm{i} = textures.zIm{i}';
            if(any(size(textures.zIm{i})~=imSize))
                imData = zeros(imSize);
                imData(pos(1):pos(1)+sz(1)-1, pos(2):pos(2)+sz(2)-1) = textures.zIm{i};
                im.texture(4,:) = imData(:);
            else
                im.texture(4,:) = textures.zIm{i}(:);
            end
        end

        im.rotation = [1 0 0; 0 1 0; 0 0 1];
        im.origin = imOrigin{i}.z;
        [id,s,r] = mrMesh(msh.host, msh.id, 'set', im);
        %msh.img(1) = im;
    end
end

return;


% BIG PICTURE TODOS (01/09/07 ras):
% A lot of the previous things on the ToDo list have been implemented in
% 2006. Here are some things that remain.
%
%
%  * Spaces: add ability to call external matlab function to
%            get coords (e.g., for Talairach; may also be easier
%            for flattening). I think the format of any function
%            called in this way should be:
%               newCoords = myFunction(oldCoords,mr);
%
%   * Import GLM tools to work on mr objects
%
%   * Flattening: either implement the 'flatten-on-the-fly' code from
%   mrFlatMesh, or else come up with a tool to flatten using the meshes.
%   Given that we were able to use Jonas Larsson's SurfRelax code for
%   mesh inflation, maybe we could also port over his flattening routines?
%   (This would appeal a bit more to me, because having a non-disc flat map
%   makes maps easier to interpret, allowing the viewer to relate the shape
%   of the cuts to positions on the 3D mesh. May also reduce distortions?)
%


function DrawCustomColorbar(clrmap,bins,numTicks,h)
% input:
% bins: values corresponding to clrmap scale, to display on colorbar
% numTicks: 2 or 3
% h:
% - if ommitted, make new figure;
% - if figure handle is passed, draw on upperright corner of anat plot
% - if axis handle is passed, colorbar will fill that axis

%%
if ~exist('numTicks','var')
    numTicks = 2;
end

if exist('h','var')
    if ishandle(h) && strcmp(get(h,'type'),'figure')
        % this is customized for default figure from 'DrawCellsOnAnat'
        axes('Position',[0.8,0.8,0.05,0.15],'Units','normalized');
        axis off;
    elseif ishandle(h) && strcmp(get(h,'type'),'axes')
        axes(h);
        axis off;
    end
else
    figure('Position',[500,200,10,300]);
    set(gcf,'color','w');
    set(gca,'Position',[0.4,0.1,0.2,0.8])
end
n = length(clrmap);
im = zeros(1,n,3);
im(1,:,:) = clrmap;
im2 = permute(im,[2 1 3]);
image(im2);
% box off
% set(gca,'XColor','w');
% set(gca,'YColor','w');

set(gca,'YDir','normal');

if numTicks == 2
    set(gca,'YTick',[1,n]);
    set(gca,'YTickLabels',{num2str(bins(1),1),num2str(bins(end),1)});
    set(gca,'TickLength',[0,0]);
elseif numTicks == 3
        set(gca,'YTick',[1,n/2,n]);
    set(gca,'YTickLabels',[bins(1),mean([bins(1),bins(end)]),bins(end)]);
    set(gca,'TickLength',[0,0]);

else
set(gca,'YTick',1:length(bins));
set(gca,'YTickLabels',bins);
end
set(gca,'XTick',[]);

end


function r = ne(p,q)
% this function compares the inequality condition of x, y, and z values of the structures that I use in
% the FVtool.
%
% SYNOPSIS:
%
%
% PARAMETERS:
%
%
% RETURNS:
%
%
% EXAMPLE:
%
% SEE ALSO:
%

% Copyright (c) 2012-2016 Ali Akbar Eftekhari
% See the license file

if (isa(p, 'FaceVariable')&&isa(q, 'FaceVariable'))
    r=p;
    r.xvalue = p.xvalue~=q.xvalue;
    r.yvalue = p.yvalue~=q.yvalue;
    r.zvalue = p.zvalue~=q.zvalue;
elseif isa(p, 'FaceVariable')
    r=p;
    r.xvalue = p.xvalue~=q;
    r.yvalue = p.yvalue~=q;
    r.zvalue = p.zvalue~=q;
else
    r=q;
    r.xvalue = p~=q.xvalue;
    r.yvalue = p~=q.yvalue;
    r.zvalue = p~=q.zvalue;
end


function slices_fig_h = cluster_orthviews_showcenters(cl, myview, overlay, xhairs, sliceorder, bgcolor, varargin)
% :Usage:
% ::
%
%    slices_fig_h = cluster_orthviews_showcenters(cl, myview, [overlay], [xhairs], [order slices flag], [background color], [var args])
%
%    cluster_orthviews_showcenters(cl, 'coronal');
%    cluster_orthviews_showcenters(cl, 'sagittal');
%    cluster_orthviews_showcenters(cl, 'axial');
%
% used in cluster_orthviews_classes
%
% ..
%    tor wager, aug 2006
% ..

    if nargin < 3 || isempty(overlay), overlay = which('scalped_single_subj_T1.img'); end
    if nargin < 4, xhairs = 1; end
    if nargin < 5, sliceorder = 0; end

    whichorth = [];
    for i = 1:length(varargin)
       if ischar(varargin{i})
            switch varargin{i}

                case 'whichorth', whichorth = varargin{i+1};

                otherwise, warning('scn_tools:badInput', ['Unknown input string option:' varargin{i}]);
            end
        end
    end

    % set up orthviews to be OK
    scn_export_spm_window('setup', overlay);
%     set(get(findobj('Tag','Graphics'), 'Children'), 'Color', 'white');
    set(findobj('Type', 'axes', 'Parent', findobj('Tag','Graphics')), 'Color', 'white');
    if xhairs, spm_orthviews('Xhairs', 'on'); end

    % Set window to be equal/constant
    [volInf_tmp, dat] = iimg_read_img(overlay, 2);
    dat = dat(volInf_tmp.wh_inmask);
    spm_orthviews('Window', whichorth, [prctile(dat, 2) prctile(dat, 98)]);

    myviews = {'axial' 'coronal' 'sagittal'};   % for selecting SPM window
    whview = find(strcmp(myviews, myview));
    if isempty(whview), error('myview must be axial, coronal, or sagittal.'); end

    if sliceorder
        % order slices from negative to positive along this dimension
        myviews2 = {'sagittal' 'coronal' 'axial' };  % for selecting coord
        whcoord = strmatch(myview, myviews2) ;
        cen = cat(1, cl.mm_center);
        [cen, wh] = unique(cen(:, whcoord));
        % remove duplicates and sort
        cl = cl(wh);

        % get text string base
        mystr = {'x = ' 'y = ' 'z = '};
        textbase = mystr{whcoord};
    end

    % get optimal number of axes
    num_clusters = length(cl);
    rc = ceil(sqrt(num_clusters));

    if isempty(whichorth)
        axh = get_orth_axishandles;
    else
        axh = get_orth_axishandles_whichorth(whichorth);
    end

    axh = axh(whview);

    slices_fig_h = figure; %create_figure(myview);
    set(slices_fig_h, 'Color', 'k');

    for i = 1:num_clusters
        newax(i) = subplot(rc, rc, i);
        axis off;
     end

    for i = 1:num_clusters
        %cluster_orthviews(cl{i}, colors2(classes(i)), 'overlay', overlay);
        spm_orthviews('Reposition', cl(i).mm_center);

        copyobj(get(axh, 'Children'), newax(i));
        axes(newax(i));
        axis image

        h = findobj(newax(i), 'Type', 'text');
        h= h(1); % kludgy fix for multiple matches ***

        if sliceorder
            % try to set a reasonable font size
            pos = get(newax(i), 'Position');
            height = pos(3);
            fs = round(height * 70);
            set(h, 'FontSize', fs)
            % set position of text (move down and right)
            pos = get(h, 'Position');
            pos(2) = 0; %pos(2) - fs./2;
            pos(1) = 0;
            set(h, 'Position', pos)
            % set text string based on cen
            set(h, 'String', [textbase num2str(cen(i))]);
        elseif ishandle(h)
            delete(h);
        end
    end

    % try to set a reasonable enlargement factor
    n = 1 + .15 * log(num_clusters ./ 2);
    n = max(n, 1); n = min(n, 3);
    enlarge_axes(gcf, n)

    % set background color to print as whatever it is on screen
    set(gcf,'InvertHardcopy', 'off');
end

function axish = get_orth_axishandles

    % Get figure and axis handles
    fh = findobj('Tag', 'Graphics');
    ch = get(fh, 'Children');
    for i= 1:length(ch)
        mytype = get(ch(i), 'Type');
        wh(i) = strcmp(mytype, 'axes');
    end
    axish = ch(find(wh));

    if isempty(axish), error('SPM figure orthviews do not exist'); end

    % get which axis is which
    for i = 1:length(axish)
        poss(i, :) = get(axish(i), 'Position');
    end

    % get rid of extra axes we may have created in the 4th quadrant
    other_axes = find(any(poss(:, 1) > .45 & poss(:, 2) < .2, 2));
    axish(other_axes) = [];
    poss(other_axes, :) = [];

    % sort into order:  axial, coronal, saggital
    ssum = sum(poss(:, 1:2), 2);
    [ssum, ind] = sort(ssum);
    axish = axish(ind);

end

function axish = get_orth_axishandles_whichorth(whichorth)
% Get the axis handles for the current orthviews
global st
for i = 1:length(st.vols), wh(i) = ~isempty(st.vols{i}); end
wh = find(wh); wh = wh(whichorth);
axish = cat(1, st.vols{wh}.ax{:});
axish = sort(cat(1, axish(:).ax));

end


%% flandmark_simple_example.m
% Test flandmark detector
%
% 27-03-12 Michal Uricar

clc;
clearvars; close all;

%% Add path

addpath('./mex/');

DIR = '../data/Images/';
IMGS = dir([DIR '*.jpg']);

% Load flandmark_model into MATLAB memory
model = flandmark_load_model('../data/flandmark_model.dat');

%% Run detector

% run detector 100 times for randomly selected image
for example = 1 : 100
    % pick random image
    idx = randi(numel(IMGS));
    filename = IMGS(idx).name;
    fname = filename(1:end-4);
    % load image and detected face bbox
    I = imread([DIR filename]);
    Ibw = rgb2gray(I);
    bbox = dlmread([DIR fname '.det']);

    % image output
    figure(1);
    imshow(I, [], 'Border', 'tight'); hold on;
    % plotbox(bbox);

    for i = 1 : size(bbox, 1)
        tic
        P = flandmark_detector(Ibw, int32(bbox(i, :)),  model);
        t1 = toc;
        fprintf('MEX:    Elapsed time %f ms\n', t1*1000);

        % show landmarks
        comps = ['S0'; 'S1'; 'S2'; 'S3'; 'S4'; 'S5'; 'S6'; 'S7'];
        plot(P(1, 1), P(2, 1), 'bs', 'LineWidth', 1, 'MarkerSize', 5, 'MarkerFaceColor', 'b');
        text(P(1, 1)+1, P(2, 1)+1, comps(1,:), 'color', 'b', 'FontSize', 12);
        plot(P(1, 2:end), P(2, 2:end), 'rs', 'LineWidth', 1, 'MarkerSize', 5, 'MarkerFaceColor', 'r');
        text(P(1, 2:end)+1, P(2, 2:end)+1, comps(2:end,:), 'color', 'r', 'FontSize', 12);
    end;
    pause(0.2);
end;

%%

clear mex;


function obj_to_tri_surface ( obj_filename, node_filename, element_filename )

%*****************************************************************************80
%
%% OBJ_TO_TRI_SURFACE transfers 3D graphics from an OBJ file to a TRI_SURFACE file.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    28 September 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string OBJ_FILENAME, the name of the OBJ file to be read.
%
%    Input, string NODE_FILENAME, the name of the TRI_SURFACE node file
%    to be written.
%
%    Input, string ELEMENT_FILENAME, the name of the TRI_SURFACE element
%    file to be written.
%

%
%  Get the size of the objects in the OBJ file.
%
  [ node_num, face_num, normal_num, order_max ] = obj_size ( obj_filename );

  obj_size_print ( obj_filename, node_num, face_num, normal_num, order_max );
%
%  Read the OBJ file.
%
  [ node_xyz, face_order, face_node, normal_vector, vertex_normal ] = ...
    obj_read ( obj_filename, node_num, face_num, normal_num, order_max );
%
%  Convert faces to triangles.
%
  element_num = sum ( face_order(1:face_num) ) - 2 * face_num;

  element_node = faces_to_triangles ( order_max, face_num, face_order, ...
    face_node, element_num );
%
%  Write the data to the TRI_SURFACE files.
%
  dim_num = size ( node_xyz, 1 );
  order_num = 3;

  tri_surface_size_print ( node_filename, element_filename, dim_num, ...
    node_num, order_num, element_num )

  tri_surface_write ( node_filename, element_filename, dim_num, node_num, ...
    order_num, element_num, node_xyz, element_node );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  TRI_SURFACE data written to:\n' );
  fprintf ( 1, '  node file    "%s".\n', node_filename );
  fprintf ( 1, '  element file "%s".\n', element_filename );

  return
end
function c = ch_cap ( c )

%*****************************************************************************80
%
%% CH_CAP capitalizes a single character.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    22 November 2003
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, character C, the character to capitalize.
%
%    Output, character C, the capitalized character.
%
  if ( 'a' <= c & c <= 'z' )
    c = c + 'A' - 'a';
  end

  return
end
function truefalse = ch_eqi ( c1, c2 )

%*****************************************************************************80
%
%% CH_EQI is a case insensitive comparison of two characters for equality.
%
%  Example:
%
%    CH_EQI ( 'A', 'a' ) is TRUE.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    28 July 2000
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, character C1, C2, the characters to compare.
%
%    Output, logical TRUEFALSE, is TRUE (1) if the characters are equal.
%
  FALSE = 0;
  TRUE = 1;

  if ( ch_cap ( c1 ) == ch_cap ( c2 ) )
    truefalse = TRUE;
  else
    truefalse = FALSE;
  end

  return
end
function value = ch_index ( s, c )

%*****************************************************************************80
%
%% CH_INDEX is the first occurrence of a character in a string.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    01 May 2004
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string S, the string to be searched.
%
%    Input, character C, the character to be searched for.
%
%    Output, integer VALUE, the location of the first occurrence of C
%    in the string, or 0 if C does not occur.
%
  value = 0;

  for i = 1 : length ( s )

    if ( s(i:i) == c )
      value = i;
      return
    end

  end

  return
end
function value = ch_is_control ( ch )

%*****************************************************************************80
%
%% CH_IS_CONTROL is TRUE if a character is a control character.
%
%  Discussion:
%
%    A "control character" has ASCII code <= 31 or 127 <= ASCII code.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    27 September 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, character CH, the character to be tested.
%
%    Output, integer CH_IS_CONTROL, TRUE if the character is a control
%    character, and FALSE otherwise.
%
  if ( ch <= 31 | 127 <= ch )
    value = 1;
  else
    value = 0;
  end

  return
end
function truefalse = ch_is_digit ( c )

%*****************************************************************************80
%
% CH_IS_DIGIT returns TRUE if the character C is a digit.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    11 December 2003
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, character C, a character.
%
%    Output, integer TRUEFALSE, is TRUE (1) if C is a digit, FALSE (0) otherwise.
%
  TRUE = 1;
  FALSE = 0;

  if ( '0' <= c & c <= '9' )
    truefalse = TRUE;
  else
    truefalse = FALSE;
  end

  return
end
function digit = ch_to_digit ( c )

%*****************************************************************************80
%
%% CH_TO_DIGIT returns the integer value of a base 10 digit.
%
%  Example:
%
%     C   DIGIT
%    ---  -----
%    '0'    0
%    '1'    1
%    ...  ...
%    '9'    9
%    ' '    0
%    'X'   -1
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    22 November 2003
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, character C, the decimal digit, '0' through '9' or blank
%    are legal.
%
%    Output, integer DIGIT, the corresponding integer value.  If C was
%    'illegal', then DIGIT is -1.
%
  if ( '0' <= c & c <= '9' )

    digit = c - '0';

  elseif ( c == ' ' )

    digit = 0;

  else

    digit = -1;

  end

  return
end
function triangle_node = faces_to_triangles ( order_max, face_num, ...
  face_order, face_node, triangle_num )

%*****************************************************************************80
%
%% FACES_TO_TRIANGLES replaces higher order faces by triangles.
%
%  Modified:
%
%    28 September 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer ORDER_MAX, the maximum face order.
%
%    Input, integer FACE_NUM, the number of faces.
%
%    Input, integer FACE_ORDER(FACE_NUM), the order of each face.
%
%    Input, integer FACE_NODE(ORDER_MAX,FACE_NUM), the nodes that make up each face.
%
%    Input, integer TRIANGLE_NUM, the number of triangles that will be generated.
%
%    Output, integer TRIANGLE_NODE(3,TRIANGLE_NUM), the triangles.
%
  triangle_node = zeros ( 3, triangle_num );

  triangle = 0;

  for face = 1 : face_num
    for order = 3 : face_order ( face )
      triangle = triangle + 1;
      triangle_node(1,triangle) = face_node(1,face);
      triangle_node(2,triangle) = face_node(order-1,face);
      triangle_node(3,triangle) = face_node(order,face);
    end
  end

  return
end
function i4mat_write ( output_filename, m, n, table )

%*****************************************************************************80
%
%% I4MAT_WRITE writes an I4MAT file.
%
%  Discussion:
%
%    An I4MAT is an array of I4's.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    26 June 2010
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string OUTPUT_FILENAME, the output filename.
%
%    Input, integer M, the spatial dimension.
%
%    Input, integer N, the number of points.
%
%    Input, integer TABLE(M,N), the points.
%

%
%  Open the file.
%
  output_unit = fopen ( output_filename, 'wt' );

  if ( output_unit < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'I4MAT_WRITE - Error!\n' );
    fprintf ( 1, '  Could not open the output file.\n' );
    error ( 'I4MAT_WRITE - Error!' );
  end
%
%  Write the data.
%
  for j = 1 : n
    for i = 1 : m
      fprintf ( output_unit, '  %12d', round ( table(i,j) ) );
    end
    fprintf ( output_unit, '\n' );
  end
%
%  Close the file.
%
  fclose ( output_unit );

  return
end
function [ node_xyz, face_order, face_node, normal_vector, vertex_normal ] = ...
  obj_read ( input_file_name, node_num, face_num, normal_num, order_max )

%*****************************************************************************80
%
%% OBJ_READ reads graphics information from a Wavefront OBJ file.
%
%  Discussion:
%
%    It is intended that the information read from the file can
%    either start a whole new graphics object, or simply be added
%    to a current graphics object via the '<<' command.
%
%    This is controlled by whether the input values have been zeroed
%    out or not.  This routine simply tacks on the information it
%    finds to the current graphics object.
%
%  Example:
%
%    #  magnolia.obj
%
%    v -3.269770 -39.572201 0.876128
%    v -3.263720 -39.507999 2.160890
%    ...
%    v 0.000000 -9.988540 0.000000
%    vn 1.0 0.0 0.0
%    ...
%    vn 0.0 1.0 0.0
%
%    f 8 9 11 10
%    f 12 13 15 14
%    ...
%    f 788 806 774
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    27 September 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string INPUT_FILENAME, the name of the input file.
%
%    Input, integer NODE_NUM, the number of points.
%
%    Input, integer FACE_NUM, the number of faces.
%
%    Input, integer NORMAL_NUM, the number of normal vectors.
%
%    Input, integer ORDER_MAX, the maximum number of vertices per face.
%
%    Output, real ( kind = 8 ) NODE_XYZ(3,NODE_NUM), the coordinates of points.
%
%    Output, integer FACE_ORDER(FACE_NUM), the number of vertices per face.
%
%    Output, integer FACE_NODE(ORDER_MAX,FACE_NUM), the nodes making faces.
%
%    Output, real ( kind = 8 ) NORMAL_VECTOR(3,NORMAL_NUM), normal vectors.
%
%    Output, integer VERTEX_NORMAL(ORDER_MAX,FACE_NUM), the indices of normal
%    vectors per vertex.
%
  ierror = 0;

  face = 0;
  node = 0;
  normal = 0;
  text_num = 0;

  face_node = zeros ( order_max, face_num );
  face_order = zeros ( face_num, 1 );
  node_xyz = zeros ( 3, node_num );
  normal_vector = zeros ( 3, normal_num );
  vertex_normal = zeros ( order_max, face_num );
%
%  If no file input, try to get one from the user.
%
  if ( nargin < 1 )
    input_file_name = input ( 'Enter the name of the ASCII OBJ file.' );
    if ( isempty ( input_file_name ) )
      return
    end
  end
%
%  Open the file.
%
  input_file_unit = fopen ( input_file_name, 'r' );

  if ( input_file_unit < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'OBJ_READ - Fatal error!\n' );
    fprintf ( 1, '  Could not open the file "%s".\n', input_file_name );
    error ( 'OBJ_READ - Fatal error!' );
    return
  end
%
%  Read a line of text from the file.
%
  while ( 1 )

    text = fgetl ( input_file_unit );

    if ( text == -1 )
      break
    end

    text_num = text_num + 1;
%
%  Replace any control characters (in particular, TAB's) by blanks.
%
    s_control_blank ( text );

    done = 1;
    word_index = 0;
%
%  Read a word from the line.
%
    [ word, done ] = word_next_read ( text, done );
%
%  If no more words in this line, read a new line.
%
    if ( done )
      continue
    end
%
%  If this word begins with '#' or '$', then it's a comment.  Read a new line.
%
    if ( word(1) == '#' | word(1) == '$' )
      continue
    end

    word_index = word_index + 1;

    if ( word_index == 1 )
      word_one = word;
    end
%
%  BEVEL
%  Bevel interpolation.
%
    if ( s_eqi ( word_one, 'BEVEL' ) )
%
%  BMAT
%  Basis matrix.
%
    elseif ( s_eqi ( word_one, 'BMAT' ) )
%
%  C_INTERP
%  Color interpolation.
%
    elseif ( s_eqi ( word_one, 'C_INTERP' ) )
%
%  CON
%  Connectivity between free form surfaces.
%
    elseif ( s_eqi ( word_one, 'CON' ) )
%
%  CSTYPE
%  Curve or surface type.
%
    elseif ( s_eqi ( word_one, 'CSTYPE' ) )
%
%  CTECH
%  Curve approximation technique.
%
    elseif ( s_eqi ( word_one, 'CTECH' ) )
%
%  CURV
%  Curve.
%
    elseif ( s_eqi ( word_one, 'CURV' ) )
%
%  CURV2
%  2D curve.
%
    elseif ( s_eqi ( word_one, 'CURV2' ) )
%
%  D_INTERP
%  Dissolve interpolation.
%
    elseif ( s_eqi ( word_one, 'D_INTERP' ) )
%
%  DEG
%  Degree.
%
    elseif ( s_eqi ( word_one, 'DEG' ) )
%
%  END
%  End statement.
%
    elseif ( s_eqi ( word_one, 'END' ) )
%
%  F V1 V2 V3 ...
%    or
%  F V1/VT1/VN1 V2/VT2/VN2 ...
%    or
%  F V1//VN1 V2//VN2 ...
%
%  Face.
%  A face is defined by the vertices.
%  Optionally, slashes may be used to include the texture vertex
%  and vertex normal indices.
%
    elseif ( s_eqi ( word_one, 'F' ) )

      face = face + 1;

      vertex = 0;

      while ( 1 )

        [ word, done ] = word_next_read ( text, done );

        if ( done )
          break
        end

        vertex = vertex + 1;
        order_max = max ( order_max, vertex );
%
%  Locate the slash characters in the word, if any.
%
        i1 = ch_index ( word, '/' );
        if ( 0 < i1 )
          i2 = ch_index ( word(i1+1), '/' ) + i1;
        else
          i2 = 0;
        end
%
%  Read the vertex index.
%
        itemp = s_to_i4 ( word );

        face_node(vertex,face) = itemp;
        face_order(face) = face_order(face) + 1;
%
%  If there are two slashes, then read the data following the second one.
%
        if ( 0 < i2 )

          itemp = s_to_i4 ( word(i2+1) );

          vertex_normal(vertex,face) = itemp;

        end

      end
%
%  G
%  Group name.
%
    elseif ( s_eqi ( word_one, 'G' ) )
%
%  HOLE
%  Inner trimming loop.
%
    elseif ( s_eqi ( word_one, 'HOLE' ) )
%
%  L
%  A line, described by a sequence of vertex indices.
%  Are the vertex indices 0 based or 1 based?
%
    elseif ( s_eqi ( word_one, 'L' ) )
%
%  LOD
%  Level of detail.
%
    elseif ( s_eqi ( word_one, 'LOD' ) )
%
%  MG
%  Merging group.
%
    elseif ( s_eqi ( word_one, 'MG' ) )
%
%  MTLLIB
%  Material library.
%
    elseif ( s_eqi ( word_one, 'MTLLIB' ) )
%
%  O
%  Object name.
%
    elseif ( s_eqi ( word_one, 'O' ) )
%
%  P
%  Point.
%
    elseif ( s_eqi ( word_one, 'P' ) )
%
%  PARM
%  Parameter values.
%
    elseif ( s_eqi ( word_one, 'PARM' ) )
%
%  S
%  Smoothing group.
%
    elseif ( s_eqi ( word_one, 'S' ) )
%
%  SCRV
%  Special curve.
%
    elseif ( s_eqi ( word_one, 'SCRV' ) )
%
%  SHADOW_OBJ
%  Shadow casting.
%
    elseif ( s_eqi ( word_one, 'SHADOW_OBJ' ) )
%
%  SP
%  Special point.
%
    elseif ( s_eqi ( word_one, 'SP' ) )
%
%  STECH
%  Surface approximation technique.
%
    elseif ( s_eqi ( word_one, 'STECH' ) )
%
%  STEP
%  Stepsize.
%
    elseif ( s_eqi ( word_one, 'STEP' ) )
%
%  SURF
%  Surface.
%
    elseif ( s_eqi ( word_one, 'SURF' ) )
%
%  TRACE_OBJ
%  Ray tracing.
%
    elseif ( s_eqi ( word_one, 'TRACE_OBJ' ) )
%
%  TRIM
%  Outer trimming loop.
%
    elseif ( s_eqi ( word_one, 'TRIM' ) )
%
%  USEMTL
%  Material name.
%
    elseif ( s_eqi ( word_one, 'USEMTL' ) )
%
%  V X Y Z
%  Geometric vertex.
%
    elseif ( s_eqi ( word_one, 'V' ) )

      node = node + 1;

      for i = 1 : 3
        [ word, done ] = word_next_read ( text, done );
        temp = s_to_r8 ( word );
        node_xyz(i,node) = temp;
      end
%
%  VN
%  Vertex normals.
%
    elseif ( s_eqi ( word_one, 'VN' ) )

      normal = normal + 1;

      for i = 1 : 3
        [ word, done ] = word_next_read ( text, done );
        temp = s_to_r8 ( word );
        normal_vector(i,normal) = temp;
      end
%
%  VT
%  Vertex texture.
%
    elseif ( s_eqi ( word_one, 'VT' ) )
%
%  VP
%  Parameter space vertices.
%
    elseif ( s_eqi ( word_one, 'VP' ) )
%
%  Unrecognized keyword.
%
    else

    end

  end

  fclose ( input_file_unit );

  return
end
function [ node_num, face_num, normal_num, order_max ] = obj_size ( ...
  input_file_name )

%*****************************************************************************80
%
%% OBJ_SIZE determines sizes of graphics objects in an Alias OBJ file.
%
%  Discussion:
%
%    The only items of interest to this routine are vertices,
%    faces, and normal vectors.
%
%  Example:
%
%    #  magnolia.obj
%
%    v -3.269770 -39.572201 0.876128
%    v -3.263720 -39.507999 2.160890
%    ...
%    v 0.000000 -9.988540 0.000000
%
%    vn 1.0 0.0 0.0
%    ...
%    vn 0.0 1.0 0.0
%
%    f 8 9 11 10
%    f 12 13 15 14
%    ...
%    f 788 806 774
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    26 September 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string INPUT_FILENAME, the input file name.
%
%    Output, integer NODE_NUM, the number of points.
%
%    Output, integer FACE_NUM, the number of faces.
%
%    Output, integer NORMAL_NUM, the number of normal vectors.
%
%    Output, integer ORDER_MAX, the maximum face order.
%
  ierror = 0;

  face_num = 0;
  node_num = 0;
  normal_num = 0;
  order_max = 0;
  text_num = 0;
%
%  If no file input, try to get one from the user.
%
  if ( nargin < 1 )
    input_file_name = input ( 'Enter the name of the ASCII OBJ file.' );
    if ( isempty ( input_file_name ) )
      return
    end
  end
%
%  Open the file.
%
  input_file_unit = fopen ( input_file_name, 'r' );

  if ( input_file_unit < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'OBJ_SIZE - Fatal error!\n' );
    fprintf ( 1, '  Could not open the file "%s".\n', input_file_name );
    error ( 'OBJ_SIZE - Fatal error!' );
    return
  end
%
%  Read a line of text from the file.
%
  while ( 1 )

    text = fgetl ( input_file_unit );

    if ( text == -1 )
      break
    end

    text_num = text_num + 1;
%
%  Replace any control characters (in particular, TABs) by blanks.
%
    s_control_blank ( text );

    done = 1;
    word_index = 0;
%
%  Read a word from the line.
%
    [ word, done ] = word_next_read ( text, done );
%
%  If no more words in this line, read a new line.
%
    if ( done )
      continue
    end
%
%  If this word begins with '#' or '$', then it is a comment.  Read a new line.
%
    if ( word(1) == '#' | word(1) == '$' )
      continue
    end

    word_index = word_index + 1;

    if ( word_index == 1 )
      word_one = word;
    end
%
%  F V1 V2 V3 ...
%    or
%  F V1/VT1/VN1 V2/VT2/VN2 ...
%    or
%  F V1//VN1 V2//VN2 ...
%
%  Face.
%  A face is defined by the vertices.
%  Optionally, slashes may be used to include the texture vertex
%  and vertex normal indices.
%
    if ( s_eqi ( word_one, 'F' ) )

      face_num = face_num + 1;

      vertex = 0;

      while ( 1 )

        [ word, done ] = word_next_read ( text, done );

        if ( done )
          break
        end

        vertex = vertex + 1;
        order_max = max ( order_max, vertex );
%
%  Locate the slash characters in the word, if any.
%
        i1 = ch_index ( word, '/' );
        if ( 0 < i1 )
          i2 = ch_index ( word(i1+1), '/' ) + i1;
        else
          i2 = 0;
        end
%
%  Read the vertex index.
%
        itemp = s_to_i4 ( word );
%
%  If there are two slashes, then read the data following the second one.
%
        if ( 0 < i2 )
          itemp = s_to_i4 ( word(i2+1) );
        end

      end
%
%  V X Y Z W
%  Geometric vertex.
%
    elseif ( s_eqi ( word_one, 'V' ) )

      node_num = node_num + 1;
      continue
%
%  VN
%  Vertex normals.
%
    elseif ( s_eqi ( word_one, 'VN' ) )

      normal_num = normal_num + 1;
      continue

    end

  end

  fclose ( input_file_unit );

  return
end
function obj_size_print ( input_file_name, node_num, face_num, normal_num, ...
  order_max )

%*****************************************************************************80
%
%% OBJ_SIZE_PRINT prints sizes associated with an OBJ file.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    26 September 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string INPUT_FILENAME, the name of the input file.
%
%    Input, integer NODE_NUM, the number of vertices defined.
%
%    Input, integer FACE_NUM, the number of faces defined.
%
%    Input, integer NORMAL_NUM, the number of normal vectors defined.
%
%    Input, integer ORDER_MAX, the maximum number of vertices per face.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Object sizes for OBJ file "%s":\n', input_file_name );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Nodes              = %d\n', node_num );
  fprintf ( 1, '  Faces              = %d\n', face_num );
  fprintf ( 1, '  Maximum face order = %d\n', order_max );
  fprintf ( 1, '  Normal vectors     = %d\n', normal_num );

  return
end
function value = r8_epsilon ( )

%*****************************************************************************80
%
%% R8_EPSILON returns the R8 roundoff unit.
%
%  Discussion:
%
%    The roundoff unit is a number R which is a power of 2 with the
%    property that, to the precision of the computer's arithmetic,
%      1 < 1 + R
%    but
%      1 = ( 1 + R / 2 )
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    22 August 2004
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, real VALUE, the roundoff unit.
%
  value = eps;

  return
end
function r8mat_write ( output_filename, m, n, table )

%*****************************************************************************80
%
%% R8MAT_WRITE writes an R8MAT file.
%
%  Discussion:
%
%    An R8MAT is an array of R8's.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    08 February 2010
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string OUTPUT_FILENAME, the output filename.
%
%    Input, integer M, the spatial dimension.
%
%    Input, integer N, the number of points.
%
%    Input, real TABLE(M,N), the points.
%

%
%  Open the file.
%
  output_unit = fopen ( output_filename, 'wt' );

  if ( output_unit < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'R8MAT_WRITE - Error!\n' );
    fprintf ( 1, '  Could not open the output file.\n' );
    error ( 'R8MAT_WRITE - Error!' );
  end
%
%  Write the data.
%
%  For smaller data files, and less precision, try:
%
%     fprintf ( output_unit, '  %14.6e', table(i,j) );
%
  for j = 1 : n
    for i = 1 : m
      fprintf ( output_unit, '  %24.16e', table(i,j) );
    end
    fprintf ( output_unit, '\n' );
  end
%
%  Close the file.
%
  fclose ( output_unit );

  return
end
function s = s_control_blank ( s )

%*****************************************************************************80
%
%% S_CONTROL_BLANK replaces control characters with blanks.
%
%  Discussion:
%
%    A "control character" has ASCII code <= 31 or 127 <= ASCII code.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    27 September 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input/output, string S, the string to be transformed.
%
  s_length = s_len_trim ( s );

  for i = 1 : s_length
    if ( ch_is_control ( s(i) ) )
      s(i) = ' ';
    end
  end

  return
end
function value = s_eqi ( s1, s2 )

%*****************************************************************************80
%
%% S_EQI is a case insensitive comparison of two strings for equality.
%
%  Example:
%
%    S_EQI ( 'Anjana', 'ANJANA' ) is TRUE.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    30 April 2004
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string S1, S2, the strings to compare.
%
%    Output, logical VALUE, is TRUE if the strings are equal.
%
  FALSE = 0;
  TRUE = 1;

  len1 = length ( s1 );
  len2 = length ( s2 );
  lenc = min ( len1, len2 );

  value = FALSE;

  for i = 1 : lenc

    c1 = ch_cap ( s1(i) );
    c2 = ch_cap ( s2(i) );

    if ( c1 ~= c2 )
      value = FALSE;
      return
    end

  end

  for i = lenc + 1 : len1
    if ( s1(i) ~= ' ' )
      value = FALSE;
      return
    end
  end

  for i = lenc + 1 : len2
    if ( s2(i) ~= ' ' )
      value = FALSE;
      return
    end
  end

  value = TRUE;

  return
end
function len = s_len_trim ( s )

%*****************************************************************************80
%
%% S_LEN_TRIM returns the length of a character string to the last nonblank.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 June 2003
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string S, the string to be measured.
%
%    Output, integer LEN, the length of the string up to the last nonblank.
%
  len = length ( s );

  while ( 0 < len )
    if ( s(len) ~= ' ' )
      return
    end
    len = len - 1;
  end

  return
end
function ival = s_to_i4 ( s )

%*****************************************************************************80
%
%% S_TO_I4 reads an integer value from a string.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    18 November 2003
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string S, a string to be examined.
%
%    Output, integer IVAL, the integer value read from the string.
%
  sgn = 1;
  state = 0;
  ival = 0;

  i = 0;

  while ( i < s_len_trim ( s ) )

    i = i + 1;
    c = s(i);

    if ( state == 0 )

      if ( c == ' ' )

      elseif ( c == '-' )
        state = 1;
        sgn = -1;
      elseif ( c == '+' )
        state = 1;
        sgn = +1;
      elseif ( '0' <= c & c <= '9' )
        state = 2;
        ival = c - '0';
      else
        fprintf ( '\n' );
        fprintf ( 'S_TO_I4 - Fatal error!\n' );
        fprintf ( '  Illegal character %c while in state %d.\n', c, state );
        return;
      end
%
%  Have read the sign, now expecting the first digit.
%
    elseif ( state == 1 )

      if ( c == ' ' )

      elseif ( '0' <= c & c <= '9' )
        state = 2;
        ival = c - '0';
      else
        fprintf ( '\n' );
        fprintf ( 'S_TO_I4 - Fatal error!\n' );
        fprintf ( '  Illegal character %c while in state %d.\n', c, state );
        return
      end
%
%  Have read at least one digit, expecting more.
%
    elseif ( state == 2 )

      if ( '0' <= c & c <= '9' )
        ival = 10 * ival + c - '0';
      else
        ival = sgn * ival;
        return;
      end

    end

  end
%
%  If we read all the characters in the string, see if we're OK.
%
  if ( state ~= 2 )
    fprintf ( '\n' );
    fprintf ( 'S_TO_I4 - Fatal error!\n' );
    fprintf ( '  Did not read enough information to define an integer!\n' );
    return;
  end

  ival = sgn * ival;

  return
end
function [ r, lchar, ierror ] = s_to_r8 ( s )

%*****************************************************************************80
%
%% S_TO_R8 reads an R8 from a string.
%
%  Discussion:
%
%    This routine will read as many characters as possible until it reaches
%    the end of the string, or encounters a character which cannot be
%    part of the real number.
%
%    Legal input is:
%
%       1 blanks,
%       2 '+' or '-' sign,
%       2.5 spaces
%       3 integer part,
%       4 decimal point,
%       5 fraction part,
%       6 'E' or 'e' or 'D' or 'd', exponent marker,
%       7 exponent sign,
%       8 exponent integer part,
%       9 exponent decimal point,
%      10 exponent fraction part,
%      11 blanks,
%      12 final comma or semicolon.
%
%    with most quantities optional.
%
%  Example:
%
%    S                 R
%
%    '1'               1.0
%    '     1   '       1.0
%    '1A'              1.0
%    '12,34,56'        12.0
%    '  34 7'          34.0
%    '-1E2ABCD'        -100.0
%    '-1X2ABCD'        -1.0
%    ' 2E-1'           0.2
%    '23.45'           23.45
%    '-4.2E+2'         -420.0
%    '17d2'            1700.0
%    '-14e-2'         -0.14
%    'e2'              100.0
%    '-12.73e-9.23'   -12.73 * 10.0**(-9.23)
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    22 November 2003
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string S, the string containing the
%    data to be read.  Reading will begin at position 1 and
%    terminate at the end of the string, or when no more
%    characters can be read to form a legal real.  Blanks,
%    commas, or other nonnumeric data will, in particular,
%    cause the conversion to halt.
%
%    Output, real R, the value that was read from the string.
%
%    Output, integer LCHAR, the number of characters of S that were used to form R.
%
%    Output, integer IERROR, is 0 if no error occurred.
%
  s_length = s_len_trim ( s );
  ierror = 0;
  r = 0.0;
  lchar = -1;
  isgn = 1;
  rtop = 0.0;
  rbot = 1.0;
  jsgn = 1;
  jtop = 0;
  jbot = 1;
  ihave = 1;
  iterm = 0;

  while ( 1 )

    lchar = lchar + 1;
    c = s(lchar+1);
%
%  Blank character.
%
    if ( c == ' ' )

      if ( ihave == 2 )

      elseif ( ihave == 6 | ihave == 7 )
        iterm = 1;
      elseif ( 1 < ihave )
        ihave = 11;
      end
%
%  Comma.
%
    elseif ( c == ',' | c == ';' )

      if ( ihave ~= 1 )
        iterm = 1;
        ihave = 12;
        lchar = lchar + 1;
      end
%
%  Minus sign.
%
    elseif ( c == '-' )

      if ( ihave == 1 );
        ihave = 2;
        isgn = -1;
      elseif ( ihave == 6 )
        ihave = 7;
        jsgn = -1;
      else
        iterm = 1;
      end
%
%  Plus sign.
%
    elseif ( c == '+' )

      if ( ihave == 1 )
        ihave = 2;
      elseif ( ihave == 6 )
        ihave = 7;
      else
        iterm = 1;
      end
%
%  Decimal point.
%
    elseif ( c == '.' )

      if ( ihave < 4 )
        ihave = 4;
      elseif ( 6 <= ihave & ihave <= 8 )
        ihave = 9;
      else
        iterm = 1;
      end
%
%  Exponent marker.
%
    elseif ( ch_eqi ( c, 'E' ) | ch_eqi ( c, 'D' ) )

      if ( ihave < 6 )
        ihave = 6;
      else
        iterm = 1;
      end
%
%  Digit.
%
    elseif ( ihave < 11 & ch_is_digit ( c ) )

      if ( ihave <= 2 )
        ihave = 3;
      elseif ( ihave == 4 )
        ihave = 5;
      elseif ( ihave == 6 | ihave == 7 )
        ihave = 8;
      elseif ( ihave == 9 )
        ihave = 10;
      end

      d = ch_to_digit ( c );

      if ( ihave == 3 )
        rtop = 10.0 * rtop + d;
      elseif ( ihave == 5 )
        rtop = 10.0 * rtop + d;
        rbot = 10.0 * rbot;
      elseif ( ihave == 8 )
        jtop = 10 * jtop + d;
      elseif ( ihave == 10 )
        jtop = 10 * jtop + d;
        jbot = 10 * jbot;
      end
%
%  Anything else is regarded as a terminator.
%
    else
      iterm = 1;
    end
%
%  If we haven't seen a terminator, and we haven't examined the
%  entire string, go get the next character.
%
    if ( iterm == 1 | s_length <= lchar + 1 )
      break;
    end

  end
%
%  If we haven't seen a terminator, and we have examined the
%  entire string, then we're done, and LCHAR is equal to S_LENGTH.
%
  if ( iterm ~= 1 & lchar + 1 == s_length )
    lchar = s_length;
  end
%
%  Number seems to have terminated.  Have we got a legal number?
%  Not if we terminated in states 1, 2, 6 or 7!
%
  if ( ihave == 1 | ihave == 2 | ihave == 6 | ihave == 7 )
    ierror = ihave;
    fprintf ( 1, '\n' );
    fprintf ( 1, 'S_TO_R8 - Fatal error!\n' );
    fprintf ( 1, '  IHAVE = %d\n', ihave );
    error ( 'S_TO_R8 - Fatal error!' );
  end
%
%  Number seems OK.  Form it.
%
  if ( jtop == 0 )
    rexp = 1.0;
  else

    if ( jbot == 1 )
      rexp = 10.0^( jsgn * jtop );
    else
      rexp = jsgn * jtop;
      rexp = rexp / jbot;
      rexp = 10.0^rexp;
    end

  end

  r = isgn * rexp * rtop / rbot;

  return
end
function timestamp ( )

%*****************************************************************************80
%
%% TIMESTAMP prints the current YMDHMS date as a timestamp.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 February 2003
%
%  Author:
%
%    John Burkardt
%
  t = now;
  c = datevec ( t );
  s = datestr ( c, 0 );
  fprintf ( 1, '%s\n', s );

  return
end
function tri_surface_size_print ( node_filename, element_filename, dim_num, ...
  node_num, order_num, triangle_num )

%*****************************************************************************80
%
%% TRI_SURFACE_SIZE_PRINT prints sizes associated with a TRI_SURFACE file.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    27 September 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string NODE_FILENAME, the name of the node file.
%
%    Input, string TRIANGLE_FILENAME, the name of the triangle file.
%
%    Input, integer DIM_NUM, the number of spatial dimensions.
%
%    Input, integer NODE_NUM, the number of nodes.
%
%    Input, integer ORDER_NUM, the order of the triangles.
%
%    Input, integer TRIANGLE_NUM, the number of triangles.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TRI_SURFACE_SIZE_PRINT:\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Node file     "%s".\n', node_filename );
  fprintf ( 1, '  Triangle file "%s".\n', element_filename );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Spatial dimension  = %d\n', dim_num );
  fprintf ( 1, '  Nodes              = %d\n', node_num );
  fprintf ( 1, '  Triangle order     = %d\n', order_num );
  fprintf ( 1, '  Triangles          = %d\n', triangle_num );

  return
end
function tri_surface_write ( node_filename, element_filename, dim_num, ...
  node_num, order_num, triangle_num, node_xyz, triangle_node )

%*****************************************************************************80
%
%% TRI_SURFACE_WRITE writes graphics information to a pair of TRI_SURFACE files.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    27 September 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string NODE_FILENAME, the name of the node file.
%
%    Input, string ELEMENT_FILENAME, the name of the element file.
%
%    Input, integer DIM_NUM, the spatial dimension.
%
%    Input, integer NODE_NUM, the number of points.
%
%    Input, integer ORDER_NUM, the order of the triangles.
%
%    Input, integer TRIANGLE_NUM, the number of triangles.
%
%    Input, real NODE_XYZ(DIM_NUM,NODE_NUM), the node coordinates.
%
%    Input, integer TRIANGLE_NODE(ORDER_NUM,TRIANGLE_NUM),
%    the nodes that form the triangles.
%
  r8mat_write ( node_filename, dim_num, node_num, node_xyz );

  i4mat_write ( element_filename, order_num, triangle_num, ...
    triangle_node );

  return
end
function [ word, done ] = word_next_read ( s, done )

%*****************************************************************************80
%
%% WORD_NEXT_READ "reads" words from a string, one at a time.
%
%  Special cases:
%
%    The following characters are considered to be a single word,
%    whether surrounded by spaces or not:
%
%      " ( ) { } [ ]
%
%    Also, if there is a trailing comma on the word, it is stripped off.
%    This is to facilitate the reading of lists.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    13 December 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string S, a string, presumably containing words
%    separated by spaces.
%
%    Input, logical DONE.
%    TRUE, if we are beginning a new string;
%    FALSE, if we are continuing to process the current string.
%
%    Output, string WORD.
%    If DONE is FALSE, then WORD contains the "next" word read.
%    If DONE is TRUE, then WORD is blank, because there was no more to read.
%
%    Output, logical DONE.
%      FALSE if another word was read,
%      TRUE if no more words could be read.
%
  persistent lenc;
  persistent next;

  tab = char ( 9 );
%
%  We "remember" LENC and NEXT from the previous call.
%
%  An input value of DONE = TRUE signals a new line of text to examine.
%
  if ( done )

    next = 1;
    done = 0;
    lenc = s_len_trim ( s );

    if ( lenc <= 0 )
      done = 1;
      word = ' ';
      return
    end

  end
%
%  Beginning at index NEXT, search the string for the next nonblank,
%  which signals the beginning of a word.
%
  ilo = next;
%
%  ...S(NEXT:) is blank.  Return with WORD = ' ' and DONE = TRUE.
%
  while ( 1 )

    if ( lenc < ilo )
      word = ' ';
      done = 1;
      next = lenc + 1;
      return
    end
%
%  If the current character is blank, skip to the next one.
%
    if ( s(ilo) ~= ' ' & s(ilo) ~= tab )
      break
    end

    ilo = ilo + 1;

  end
%
%  ILO is the index of the next nonblank character in the string.
%
%  If this initial nonblank is a special character,
%  then that's the whole word as far as we're concerned,
%  so return immediately.
%
  if ( s(ilo) == '"' | ...
       s(ilo) == '(' | ...
       s(ilo) == ')' | ...
       s(ilo) == '{' | ...
       s(ilo) == '}' | ...
       s(ilo) == '[' | ...
       s(ilo) == ']' )

    word = s(ilo);
    next = ilo + 1;
    return

  end
%
%  Now search for the last contiguous character that is not a
%  blank, TAB, or special character.
%
  next = ilo + 1;

  while ( next <= lenc )

    if ( s(next) == ' ' )
      break;
    elseif ( s(next) == tab )
      break;
    elseif ( s(next) == '"' )
      break;
    elseif ( s(next) == '(' )
      break;
    elseif ( s(next) == ')' )
      break;
    elseif ( s(next) == '{' )
      break;
    elseif ( s(next) == '}' )
      break;
    elseif ( s(next) == '[' )
      break;
    elseif ( s(next) == ']' )
      break;
    end

    next = next + 1;

  end

  if ( s(next-1) == ',' )
    word = s(ilo:next-2);
  else
    word = s(ilo:next-1);
  end

  return
end


function view = resetSlider(view,slider,minVal,maxVal,val)
%
%     view = resetSlider(view,slider,minVal,maxVal,val)
%
% Resets slider to have specified min, max, and value.
% Sets the sliderHandle itself as well as the text label.
% Called by setParameterMap to reset the mapWindow sliders.
%
% djh, 4/99
% ras, 04/04:   made parallel changes with makeSlider and setSlider
%               (now has edit fields w/ label)

% Set slider limits
set(slider.sliderHandle,'min',minVal);
set(slider.sliderHandle,'max',maxVal);

% Set slider value
set(slider.sliderHandle,'Value',val);

% Update slider text labels
str = sprintf('%3.3g',val);
set(slider.labelHandle,'string',str);

% Return the current axes to the main image
% BW:  I don't understand this.  It didn't work when called from open3dwindow,
% so I changed gcf to view.ui.figNum in the hopes that the change was good
% enough.  It all seemed to work and it fixed my problem.
set(view.ui.figNum,'CurrentAxes',view.ui.mainAxisHandle);

return


function out=mpExpForm(xval,xexp)

out=[xval,'e',sprintf('%i',xexp)];