function avw_img_write(avw, fileprefix, IMGorient, machine, verbose)

% avw_img_write - write Analyze image files (*.img)
%
% avw_img_write(avw,fileprefix,[IMGorient],[machine],[verbose])
%
% avw.img    - a 3D matrix of image data (double precision).
% avw.hdr    - a struct with image data parameters.  If
%              not empty, this function calls avw_hdr_write.
%
% fileprefix - a string, the filename without the .img
%              extension. If empty, may use avw.fileprefix
%
% IMGorient - optional int, force writing of specified
%             orientation, with values:
%
%   [],  if empty, will use avw.hdr.hist.orient field
%    0,  transverse/axial unflipped (default, radiological)
%    1,  coronal unflipped
%    2,  sagittal unflipped
%    3,  transverse/axial flipped, left to right
%    4,  coronal flipped, anterior to posterior
%    5,  sagittal flipped, superior to inferior
%
% This function will set avw.hdr.hist.orient and write the
% image data in a corresponding order.  This function is
% in alpha development, so it has not been exhaustively
% tested (07/2003). See avw_img_read for more information
% and documentation on the orientation option.
% Orientations 3-5 are NOT recommended!  They are part
% of the Analyze format, but only used in Analyze
% for faster raster graphics during movies.
%
% machine - a string, see machineformat in fread for details.
%           The default here is 'ieee-le'.
%
% verbose - the default is to output processing information to the command
%           window.  If verbose = 0, this will not happen.
%
% Tip: to change the data type, set avw.hdr.dime.datatype to:
%
%     1    Binary             (  1 bit  per voxel)
%     2    Unsigned character (  8 bits per voxel)
%     4    Signed short       ( 16 bits per voxel)
%     8    Signed integer     ( 32 bits per voxel)
%    16    Floating point     ( 32 bits per voxel)
%    32    Complex, 2 floats  ( 64 bits per voxel), not supported
%    64    Double precision   ( 64 bits per voxel)
%   128    Red-Green-Blue     (128 bits per voxel), not supported
%
% See also: avw_write, avw_hdr_write,
%           avw_read, avw_hdr_read, avw_img_read, avw_view
%

% $Revision$ $Date: 2009/01/14 09:24:45 $

% Licence:  GNU GPL, no express or implied warranties
% History:  05/2002, Darren.Weber@flinders.edu.au
%                    The Analyze format is copyright
%                    (c) Copyright, 1986-1995
%                    Biomedical Imaging Resource, Mayo Foundation
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%------------------------------------------------------------------------
% Check inputs

if ~exist('avw','var')
    doc avw_img_write;
    ft_error('...no input avw.');
elseif isempty(avw)
    ft_error('...empty input avw.');
elseif ~isfield(avw,'img')
    ft_error('...empty input avw.img');
end

if ~exist('fileprefix','var')
    if isfield(avw,'fileprefix')
        if ~isempty(avw.fileprefix)
            fileprefix = avw.fileprefix;
        else
            fileprefix = [];
        end
    else
        fileprefix = [];
    end
end
if isempty(fileprefix)
    [fileprefix, pathname, filterindex] = uiputfile('*.hdr','Specify an output Analyze .hdr file');
    if pathname, cd(pathname); end
    if ~fileprefix
        doc avw_img_write;
        ft_error('no output .hdr file specified');
    end
end

if contains(fileprefix, '.hdr')
%    fprintf('AVW_IMG_WRITE: Removing .hdr extension from ''%s''\n',fileprefix);
    fileprefix = strrep(fileprefix,'.hdr','');
end
if contains(fileprefix, '.img')
%    fprintf('AVW_IMG_WRITE: Removing .img extension from ''%s''\n',fileprefix);
    fileprefix = strrep(fileprefix,'.img','');
end

if ~exist('IMGorient','var'), IMGorient = ''; end
if ~exist('machine','var'), machine = 'ieee-le'; end
if ~exist('verbose','var'), verbose = 1; end

if isempty(IMGorient), IMGorient = ''; end
if isempty(machine), machine = 'ieee-le'; end
if isempty(verbose), verbose = 1; end

%------------------------------------------------------------------------
% MAIN
if verbose
    version = '????????????????';
    fprintf('\nAVW_IMG_WRITE [v%s]\n',version(12:16));  tic;
end

fid = fopen(sprintf('%s.img',fileprefix),'w',machine);
if fid < 0
    ft_error('Cannot open file %s.img\n',fileprefix);
else
    avw = write_image(fid,avw,fileprefix,IMGorient,machine,verbose);
end

if verbose
    t=toc; fprintf('...done (%5.2f sec).\n\n',t);
end

% MUST write header after the image, to ensure any
% orientation changes during image write are saved
% in the header
avw_hdr_write(avw,fileprefix,machine,verbose);

return

function avw_hdr_write(avw, fileprefix, machine, verbose)

% AVW_HDR_WRITE - Write Analyze header file (*.hdr)
%
% avw_hdr_write(avw,[fileprefix],[machine],[verbose])
%
% eg, avw_hdr_write(avw,'test');
%
% avw        - a struct with .hdr field, which itself is a struct,
%              containing all fields of an Analyze header.
%              For details, see avw_hdr_read.m
%
% fileprefix - a string, the filename without the .hdr extension.
%              If empty, may use avw.fileprefix
%
% machine    - a string, see machineformat in fread for details.
%              The default here is 'ieee-le'.
%
% verbose - the default is to output processing information to the command
%           window.  If verbose = 0, this will not happen.
%
% See also, AVW_HDR_READ AVW_HDR_MAKE
%           AVW_IMG_READ AVW_IMG_WRITE
%

% $Revision$ $Date: 2009/01/14 09:24:45 $

% Licence:  GNU GPL, no express or implied warranties
% History:  05/2002, Darren.Weber@flinders.edu.au
%           02/2003, Bennett.Landman@ieee.org
%                    - more specific data history var sizes
%                    - 02/2003 confirmed, Darren
%
%                    The Analyze format and c code below is copyright
%                    (c) Copyright, 1986-1995
%                    Biomedical Imaging Resource, Mayo Foundation
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if ~exist('verbose','var'), verbose = 1; end
if ~exist('machine','var'), machine = 'ieee-le'; end

if verbose,
    version = '????????????????';
    fprintf('AVW_HDR_WRITE [v%s]\n',version(12:16));  tic;
end

%----------------------------------------------------------------------------
% Check inputs

if ~exist('avw','var')
    ft_warning('...no input avw - calling avw_hdr_make\n');
    avw = avw_hdr_make;
elseif isempty(avw)
    ft_warning('...empty input avw - calling avw_hdr_make\n');
    avw = avw_hdr_make;
elseif ~isfield(avw,'hdr')
    ft_warning('...empty input avw.hdr - calling avw_hdr_make\n');
    avw = avw_hdr_make;
end
if ~isequal(avw.hdr.hk.sizeof_hdr,348)
    ft_error('...avw.hdr.hk.sizeof_hdr must be 348!\n');
end

quit = 0;
if ~exist('fileprefix','var')
    if isfield(avw,'fileprefix')
        if ~isempty(avw.fileprefix)
            fileprefix = avw.fileprefix;
        else
            quit = 1;
        end
    else
        quit = 1;
    end
    if quit
        helpwin avw_hdr_write;
        ft_error('...no input fileprefix - see help avw_hdr_write\n\n');
        return;
    end
end

if contains(fileprefix, '.hdr')
%    fprintf('AVW_HDR_WRITE: Removing .hdr extension from ''%s''\n',fileprefix);
    fileprefix = strrep(fileprefix,'.hdr','');
end

%----------------------------------------------------------------------------
% MAIN

if verbose, tic; end

% % force volume to 4D if necessary; conforms to AVW standard.  i lifted this
% % code from mri_toolbox/avw_hdr_read.m and modified it just a little bit
% % (using minDim = 4; etc)
% minDim = 4;
% currDim = double(avw.hdr.dime.dim(1));
% if ( currDim < minDim )
%    % fprintf( 'Warning %s: Forcing %d dimensions in avw.hdr.dime.dim\n', ...
%    %    mfilename, minDim );
%    avw.hdr.dime.dim(1) = int16(minDim);
%    avw.hdr.dime.dim(currDim+2:minDim+1) = int16(1);
%    avw.hdr.dime.pixdim(1) = int16(minDim);
%    avw.hdr.dime.pixdim(currDim+2:minDim+1) = int16(1);
% end

fid = fopen(sprintf('%s.hdr',fileprefix),'w',machine);
if fid < 0
    ft_error('Cannot write to file %s.hdr\n',fileprefix);
else
    if verbose, fprintf('...writing %s Analyze header.\n',machine); end
    write_header(fid,avw,verbose);
end

if verbose, t=toc; fprintf('...done (%5.2f sec).\n\n',t); end

return

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

function avw = write_image(fid,avw,fileprefix,IMGorient,machine,verbose)

% short int bitpix;    /* Number of bits per pixel; 1, 8, 16, 32, or 64. */
% short int datatype   /* Datatype for this image set */
% /*Acceptable values for datatype are*/
% #define DT_NONE             0
% #define DT_UNKNOWN          0    /*Unknown data type*/
% #define DT_BINARY           1    /*Binary             ( 1 bit per voxel)*/
% #define DT_UNSIGNED_CHAR    2    /*Unsigned character ( 8 bits per voxel)*/
% #define DT_SIGNED_SHORT     4    /*Signed short       (16 bits per voxel)*/
% #define DT_SIGNED_INT       8    /*Signed integer     (32 bits per voxel)*/
% #define DT_FLOAT           16    /*Floating point     (32 bits per voxel)*/
% #define DT_COMPLEX         32    /*Complex,2 floats   (64 bits per voxel)/*
% #define DT_DOUBLE          64    /*Double precision   (64 bits per voxel)*/
% #define DT_RGB            128    /*A Red-Green-Blue datatype*/
% #define DT_ALL            255    /*Undocumented*/

switch double(avw.hdr.dime.datatype)
case   1
    avw.hdr.dime.bitpix = int16( 1); precision = 'bit1';
case   2
    avw.hdr.dime.bitpix = int16( 8); precision = 'uchar';
case   4
    avw.hdr.dime.bitpix = int16(16); precision = 'int16';
case   8
    avw.hdr.dime.bitpix = int16(32); precision = 'int32';
case  16
    avw.hdr.dime.bitpix = int16(32); precision = 'single';
case  32
    ft_error('...complex datatype not yet supported.\n');
case  64
    avw.hdr.dime.bitpix = int16(64); precision = 'double';
case 128
    ft_error('...RGB datatype not yet supported.\n');
otherwise
    ft_warning('...unknown datatype, using type 16 (32 bit floats).\n');
    avw.hdr.dime.datatype = int16(16);
    avw.hdr.dime.bitpix = int16(32); precision = 'single';
end

% write the .img file, depending on the .img orientation
if verbose,
    fprintf('...writing %s precision Analyze image (%s).\n',precision,machine);
end

fseek(fid,0,'bof');

% The standard image orientation is axial unflipped
if isempty(avw.hdr.hist.orient),
    msg = [ '...avw.hdr.hist.orient ~= 0.\n',...
            '   This function assumes the input avw.img is\n',...
            '   in axial unflipped orientation in memory.  This is\n',...
            '   created by the avw_img_read function, which converts\n',...
            '   any input file image to axial unflipped in memory.\n'];
    ft_warning(msg)
end

if isempty(IMGorient),
    if verbose,
        fprintf('...no IMGorient specified, using avw.hdr.hist.orient value.\n');
    end
    IMGorient = double(avw.hdr.hist.orient);
end

if ~isfinite(IMGorient),
    if verbose,
        fprintf('...IMGorient is not finite!\n');
    end
    IMGorient = 99;
end

switch IMGorient,

case 0, % transverse/axial unflipped

    % For the 'transverse unflipped' type, the voxels are stored with
    % Pixels in 'x' axis (varies fastest) - from patient right to left
    % Rows in   'y' axis                  - from patient posterior to anterior
    % Slices in 'z' axis                  - from patient inferior to superior

    if verbose, fprintf('...writing axial unflipped\n'); end

    avw.hdr.hist.orient = uint8(0);

    SliceDim = double(avw.hdr.dime.dim(4)); % z
    RowDim   = double(avw.hdr.dime.dim(3)); % y
    PixelDim = double(avw.hdr.dime.dim(2)); % x
    SliceSz  = double(avw.hdr.dime.pixdim(4));
    RowSz    = double(avw.hdr.dime.pixdim(3));
    PixelSz  = double(avw.hdr.dime.pixdim(2));

    x = 1:PixelDim;
    for z = 1:SliceDim,
        for y = 1:RowDim,
            fwrite(fid,avw.img(x,y,z),precision);
        end
    end

case 1, % coronal unflipped

    % For the 'coronal unflipped' type, the voxels are stored with
    % Pixels in 'x' axis (varies fastest) - from patient right to left
    % Rows in   'z' axis                  - from patient inferior to superior
    % Slices in 'y' axis                  - from patient posterior to anterior

    if verbose, fprintf('...writing coronal unflipped\n'); end

    avw.hdr.hist.orient = uint8(1);

    SliceDim = double(avw.hdr.dime.dim(3)); % y
    RowDim   = double(avw.hdr.dime.dim(4)); % z
    PixelDim = double(avw.hdr.dime.dim(2)); % x
    SliceSz  = double(avw.hdr.dime.pixdim(3));
    RowSz    = double(avw.hdr.dime.pixdim(4));
    PixelSz  = double(avw.hdr.dime.pixdim(2));

    x = 1:PixelDim;
    for y = 1:SliceDim,
        for z = 1:RowDim,
            fwrite(fid,avw.img(x,y,z),precision);
        end
    end

case 2, % sagittal unflipped

    % For the 'sagittal unflipped' type, the voxels are stored with
    % Pixels in 'y' axis (varies fastest) - from patient posterior to anterior
    % Rows in   'z' axis                  - from patient inferior to superior
    % Slices in 'x' axis                  - from patient right to left

    if verbose, fprintf('...writing sagittal unflipped\n'); end

    avw.hdr.hist.orient = uint8(2);

    SliceDim = double(avw.hdr.dime.dim(2)); % x
    RowDim   = double(avw.hdr.dime.dim(4)); % z
    PixelDim = double(avw.hdr.dime.dim(3)); % y
    SliceSz  = double(avw.hdr.dime.pixdim(2));
    RowSz    = double(avw.hdr.dime.pixdim(4));
    PixelSz  = double(avw.hdr.dime.pixdim(3));

    y = 1:PixelDim;
    for x = 1:SliceDim,
        for z = 1:RowDim,
            fwrite(fid,avw.img(x,y,z),precision);
        end
    end

case 3, % transverse/axial flipped

    % For the 'transverse flipped' type, the voxels are stored with
    % Pixels in 'x' axis (varies fastest) - from patient right to left
    % Rows in   'y' axis                  - from patient anterior to posterior*
    % Slices in 'z' axis                  - from patient inferior to superior

    if verbose,
        fprintf('...writing axial flipped (+Y from Anterior to Posterior)\n');
    end

    avw.hdr.hist.orient = uint8(3);

    SliceDim = double(avw.hdr.dime.dim(4)); % z
    RowDim   = double(avw.hdr.dime.dim(3)); % y
    PixelDim = double(avw.hdr.dime.dim(2)); % x
    SliceSz  = double(avw.hdr.dime.pixdim(4));
    RowSz    = double(avw.hdr.dime.pixdim(3));
    PixelSz  = double(avw.hdr.dime.pixdim(2));

    x = 1:PixelDim;
    for z = 1:SliceDim,
        for y = RowDim:-1:1, % flipped in Y
            fwrite(fid,avw.img(x,y,z),precision);
        end
    end

case 4, % coronal flipped

    % For the 'coronal flipped' type, the voxels are stored with
    % Pixels in 'x' axis (varies fastest) - from patient right to left
    % Rows in   'z' axis                  - from patient inferior to superior
    % Slices in 'y' axis                  - from patient anterior to posterior

    if verbose,
        fprintf('...writing coronal flipped (+Z from Superior to Inferior)\n');
    end

    avw.hdr.hist.orient = uint8(4);

    SliceDim = double(avw.hdr.dime.dim(3)); % y
    RowDim   = double(avw.hdr.dime.dim(4)); % z
    PixelDim = double(avw.hdr.dime.dim(2)); % x
    SliceSz  = double(avw.hdr.dime.pixdim(3));
    RowSz    = double(avw.hdr.dime.pixdim(4));
    PixelSz  = double(avw.hdr.dime.pixdim(2));

    x = 1:PixelDim;
    for y = 1:SliceDim,
        for z = RowDim:-1:1,
            fwrite(fid,avw.img(x,y,z),precision);
        end
    end

case 5, % sagittal flipped

    % For the 'sagittal flipped' type, the voxels are stored with
    % Pixels in 'y' axis (varies fastest) - from patient posterior to anterior
    % Rows in   'z' axis                  - from patient superior to inferior
    % Slices in 'x' axis                  - from patient right to left

    if verbose,
        fprintf('...writing sagittal flipped (+Z from Superior to Inferior)\n');
    end

    avw.hdr.hist.orient = uint8(5);

    SliceDim = double(avw.hdr.dime.dim(2)); % x
    RowDim   = double(avw.hdr.dime.dim(4)); % z
    PixelDim = double(avw.hdr.dime.dim(3)); % y
    SliceSz  = double(avw.hdr.dime.pixdim(2));
    RowSz    = double(avw.hdr.dime.pixdim(4));
    PixelSz  = double(avw.hdr.dime.pixdim(3));

    y = 1:PixelDim;
    for x = 1:SliceDim,
        for z = RowDim:-1:1, % superior to inferior
            fwrite(fid,avw.img(x,y,z),precision);
        end
    end

otherwise, % transverse/axial unflipped

    % For the 'transverse unflipped' type, the voxels are stored with
    % Pixels in 'x' axis (varies fastest) - from patient right to left
    % Rows in   'y' axis                  - from patient posterior to anterior
    % Slices in 'z' axis                  - from patient inferior to superior

    if verbose,
        fprintf('...unknown orientation specified, assuming default axial unflipped\n');
    end

    avw.hdr.hist.orient = uint8(0);

    SliceDim = double(avw.hdr.dime.dim(4)); % z
    RowDim   = double(avw.hdr.dime.dim(3)); % y
    PixelDim = double(avw.hdr.dime.dim(2)); % x
    SliceSz  = double(avw.hdr.dime.pixdim(4));
    RowSz    = double(avw.hdr.dime.pixdim(3));
    PixelSz  = double(avw.hdr.dime.pixdim(2));

    x = 1:PixelDim;
    for z = 1:SliceDim,
        for y = 1:RowDim,
            fwrite(fid,avw.img(x,y,z),precision);
        end
    end

end

fclose(fid);

% Update the header
avw.hdr.dime.dim(2:4) = int16([PixelDim,RowDim,SliceDim]);
avw.hdr.dime.pixdim(2:4) = single([PixelSz,RowSz,SliceSz]);

return

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

function write_header(fid,avw,verbose)

    header_key(fid,avw.hdr.hk);
    image_dimension(fid,avw.hdr.dime);
    data_history(fid,avw.hdr.hist);

    % check the file size is 348 bytes
    fbytes = ftell(fid);
    fclose(fid);
    if ~isequal(fbytes,348),
        msg = sprintf('...file size is not 348 bytes!\n');
        ft_warning(msg);
    end

return

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

function header_key(fid,hk)

	% Original header structures - ANALYZE 7.5
	% struct header_key                      /* header key      */
	%       {                                /* off + size      */
	%       int sizeof_hdr                   /*  0 +  4         */
	%       char data_type[10];              /*  4 + 10         */
	%       char db_name[18];                /* 14 + 18         */
	%       int extents;                     /* 32 +  4         */
	%       short int session_error;         /* 36 +  2         */
	%       char regular;                    /* 38 +  1         */
	%       char hkey_un0;                   /* 39 +  1         */
	%       };                               /* total=40 bytes  */

    fseek(fid,0,'bof');

    fwrite(fid, hk.sizeof_hdr(1),   'int32');  % must be 348!

    data_type = sprintf('%-10s',hk.data_type); % ensure it is 10 chars
    fwrite(fid, hk.data_type(1:10), 'uchar');

    db_name   = sprintf('%-18s',hk.db_name);   % ensure it is 18 chars
    fwrite(fid, db_name(1:18),      'uchar');

    fwrite(fid, hk.extents(1),      'int32');
    fwrite(fid, hk.session_error(1),'int16');

    regular   = sprintf('%1s',hk.regular);     % ensure it is 1 char
    fwrite(fid, regular(1),         'uchar');  % might be uint8

    %hkey_un0  = sprintf('%1s',hk.hkey_un0);    % ensure it is 1 char
    %fwrite(fid, hkey_un0(1),        'uchar');
    fwrite(fid, hk.hkey_un0(1),     'uint8');

    %    >Would you set hkey_un0 as char or uint8?
    %   Really doesn't make any difference.  As far as anyone here can remember,
    %   this was just to pad to an even byte boundary for that structure.  I guess
    %   I'd suggest setting it to a uint8 value of 0 (i.e, truly zero-valued) so
    %   that it doesn't look like anything important!
    %   Denny <hanson.dennis2@mayo.edu>

return

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

function image_dimension(fid,dime)

	%struct image_dimension
	%       {                                /* off + size      */
	%       short int dim[8];                /* 0 + 16          */
	%       char vox_units[4];               /* 16 + 4          */
	%       char cal_units[8];               /* 20 + 8          */
	%       short int unused1;               /* 28 + 2          */
	%       short int datatype;              /* 30 + 2          */
	%       short int bitpix;                /* 32 + 2          */
	%       short int dim_un0;               /* 34 + 2          */
	%       float pixdim[8];                 /* 36 + 32         */
	%			/*
	%				pixdim[] specifies the voxel dimensions:
	%				pixdim[1] - voxel width
	%				pixdim[2] - voxel height
	%				pixdim[3] - interslice distance
	%					..etc
	%			*/
	%       float vox_offset;                /* 68 + 4          */
	%       float roi_scale;                 /* 72 + 4          */
	%       float funused1;                  /* 76 + 4          */
	%       float funused2;                  /* 80 + 4          */
	%       float cal_max;                   /* 84 + 4          */
	%       float cal_min;                   /* 88 + 4          */
	%       int compressed;                  /* 92 + 4          */
	%       int verified;                    /* 96 + 4          */
	%       int glmax;                       /* 100 + 4         */
	%       int glmin;                       /* 104 + 4         */
	%       };                               /* total=108 bytes */

	fwrite(fid, dime.dim(1:8),      'int16');
	fwrite(fid, dime.vox_units(1:4),'uchar');
	fwrite(fid, dime.cal_units(1:8),'uchar');
	fwrite(fid, dime.unused1(1),    'int16');
	fwrite(fid, dime.datatype(1),   'int16');
	fwrite(fid, dime.bitpix(1),     'int16');
	fwrite(fid, dime.dim_un0(1),    'int16');
	fwrite(fid, dime.pixdim(1:8),   'float32');
	fwrite(fid, dime.vox_offset(1), 'float32');

    % Ensure compatibility with SPM (according to MRIcro)
    if dime.roi_scale == 0, dime.roi_scale = 0.00392157; end
	fwrite(fid, dime.roi_scale(1),  'float32');

	fwrite(fid, dime.funused1(1),   'float32');
	fwrite(fid, dime.funused2(1),   'float32');
	fwrite(fid, dime.cal_max(1),    'float32');
	fwrite(fid, dime.cal_min(1),    'float32');
	fwrite(fid, dime.compressed(1), 'int32');
	fwrite(fid, dime.verified(1),   'int32');
	fwrite(fid, dime.glmax(1),      'int32');
	fwrite(fid, dime.glmin(1),      'int32');

return

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

function data_history(fid,hist)

	% Original header structures - ANALYZE 7.5
	%struct data_history
	%       {                                /* off + size      */
	%       char descrip[80];                /* 0 + 80          */
	%       char aux_file[24];               /* 80 + 24         */
	%       char orient;                     /* 104 + 1         */
	%       char originator[10];             /* 105 + 10        */
	%       char generated[10];              /* 115 + 10        */
	%       char scannum[10];                /* 125 + 10        */
	%       char patient_id[10];             /* 135 + 10        */
	%       char exp_date[10];               /* 145 + 10        */
	%       char exp_time[10];               /* 155 + 10        */
	%       char hist_un0[3];                /* 165 + 3         */
	%       int views                        /* 168 + 4         */
	%       int vols_added;                  /* 172 + 4         */
	%       int start_field;                 /* 176 + 4         */
	%       int field_skip;                  /* 180 + 4         */
	%       int omax;                        /* 184 + 4         */
	%       int omin;                        /* 188 + 4         */
	%       int smax;                        /* 192 + 4         */
	%       int smin;                        /* 196 + 4         */
	%       };                               /* total=200 bytes */

    descrip     = sprintf('%-80s', hist.descrip);       % 80 chars
    aux_file    = sprintf('%-24s', hist.aux_file);      % 24 chars
    originator  = sprintf('%-10s', hist.originator);    % 10 chars
    generated   = sprintf('%-10s', hist.generated);     % 10 chars
    scannum     = sprintf('%-10s', hist.scannum);       % 10 chars
    patient_id  = sprintf('%-10s', hist.patient_id);    % 10 chars
    exp_date    = sprintf('%-10s', hist.exp_date);      % 10 chars
    exp_time    = sprintf('%-10s', hist.exp_time);      % 10 chars
    hist_un0    = sprintf( '%-3s', hist.hist_un0);      %  3 chars

    % ---
    % The following should not be necessary, but I actually
    % found one instance where it was, so this totally anal
    % retentive approach became necessary, despite the
    % apparently elegant solution above to ensuring that variables
    % are the right length.

    if length(descrip) < 80,
      paddingN = 80-length(descrip);
      padding = char(repmat(double(' '),1,paddingN));
      descrip = [descrip,padding];
    end
    if length(aux_file) < 24,
      paddingN = 24-length(aux_file);
      padding = char(repmat(double(' '),1,paddingN));
      aux_file = [aux_file,padding];
    end
    if length(originator) < 10,
      paddingN = 10-length(originator);
      padding = char(repmat(double(' '),1,paddingN));
      originator = [originator, padding];
    end
    if length(generated) < 10,
      paddingN = 10-length(generated);
      padding = char(repmat(double(' '),1,paddingN));
      generated = [generated, padding];
    end
    if length(scannum) < 10,
      paddingN = 10-length(scannum);
      padding = char(repmat(double(' '),1,paddingN));
      scannum = [scannum, padding];
    end
    if length(patient_id) < 10,
      paddingN = 10-length(patient_id);
      padding = char(repmat(double(' '),1,paddingN));
      patient_id = [patient_id, padding];
    end
    if length(exp_date) < 10,
      paddingN = 10-length(exp_date);
      padding = char(repmat(double(' '),1,paddingN));
      exp_date = [exp_date, padding];
    end
    if length(exp_time) < 10,
      paddingN = 10-length(exp_time);
      padding = char(repmat(double(' '),1,paddingN));
      exp_time = [exp_time, padding];
    end
    if length(hist_un0) < 10,
      paddingN = 10-length(hist_un0);
      padding = char(repmat(double(' '),1,paddingN));
      hist_un0 = [hist_un0, padding];
    end

    % -- if you thought that was anal, try this;
    % -- lets check for unusual ASCII char values!

    if find(double(descrip)>128),
      indexStrangeChar = find(double(descrip)>128);
      descrip(indexStrangeChar) = ' ';
    end
    if find(double(aux_file)>128),
      indexStrangeChar = find(double(aux_file)>128);
      aux_file(indexStrangeChar) = ' ';
    end
    if find(double(originator)>128),
      indexStrangeChar = find(double(originator)>128);
      originator(indexStrangeChar) = ' ';
    end
    if find(double(generated)>128),
      indexStrangeChar = find(double(generated)>128);
      generated(indexStrangeChar) = ' ';
    end
    if find(double(scannum)>128),
      indexStrangeChar = find(double(scannum)>128);
      scannum(indexStrangeChar) = ' ';
    end
    if find(double(patient_id)>128),
      indexStrangeChar = find(double(patient_id)>128);
      patient_id(indexStrangeChar) = ' ';
    end
    if find(double(exp_date)>128),
      indexStrangeChar = find(double(exp_date)>128);
      exp_date(indexStrangeChar) = ' ';
    end
    if find(double(exp_time)>128),
      indexStrangeChar = find(double(exp_time)>128);
      exp_time(indexStrangeChar) = ' ';
    end
    if find(double(hist_un0)>128),
      indexStrangeChar = find(double(hist_un0)>128);
      hist_un0(indexStrangeChar) = ' ';
    end

    % --- finally, we write the fields

    fwrite(fid, descrip(1:80),    'uchar');
    fwrite(fid, aux_file(1:24),   'uchar');

    %orient      = sprintf(  '%1s', hist.orient);        %  1 char
    %fwrite(fid, orient(1),        'uchar');
    fwrite(fid, hist.orient(1),   'uint8');     % see note below on char

    fwrite(fid, originator(1:10), 'uchar');
    fwrite(fid, generated(1:10),  'uchar');
    fwrite(fid, scannum(1:10),    'uchar');
    fwrite(fid, patient_id(1:10), 'uchar');
    fwrite(fid, exp_date(1:10),   'uchar');
    fwrite(fid, exp_time(1:10),   'uchar');
    fwrite(fid, hist_un0(1:3),    'uchar');

    fwrite(fid, hist.views(1),      'int32');
    fwrite(fid, hist.vols_added(1), 'int32');
    fwrite(fid, hist.start_field(1),'int32');
    fwrite(fid, hist.field_skip(1), 'int32');
    fwrite(fid, hist.omax(1),       'int32');
    fwrite(fid, hist.omin(1),       'int32');
    fwrite(fid, hist.smax(1),       'int32');
    fwrite(fid, hist.smin(1),       'int32');

return

% Note on using char:
% The 'char orient' field in the header is intended to
% hold simply an 8-bit unsigned integer value, not the ASCII representation
% of the character for that value.  A single 'char' byte is often used to
% represent an integer value in Analyze if the known value range doesn't
% go beyond 0-255 - saves a byte over a short int, which may not mean
% much in today's computing environments, but given that this format
% has been around since the early 1980's, saving bytes here and there on
% older systems was important!  In this case, 'char' simply provides the
% byte of storage - not an indicator of the format for what is stored in
% this byte.  Generally speaking, anytime a single 'char' is used, it is
% probably meant to hold an 8-bit integer value, whereas if this has
% been dimensioned as an array, then it is intended to hold an ASCII
% character string, even if that was only a single character.
% Denny  <hanson.dennis2@mayo.edu>

% See other notes in avw_hdr_read


%LOADPCD Load a point cloud from a PCD format file
%
% P = LOADPCD(FNAME) is a set of points loaded from the PCD format
% file FNAME.
%
% For an unorganized point cloud the columns of P represent the 3D points,
% and the rows are: x, y, z, r, g, b, a depending on the FIELDS in the file.
%
% For an organized point cloud P is a 3-dimensional matrix (HxWxN) where the
% N planes are: x, y, z, r, g, b, a depending on the FIELDS in the file.  This
% format is useful since the planes z, r, g, b, a can be considered as images.
%
% Notes::
% - Only the x y z field format are currently supported
% - The file can be in ascii or binary format, binary_compressed is not
%   supported
%
% See also pclviewer, lspcd, loadpcd.
%
% Copyright (C) 2013, by Peter I. Corke

% TODO
% - handle binary_compressed

function points = loadpcd(fname)

    verbose = true;

    fp = fopen(fname, 'r');

    while true
        line = fgetl(fp);

        if line(1) == '#'
            continue;
        end

        [field,remain] = strtok(line, ' \t');
        remain = strtrim(remain);

        switch field
            case 'VERSION'
                continue;
            case 'FIELDS'
                FIELDS = remain;
            case 'TYPE'
                TYPE = remain;
            case 'SIZE'
                sizes = str2num(remain);
            case 'WIDTH'
                width = str2num(remain);
            case 'HEIGHT'
                height = str2num(remain);
            case 'POINTS'
                npoints = str2num(remain);
            case 'COUNT'
                count = str2num(remain);
            case 'DATA'
                mode = remain;
                break;
            otherwise
                warning('unknown field %s\n', field);
        end
    end

    % parse out details of the fields
    %  numFields    the number of fields
    %  sizes        vector of field sizes (in bytes)
    %  types        vector of type identifiers (I U F)
    %  fields       vector of field names (x y z rgb rgba etc)
    numFields = numel(sizes);
    types = cell2mat(regexp(TYPE,'\s+','split'));
    fields = regexp(FIELDS,'\s+','split');

    if verbose
        % the doco says height > 1 means organized, but some old files have
        % height = 1 and width > 1
        if height > 1 && width > 1
            organized = true;
            org = 'organized';
        else
            organized = false;
            org = 'unorganized';
        end
        fprintf('%s: %s, %s, <%s> %dx%d\n', ...
            fname, mode, org, FIELDS, width, height);
        fprintf('  %s; %s\n', TYPE, num2str(sizes));
    end

    if any(count > 1)
        error('can only handle 1 element per dimension');
    end

    switch mode
        case 'ascii'
            format = '';
            for j=1:numFields
                switch types(j)
                    case 'I', typ = 'd';
                    case 'U', typ = 'u';
                    case 'F', typ = 'f';
                end
                format = [format '%' typ num2str(sizes(j)*8)];
            end
            c = textscan(fp, format, npoints);
            points = [];
            for j=1:length(c)
                points = [points; c{j}'];
            end
            if size(points,2) ~= npoints
                error('incorrect number of points in file: was %d, should be %d', ...
                    size(points,2), npoints);
            end

        case 'binary'
            format = '';

            if true || all(types == types(1)) && all(sizes == sizes(1))
                % simple case where all fields have the same length and type

                % map IUF -> int, uint, float
                switch types(1)
                    case 'I'
                        fmt = 'int';
                    case 'U'
                        fmt = 'uint';
                    case 'F'
                        fmt = 'float';
                end

                format = [format '*' fmt num2str(sizes(1)*8)];
                points = fread(fp, [numFields npoints], format);

            else

                % more complex case where fields have different length and type
                % code contributed by Will

                startPos_fp = ftell(fp);

                % Just initialize the xyz portion for now
                points = zeros(3, npoints);

                for i=1:numFields
                    % map each field sequentially, using fread() skip functionality,
                    % essentially interleaved reading of the file

                    % map IUF -> int, uint, float
                    switch types(i)
                        case 'I'
                            fmt = 'int';
                        case 'U'
                            fmt = 'uint';
                        case 'F'
                            fmt = 'float';
                    end

                    format = ['*' fmt num2str(sizes(i)*8)];
                    fseek(fp, startPos_fp + sum(sizes(1:i-1)), 'bof');
                    data = fread(fp, [1 npoints], format, sum(sizes)-sizes(i));

                    switch fields{i}
                        case 'x'
                            points(1,:) = data;
                        case 'y'
                            points(2,:) = data;
                        case 'z'
                            points(3,:) = data;
                        case {'rgb', 'rgba'}
                            points(4,:) = data;
                    end
                end

            end

        case 'binary_compressed'
            % binary part of the file contains:
            %  compressed size of data (uint32)
            %  uncompressed size of data (uint32)
            %  compressed data
            %  junk
            compressed_size = fread(fp, 1, 'uint32');
            uncompressed_size = fread(fp, 1, 'uint32');
            compressed_data = fread(fp, compressed_size, 'uint8')';

            uncompressed_data = lzfd(compressed_data);
            if length(uncompressed_data) ~= uncompressed_size
                error('decompression error');
            end

            % the data is stored unpacked, that is one field for all points,
            % then the next field for all points, etc.

            start = 1;
            for i=1:numFields
                len = sizes(i)*npoints;
                switch types(1)
                    case 'I'
                        fmt = 'int32';
                    case 'U'
                        fmt = 'uint32';
                    case 'F'
                        fmt = 'single';
                end
                field = typecast(uncompressed_data(start:start+len-1), fmt);
                start = start + len;

                switch fields{i}
                    case 'x'
                        points(1,:) = field;
                    case 'y'
                        points(2,:) = field;
                    case 'z'
                        points(3,:) = field;
                    case {'rgb', 'rgba'}
                        points(4,:) = field;
                end
            end

        otherwise
            error('unknown DATA mode: %s', mode);
    end

    if size(points,1) > 3
        % convert RGB from float to rgb
        rgb = typecast(points(4,:), 'uint32');
        switch FIELDS
            case 'x y z rgb'
                R = double(bitand(255, bitshift(rgb, 16))) /255;
                G = double(bitand(255, bitshift(rgb, 8))) /255;
                B = double(bitand(255, rgb)) /255;
                points = [points(1:3,:); R; G; B];

            case 'x y z rgba'
                R = double(bitand(255, bitshift(rgb, 24))) /255;
                G = double(bitand(255, bitshift(rgb, 16))) /255;
                B = double(bitand(255, bitshift(rgb, 8))) /255;
                A = double(bitand(255, rgb)) /255;
                points = [points(1:3,:); R; G; B; A];
        end
    end

    if organized
        % data is an organized point cloud, rearrange it into planes

        points = permute( reshape( shiftdim(points, 1), width, height, []), [2 1 3]);
    end

    fclose(fp);


 function [dim, varargout] = size(ob, varargin)
%function dim = size(ob, varargin)
% or [dim1 dim2] = size(ob)
% "size" method for this class

dim = ob.dim;

if length(varargin) == 1
	dim = dim(varargin{1});
	return
elseif length(varargin) ~= 0
	error 'bug'
end

if nargout > 1
	varargout{1} = dim(2);
	dim = dim(1);
end


function mode = setColormap(mode,cmapFn)
%
%  mode = setColormap(mode,cmapFn)
%
% Author:  My guess, Dave Heeger
% Purpose:
%   If you call a color map function, say hsv,
%   this routine builds a color map entry for that mode using the hsv function.
%

numGrays  = mode.numGrays;
numColors = mode.numColors;

% mode.cmap=cmapFn(numGrays,numColors);
eval(['mode.cmap=',cmapFn,'(numGrays,numColors);']);
mode.name = cmapFn;

return


function test_bug2773

% WALLTIME 00:20:00
% MEM 2gb
% DEPENDENCY ft_dipolefitting ft_movieplotER ft_prepare_sourcemodel ft_prepare_layout

orig = load(dccnpath('/home/common/matlab/fieldtrip/data/test/bug2773.mat'));
vol  = orig.cfg.vol;
elec = orig.cfg.elec;

cfg = [];
cfg.elec = elec;
cfg.channel =    {
  '1'
  '2'
  '3'
  '4'
  '5'
  '6'
  '7'
  '8'
  '9'
  '10'
  '11'
  '12'
  '13'
  '14'
  '15'
  '16'
  '17'
  '18'
  '19'
  '20'
  '21'
  '22'
  '23'
  '24'
  '25'
  '26'
  '27'
  '28'
  '29'
  '30'
  '31'
  '32'
  '33'
  '34'
  '35'
  '36'
  '37'
  '38'
  '39'
  '40'
  '41'
  '42'
  '43'
  '44'
  '45'
  '46'
  '47'
  '48'
  '49'
  '50'
  '51'
  '52'
  '53'
  '54'
  '55'
  '56'
  '57'
  '58'
  '59'
  '60'
  '61'
  };

layout = ft_prepare_layout(cfg); % it is not a very nice layout, but will do for the test script

figure; ft_plot_layout(layout);
figure; ft_plot_sens(elec);
figure; ft_plot_headmodel(vol);


classdef TestBinaryDescriptorMatcher
    %TestBinaryDescriptorMatcher

    properties (Constant)
        fields = {'queryIdx', 'trainIdx', 'imgIdx', 'distance'};
    end

    methods (Static)
        function test_matcher
            %TODO: something in this test is causing memory corruption and
            %TODO: crashing MATLAB on repeated runs.. most likely an OpenCV bug!
            if true
                error('mexopencv:testskip', 'todo');
            end

            X = randi([0,255], [50,32], 'uint8');
            Y = randi([0,255], [10,32], 'uint8');
            matcher = cv.BinaryDescriptorMatcher();
            matcher.add(X);
            matcher.train();

            m = matcher.match(Y);
            validateattributes(m, {'struct'}, {'vector'});
            assert(all(ismember(TestBinaryDescriptorMatcher.fields, ...
                fieldnames(m))));

            k = 3;
            m = matcher.knnMatch(Y, k);
            validateattributes(m, {'cell'}, ...
                {'vector', 'numel',size(Y,1)});
            cellfun(@(mm) validateattributes(mm, {'struct'}, ...
                {'vector', 'numel',k}), m);
            cellfun(@(mm) assert(all(ismember(...
                TestBinaryDescriptorMatcher.fields, fieldnames(mm)))), m);

            maxDist = 125.0;
            m = matcher.radiusMatch(Y, maxDist);
            validateattributes(m, {'cell'}, ...
                {'vector', 'numel',size(Y,1)});
            cellfun(@(mm) validateattributes(mm, ...
                {'struct'}, {'vector'}), m);
            cellfun(@(mm) assert(all(ismember(...
                TestBinaryDescriptorMatcher.fields, fieldnames(mm)))), m);
            assert(all(cellfun(@(mm) all([mm.distance] <= maxDist), m)));
        end

        function test_matcher_mask
            X = randi([0,255], [50,32], 'uint8');
            Y = randi([0,255], [10,32], 'uint8');
            matcher = cv.BinaryDescriptorMatcher();
            mask = rand(size(Y,1), 1) > 0.5;

            m = matcher.match(Y, X, 'Mask',mask);
            validateattributes(m, {'struct'}, {'vector'});

            m = matcher.knnMatch(Y, X, 3, 'Mask',mask);
            validateattributes(m, {'cell'}, {'vector', 'numel',size(Y,1)});

            m = matcher.radiusMatch(Y, X, 2.0, 'Mask',mask);
            validateattributes(m, {'cell'}, {'vector', 'numel',size(Y,1)});
        end

        function test_closest_image
            %TODO: something in this test is causing memory corruption and
            %TODO: crashing MATLAB on repeated runs.. most likely an OpenCV bug!
            if true
                error('mexopencv:testskip', 'todo');
            end

            % compute descriptors for all training images
            obj = cv.BinaryDescriptor('NumOfOctave',1);
            matcher = cv.BinaryDescriptorMatcher();
            query = [];
            files = dir(fullfile(mexopencv.root(),'test','shape0*.png'));
            if isempty(files)
                error('mexopencv:testskip', 'missing data');
            end
            idxQuery = 1;
            idxTrain = 2:numel(files);
            for i=1:numel(files)
                img = cv.imread(fullfile(mexopencv.root(),'test',files(i).name), 'Flags',0);
                whos img
                [~,desc] = obj.detectAndCompute(img);
                assert(~isempty(desc));
                if i == idxQuery
                    query = desc;
                else
                    matcher.add(desc);
                end
            end

            % find matches between query and train set
            matcher.train();
            m = matcher.match(query);

            % naive approach to find nearest image
            [~,ord] = sort([m.distance]);         % retain best 100 (min dist)
            m = m(ord(1:min(10,end)));
            ii = idxTrain(mode([m.imgIdx]) + 1);  % most frequest image index
            query = files(idxQuery).name;
            closest = files(ii).name;
        end
    end

end


function value = p18_r8vec ( action, name, dim_num, value )

%*****************************************************************************80
%
%% P18_R8VEC sets or gets R8VEC parameters for problem 18.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    19 March 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string ACTION, the action.
%    'D' sets the internal value of the object to a default value.
%    If NAME = '*', then all variables are defaulted.
%    'G' means the current value of the object should be returned.
%    'R' means randomize the object and return it.
%    'S' means the input values of the object and its dimension should
%      be stored.
%
%    Input, string NAME, the name of the parameter.
%    'Z' is the base vector.
%
%    Input, integer DIM_NUM, the dimension of the object.
%
%    Input/output, real VALUE(DIM_NUM), the value of the object.
%
  persistent dim_num_save
  persistent z

  if ( size ( dim_num_save ) == 0 )
    dim_num_save = 0;
  end

  if ( dim_num_save ~= dim_num )
    dim_num_save = 0;
    z = [];
  end

  if ( dim_num_save == 0 )
    dim_num_save = dim_num;
  end

  if ( action == 'D' | action == 'd' )

    if ( name == 'Z' | name == 'z' | name == '*' )
      z(1:dim_num) = 0.5;
    end

  elseif ( action == 'G' | action == 'g' )

    if ( name == 'Z' | name == 'z' )
      value(1:dim_num) = z(1:dim_num);
    else
      fprintf ( 1, '\n' );
      fprintf ( 1, 'P18_R8VEC - Fatal error!\n' );
      fprintf ( 1, '  Unrecognized name = "%s".\n', name );
      error ( 'P18_R8VEC - Fatal error!' );
    end

  elseif ( action == 'R' | action == 'r' )

    if ( name == 'Z' | name == 'z' )
      z = rand ( 1, dim_num );
      value(1:dim_num) = z(1:dim_num);
    else
      fprintf ( 1, '\n' );
      fprintf ( 1, 'P18_R8VEC - Fatal error!\n' );
      fprintf ( 1, '  Unrecognized name = "%s".\n', name );
      error ( 'P18_R8VEC - Fatal error!' );
    end

  elseif ( action == 'S' | action == 's' )

    if ( name == 'Z' | name == 'z' )
      z(1:dim_num) = value(1:dim_num);
    else
      fprintf ( 1, '\n' );
      fprintf ( 1, 'P18_R8VEC - Fatal error!\n' );
      fprintf ( 1, '  Unrecognized name = "%s".\n', name );
      error ( 'P18_R8VEC - Fatal error!' );
    end

  else

    fprintf ( 1, '\n' );
    fprintf ( 1, 'P18_R8VEC - Fatal error!\n' );
    fprintf ( 1, '  Unrecognized action = "%s".\n', action );
    error ( 'P18_R8VEC - Fatal error!' );

  end

  return
end


function [Obj, log] = SOFAexpand(Obj,VarName)
%SOFAexpand - Expand variables in a SOFA object
%   Usage: Obj = SOFAexpand(Obj,VarName)
%
%   SOFAexpand(Obj,VarName) expands the the singleton dimensions of
%   the variable VarName, e.g., a variable SourcePosition containing a single entry
%   thus size of [I C], will be expanded to the next possible,thus size of [I M].
%   The potential for the expansion is defined in API.Dimensions.VarName.
%   Obj.API.Dimensions will be updated to the new dimensions.
%
%   SOFAexpand(Obj) expands the singleton dimensions of all variables of Obj.
%   Note that Data variables are not expanded.
%
%	Obj = SOFAexpand(Obj,VarName) expands the singleton dimensions of the variable VarName.
%
%   [Obj,log] = SOFAexpand(..) returns a log of expanded variables.

% #Author: Piotr Majdak
% #Author: Michael Mihocic: header documentation updated (28.10.2021)
%
% SOFA Toolbox - function SOFAexpand
% Copyright (C) Acoustics Research Institute - Austrian Academy of Sciences
% Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European Commission - subsequent versions of the EUPL (the "License")
% You may not use this work except in compliance with the License.
% You may obtain a copy of the License at: https://joinup.ec.europa.eu/software/page/eupl
% Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
% See the License for the specific language governing  permissions and limitations under the License.

%% Initial check
OC = SOFAgetConventions(Obj.GLOBAL_SOFAConventions,'a');
log={''};

%% Update dimensions
Obj=SOFAupdateDimensions(Obj,'nodata');

%% If VarName given, expand a single variable only
if ~exist('VarName','var'),

  %% Expand all variables
    % create field names which should have dimensions
  X=rmfield(Obj,{'Data','API'});
  if isfield(X,'PRIVATE'), X=rmfield(X,'PRIVATE'); end
  Xf=fieldnames(X);

  % Update the dimensions structure w/o data
  for ii=1:length(Xf)
    if ~isempty(strfind(Xf{ii},'_')),	continue; end; % is an attribute --> not expandable
    if ~isfield(OC.API.Dimensions, Xf{ii}), continue; end; % is a used-defined variable --> not expandable
    dim=OC.API.Dimensions.(Xf{ii}); % all possible dimensions
    if ~iscell(dim), continue; end;	% is a variable with a single dimension definition --> not expandable
    if numel(dim)==1, continue; end;	% is a variable with a single dimension definition --> not expandable
    [varNew,dimNew]=expand(Obj,Xf{ii},dim);
    if ~isempty(varNew),
      Obj.(Xf{ii})=varNew;
      Obj.API.Dimensions.(Xf{ii})=dimNew;
      log{end+1}=[Xf{ii} ' expanded to ' dimNew];
    end
  end

  % Expand the dimensions of Data
  Xf=fieldnames(Obj.Data);
  for ii=1:length(Xf)
    if ~isempty(strfind(Xf{ii},'_')),	continue; end; % is an attribute --> not expandable
    if ~isfield(OC.API.Dimensions.Data, Xf{ii}), continue; end; % is a used-defined variable --> not expandable
    dim=OC.API.Dimensions.Data.(Xf{ii}); % all possible dimensions
    if ~iscell(dim), continue; end;	% is a variable with a single dimension definition --> not expandable
    if numel(dim)==1, continue; end;	% is a variable with a single dimension definition --> not expandable
    [varNew,dimNew]=expandData(Obj,Xf{ii},dim);
    if ~isempty(varNew),
      Obj.Data.(Xf{ii})=varNew;
      Obj.API.Dimensions.Data.(Xf{ii})=dimNew;
      log{end+1}=['Data.' Xf{ii} ' expanded to ' dimNew];
    end
  end

else	% Expand a single variable only
	if isempty(strfind(VarName,'_')),	% is an attribute --> not expandable
    if strncmp(VarName,'Data.',length('Data.'))
      % variable within the Data. structure
      VarName=VarName(length('Data.')+1:end);
      if isfield(OC.API.Dimensions.Data, VarName), % is a used-defined variable --> not expandable
        dim=OC.API.Dimensions.Data.(VarName); % all possible dimensions
        if iscell(dim), % is a variable with a single dimension definition --> not expandable
            [varNew,dimNew]=expandData(Obj,VarName,dim);
            if ~isempty(varNew),
                Obj.Data.(VarName)=varNew;
                Obj.API.Dimensions.Data.(VarName)=dimNew;
                log{end+1}=['Data.' VarName ' expanded to ' dimNew];
            end
        end
      end
    else
      if isfield(OC.API.Dimensions, VarName), % is a used-defined variable --> not expandable
        dim=OC.API.Dimensions.(VarName); % all possible dimensions
        if iscell(dim), % is a variable with a single dimension definition --> not expandable
          [varNew,dimNew]=expand(Obj,VarName,dim);
          if ~isempty(varNew),
              Obj.(VarName)=varNew;
              Obj.API.Dimensions.(VarName)=dimNew;
              log{end+1}=[VarName ' expanded to ' dimNew];
          end
        end
      end
		end
	end
end

%% log variable
if length(log)>1, log=log(2:end); else log={}; end;

%% expand a single variable
% Obj: the full SOFA object
% f: name of the variable
% dims: allowed dimensions of that variable (cell array)
% var: expanded variable, or empty if nothing happened
% dN: new dimension, or empty if nothing happened
function [var,dN]=expand(Obj,f,dims)
	d=cell2mat(strfind(dims,'I'));	% all choices for a singleton dimensions
	for jj=1:length(d)	% loop through all expandable dimensions
		len=size(Obj.(f),d(jj)); % size of the considered dimension
		if len>1, continue; end;	% the expandable dimension is already expanded
		dN=dims{cellfun('isempty',strfind(dims,'I'))==1};
		var=bsxfun(@times,Obj.(f),ones([getdim(Obj,dN) 1]));
	end
	if ~exist('var','var'), var=[]; dN=[]; end;
%% Get the sizes of the dimension variables according the dimension variables in str
function vec=getdim(Obj,str)
	vec=arrayfun(@(f)(Obj.API.(f)),upper(str));

%% expand a single Data variable
% Obj: the full SOFA object
% f: name of the Data variable
% dims: allowed dimensions of that variable (cell array)
% var: expanded variable, or empty if nothing happened
% dN: new dimension, or empty if nothing happened
function [var,dN]=expandData(Obj,f,dims)
	d=cell2mat(strfind(dims,'I'));	% all choices for a singleton dimensions
	for jj=1:length(d)	% loop through all expandable dimensions
		len=size(Obj.Data.(f),d(jj)); % size of the considered dimension
		if len>1, continue; end;	% the expandable dimension is already expanded
		dN=dims{cellfun('isempty',strfind(dims,'I'))==1};
		var=bsxfun(@times,Obj.Data.(f),ones([getdim(Obj,dN) 1]));
	end
	if ~exist('var','var'), var=[]; dN=[]; end;


% eeg_multieegplot() - Produce an eegplot() of a the average of an epoched dataset
%                  (with optional pre-labelling of specific trials).
% Usage:
%   >> eeg_multieegplot( data,trialrej, elecrej, ...
%                                'key1', value, 'key2', value ... );
% Inputs:
%   data        - input data (channels x points or channels x points x trials).
%   trialrej    - array of 0s and 1s (depicting rejected trials) (size sweeps)
%   elecrej     - array of 0s and 1s (depicting electrodes rejected in
%                 all trials) (size nbelectrodes x sweeps )
%   oldtrialrej - array of 0s and 1s (depicting rejected trials) (size sweeps)
%   oldelecrej  - array of 0s and 1s (depicting electrodes rejected in
%                 all trials) (size nbelectrodes x sweeps )
%
% Note: 1) {'Key', value } Arguments are passed on to eegplot()
%       2) To ignore previous rejections simply set 'oldtrialrej' and
%          'oldelecrej' arguments to empty ([]).
%
% Author: Arnaud Delorme, CNL / Salk Institute, 2001
%
% See also: eegplot(), eegplot2event(), eegplot2trial(), eeglab()

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

% 01-25-02 reformated help & license -ad
% 03-07-02 corrected help -ad

function eeg_multieegplot( data, rej, rejE, oldrej, oldrejE, varargin);

if nargin < 1
   help eeg_multieegplot;
   return;
end;
if nargin < 4
   oldrej = [];
end;
if nargin < 5
   oldrejE = [];
end;
if ~exist('command')
	command = '';
end;
chans = size(data,1);
pnts  = size(data,2);

colnew = [0.8 0.8 1];
colold = [0.8 1 0.8];

if ndims(data) > 2 % --------------- considering epoched EEG data
   rejeegplot = [];
   % concatenate old rejection if not empty
   % --------------------------------------
   if ~isempty( oldrej )
   		oldrej 	 = find( oldrej > 0);
   		oldrejE  = oldrejE(:, oldrej)';
   		rejeegplot = trial2eegplot( oldrej, oldrejE, pnts, colold);
   end;
   % convert for eegplot
   % -------------------
   if ~isempty(	rej )
   		rej    = find( rej > 0);
   		rejE   = rejE(:,rej)';
   		secondrejeegplot = trial2eegplot( rej, rejE, pnts, colnew); % see bottom of code for this function
   		rejeegplot = [ rejeegplot' secondrejeegplot' ]';

   		% remove duplicates
   		% -----------------
		%[tmp I] = unique( rejeegplot(:,1) );
		%rejeegplot = rejeegplot(I,:);
   end;
else % ---------------------------------------- considering continuous EEG
   % for continuous EEG, electrodes (rejE and oldrejE) are not considered yet
   % because there would be a format problem (these rejection are stored in
   % the event array).

   rejeegplot = [];
   if ~isempty(rej) %assuming nrejection x 2 (2 = begin end)
      s = size(rej, 1);
      rejeegplot = [ rej(3:4) colnew*ones(s,1)  zeros(s, chans) ];
   end;

   % pooling previous rejections
   if ~isempty(oldrej)
       tmp = [ oldrej(:, 3:4) colold*ones(s,1) zeros(size(oldrej,1), chans) ];
       rejeegplot = [rejeegplot; tmp];
   end;
end;

if isempty(varargin)
	eegplot(data, 'winlength', 5, 'position', [100 300 800 500], 'winrej', rejeegplot, 'xgrid', 'off');
else
	eegplot(data, 'winlength', 5, 'position', [100 300 800 500], 'winrej', rejeegplot, 'xgrid', 'off', varargin{:} );
end;
return;

% convert eeglab format to eeplot format of rejection window
% ----------------------------------------------------------
function rejeegplot = trial2eegplot( rej, rejE, pnts, color)
   	rejeegplot = zeros(length(rej), size(rejE,2)+5);
   	rejeegplot(:, 6:end) = rejE;
   	rejeegplot(:, 1) = (rej(:)-1)*pnts;
   	rejeegplot(:, 2) = rej(:)*pnts-1;
   	rejeegplot(:, 3:5) = ones(size(rejeegplot,1),1)*color;
return


function tblstring = makeSAMMIdataString(tbl)
    tblstring = '[[''';

    %Headers
    tblstring = strcat(tblstring,strjoin(tbl.Properties.VariableNames,''','''),'''],');

    %Data
    dat = table2array(tbl);

    %Make key string
    fun = @(a) strjoin(sprintfc('%g',a{1}),'","');
    fd = arrayfun(fun,num2cell(dat,2),'UniformOutput',false);
    fd = strcat('["',tbl.Properties.RowNames,'","',fd,'"]');
    tblstring = strcat(tblstring,strjoin(fd,','),']');
end


function sout = cvx_solver( flag )

%CVX_SOLVER    CVX solver selection.
%   CVX_SOLVER SDPT3  selects SDPT3  as the solver CVX uses to solve models.
%   CVX_SOLVER SeDuMi selects SeDuMi as the solver CVX uses to solve models.
%   The solver string is case-insensitive; e.g., 'sdpt3' is fine.
%
%   The default solver is SeDuMi. For most models, this will be the best
%   choice. Nevertheless, for your problems you may find that SDPT3 is
%   more accurate or reliable, hence the need for this command.
%
%   If CVX_SOLVER is called within a model---that is, between the statements
%   CVX_BEGIN and CVX_END---then the new solver selection applies only to that
%   particular model. In this mode, the change takes place for *both*
%   successive approximation models and normal models.
%
%   If called outside of a model, then the change applies to
%   all subsequent models; that is, it modifies the default solver.
%
%   On exit, CVX_SOLVER returns the *previous* solver. This can be used to
%   restore that solver selection at a later time, in a manner similar to
%   CVX_PRECISION.
%
%   CVX_SOLVER, with no arguments, returns the current solver.

global cvx___
cvx_global
if nargin > 0,
    if isempty( flag ),
        flag = 'sedumi';
    elseif ~ischar( flag ) || size( flag, 1 ) ~= 1,
        error( 'Argument must be a string.' );
    elseif ~isfield( cvx___.path.solvers, lower( flag )  ),
        error( 'Unknown, unusable, or missing solver: %s', flag );
    end
end
if isempty( cvx___.problems ),
    s = cvx___.solver;
    if nargin > 0,
        cvx___.solver = flag;
    end
else
    s = cvx___.problems(end).solver;
    if nargin > 0,
        if ~strcmpi( s, flag ) && ~isa( evalin( 'caller', 'cvx_problem', '[]' ), 'cvxprob' ),
            warning( 'CVX:Solver', 'The global CVX solver selection cannot be changed while a model is being constructed.' );
        else
            cvx___.problems(end).solver = flag;
        end
    end
end
if nargin > 0 && cvx___.path.hold,
    cvx_setspath( flag );
end
if nargin == 0 || nargout > 0,
    sout = s;
end

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


% reload paths etc.
% NOTE!
% The mex lock has been removed from caffe_.cpp!
%munlock('caffe_') ;
clear all ; %#ok
caffePath = '/users/albanie/coding/libs/caffes/se-caffe/matlab' ;
%munlock('caffe_') ;
%clear caffe_.mexa64 ;
clear caffe_ ;
rehash path ;

% hack to avoid cuda errors
a = gpuArray(1); clear a ; %#ok

% refresh/set up ssd-caffe
addpath(caffePath) ;

caffeRoot = '/users/albanie/coding/libs/caffes/se-caffe' ;

% set paths and load caffe ssd-model
modelDir = '/users/albanie/data/models/caffe/SE-nets/proto' ;
dataDir = '/users/albanie/data/models/caffe/SE-nets/weights' ;
model = fullfile(modelDir, 'SE-ResNet-50-debug.prototxt') ;
weights = fullfile(dataDir, 'SE-ResNet-50.caffemodel') ;
caffe.set_mode_cpu() ;

% to use the relative paths defined in the prototxt, we change into the
% caffe root to load the network
cd(caffeRoot) ;

% load model
caffeNet = caffe.Net(model, weights, 'test') ;

% load mcn model for comparison

% set path to trunk model (VGG-VD-16)
opts.trunkModelPath = fullfile(vl_rootnn, 'data', 'models-import', ...
                                'SE-ResNet-50-mcn.mat') ;
opts.imageSize = [224 224] ;
net = load(opts.trunkModelPath) ; net = dagnn.DagNN.loadobj(net) ;


%CALCBLURRINESS  Calculate image blurriness
%
%     blurriness = cv.calcBlurriness(img)
%
% ## Input
% * __img__ input image.
%
% ## Output
% * __blurriness__ calculated blurriness.
%
% See also: cv.Sobel
%


classdef TestRollingGuidanceFilter
    %TestRollingGuidanceFilter

    methods (Static)
        function test_1
            img = cv.imread(fullfile(mexopencv.root(),'test','lena.jpg'), ...
                'Color',true, 'ReduceScale',2);
            dst = cv.rollingGuidanceFilter(img, 'SigmaSpace',3.0);
            validateattributes(dst, {class(img)}, {'size',size(img)});
        end

        function test_error_argnum
            try
                cv.rollingGuidanceFilter();
                throw('UnitTest:Fail');
            catch e
                assert(strcmp(e.identifier,'mexopencv:error'));
            end
        end
    end

end


function opts = mkopts_cdp(K);

opts.algorithm = 'cdp';
opts.use_kd_tree = 0;
opts.initial_K = K;
opts.do_greedy = 0;
opts.do_split = 0;
opts.do_merge = 0;
opts.do_sort = 0;

% Local Variables: ***
% mode: matlab ***
% End: ***


%
% Test to make sure the acceptance ratios are correct for the MH moves.
% This compares the ratios from the relevant conditional distributions
% to the overall generative score
%
% If this does not throw an assert, then it should be working.
%
ntry = 1;
verbose = true;
debug = true;
ps = defaultps;
load(ps.libname,'lib');
for t=1:ntry
    fprintf(1,'TRY %d\n',t);
    motor_program = generate_all_rel_character(lib);
    M = motor_program();
    mcmc_all(M,lib,1,'verbose','debug','type','token','relation');
end


function [] = getStateFiles(model_3d,statesDir,goodInds)

globals;
PASCAL_DIR = PASCAL_DIR;
if(nargin<3)
    goodInds = true(length(model_3d.c),1);
end
params = get_params();
viewClusters = cluster_views(model_3d,find(goodInds(:)),params.vis.numRotClusters,0);
%pBar =  TimedProgressBar( length(model_3d.c), 30, ...
%    'Generating state files ', ', completed ', 'Generated state files in ' );

parfor instance = 1:length(model_3d.c)

    if(~goodInds(instance))
        continue;
    end
    %% Read image
    if(strcmp(model_3d.voc_image_id{instance}(end-2:end),'jpg')~=0)
        fname = [PASCAL_DIR model_3d.voc_image_id{instance}];
    else
        fname = [PASCAL_DIR model_3d.voc_image_id{instance} '.jpg'];
    end
    im = imread(fname);

    %% Get Segmentation from pascal annotations
     %disp(['Instance ' num2str(instance)]);
     if(isfield(model_3d,'voc_rec_id'))
         voc_id = [model_3d.voc_image_id{instance} '_' num2str(model_3d.voc_rec_id(instance))];
     else
         voc_id = [model_3d.voc_image_id{instance} '_1'];
     end
    if(isfield(model_3d,'flip'))
        flip = model_3d.flip(instance);
    else
        flip = 0;
    end

    if(flip)
        im(:,:,1) = fliplr(im(:,:,1));im(:,:,2) = fliplr(im(:,:,2));im(:,:,3) = fliplr(im(:,:,3));
        voc_id = ['flip_' voc_id];
    end

    segs = model_3d.seg;
    if(iscell(segs))
        mask = segs{instance};
    else
        mask = roipoly(im,segs.poly_x{instance},segs.poly_y{instance});
    end

    [~,occlusionIDX] = bwdist(mask);
    %mask = roipoly(im,segs.poly_x{instance}{1},segs.poly_y{instance}{1});

    %% Prepare data for instance from model structure
    bbox = model_3d.bbox(instance,:); % Used this for bbox scaling!
    % Keep all the information in bbox while scaling
    bbox = [floor(bbox(1:2)) ceil(bbox(3:4))];
    sc = max(bbox(3),bbox(4))/model_3d.params.nrsfm.norm_dim;
    nImages = size(model_3d.points3,1)/3;
    tr = bbox(1,1:2)';
    vis_points = [model_3d.points3(instance,:);model_3d.points3(nImages+instance,:);...
        model_3d.points3(2*nImages+instance,:)];
    vis_points = sc*vis_points;
    vis_points(1:2,:) = vis_points(1:2,:)+repmat(tr,[1,size(model_3d.points3,2)]);
    %vis_points(3,:) = -vis_points(3,:);

    %% visualization

    %subplot(2,2,1), imagesc(im); rectangle('Position',bbox,'EdgeColor','r','LineWidth',1);axis equal;
    %hold on;plot(vis_points(1,:),vis_points(2,:),'r.','MarkerSize',20);
    %hold on; trimesh(f',vis_points(1,:),vis_points(2,:),'LineWidth',3);axis equal;
    %subplot(2,2,2), imagesc(dmap);colormap('jet');axis equal;
    %hold on; trimesh(f',vis_points(1,:),vis_points(2,:),'LineWidth',3);axis equal;
    %subplot(2,2,3), imagesc(mask);colormap('gray');axis equal;
    %subplot(2,2,4),trimesh(f,vis_points(1,:),vis_points(2,:));axis equal;
    %pause();close all;

    %% Setup state file output
    state=struct;
    %state.dmapCoarse = dmap;
    state.mask = mask;
    state.gtmask= mask;
    state.im=im;
    state.voc_id = voc_id;
    state.kps = vis_points;
    state.bbox = bbox;
    %state.cameraPos = cameraPos;
    %state.cameraF = cameraF;
    state.cameraRot = model_3d.rots{instance};
    state.cameraScale = model_3d.c(instance)*sc;
    state.def_weights = model_3d.def_weights(instance,:);
    state.translation = mean(state.kps(1:2,:),2);

    state.transform3d = giveTransformFunc3d(state.cameraRot,state.cameraScale,state.translation);
    state.invtransform3d = giveInvTransformFunc3d(state.cameraRot,state.cameraScale,state.translation);
    state.bdry = getBoundary(state.mask);
    state.occlusionIDX = occlusionIDX;
    state.viewClusters = viewClusters;
    state.globalID = instance;
    savefunc(fullfile(statesDir, [voc_id '.mat']), state);
    %pBar.progress();
end
%pBar.stop();
end

function savefunc(fname,state)
save(fname,'state');
end

function tfun3d = giveTransformFunc3d(R,c,tr)

function S3d = tf(S)
S3d = c*R*S';
tr3 = [tr;zeros(1,size(tr,2))];
S3d = bsxfun(@plus,S3d,tr3);
S3d = S3d';
end

tfun3d = @tf;
end

function tfun3d = giveInvTransformFunc3d(R,c,tr)

function S3d = invtf(S)
tr3 = [tr' zeros(size(tr,2),1)];
S3d = bsxfun(@minus,S,tr3);
S3d = (S3d*R)/c;
end

tfun3d = @invtf;
end

function bdry = getBoundary(mask)
f = [0 1 0;1 0 1; 0 1 0];
[I,J] = find(mask.*(conv2(double(mask),f,'same')<4));
bdry = [J,I];
end


%Function to place dose into the running CERR plan.
%Just edit the strings below.
%JOD.
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
% without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% See the GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with CERR.  If not, see <http://www.gnu.org/licenses/>.

% [CTUniform3D, CTUniformInfoS] = getUniformizedCTScan;
function planC = addNewDose(dose3D, planC)

register = 'UniformCT';  %Currently only option supported.  Dose has the same shape as the uniformized CT scan.
doseError = [];
fractionGroupID = 'CERR test';
doseEdition = 'CERR test';
description = 'Test PB distribution.'
overWrite = 'no';  %Overwrite the last CERR dose?
dose2CERR(dose3D,doseError,fractionGroupID,doseEdition,description,register,[],overWrite)


function planC = copyStrToScan_meshBased(structNum,scanNum,planC)
%function planC = copyStrToScan_meshBased(structNum,scanNum,planC)
%
%This function derives a new structure from structNum which is associated
%to scanNum. The naming convention for this new structure is
%[structName assoc scanNum]. If structNum is already associated to scanNum,
%the unchanged planC is returned back.
%
%APA, 11/13/07
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
% without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% See the GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with CERR.  If not, see <http://www.gnu.org/licenses/>.

global stateS

if ~exist('planC')
    global planC
end

indexS = planC{end};

%return if structNum is already associated to scanNum
assocScanNum = getAssociatedScan(planC{indexS.structures}(structNum).assocScanUID);
if assocScanNum == scanNum
    warning(['Structure Number ',num2str(structNum),' is already assocoated with scan ',num2str(scanNum)])
    return;
end

%set Matlab path to directory containing the Mesh-library
currDir = cd;
if ispc
    meshDir = fileparts(which('libMeshContour.dll'));
    cd(meshDir);
    loadlibrary('libMeshContour','MeshContour.h');
elseif isunix
    meshDir = fileparts(which('libMeshContour.so'));
    cd(meshDir);
    loadlibrary('libMeshContour.so','MeshContour.h');
end

%Create Mesh-representation if it does not exist
clearMeshFlag = 0;
smoothIter = 10;

if ~isfield(planC{indexS.structures}(structNum),'meshRep') || (isfield(planC{indexS.structures}(structNum),'meshRep') && ~isempty(planC{indexS.structures}(structNum).meshRep) && planC{indexS.structures}(structNum).meshRep == 0)  || (isfield(planC{indexS.structures}(structNum),'meshRep') && isempty(planC{indexS.structures}(structNum).meshRep))

    assocScan = getStructureAssociatedScan(structNum,planC);
    [xVals, yVals, zVals] = getScanXYZVals(planC{indexS.scan}(assocScan));
    structUID   = planC{indexS.structures}(structNum).strUID;
    [rasterSegments, planC, isError]    = getRasterSegments(structNum,planC);
    [mask3M, uniqueSlices] = rasterToMask(rasterSegments, assocScan);
    mask3M = permute(mask3M,[2 1 3]);
    %Handle structures defined on single CT slice
    if size(mask3M,3)==1
        if uniqueSlices==1
            mask3M(:,:,2) = zeros(size(mask3M));
            uniqueSlices = [uniqueSlices uniqueSlices+1];
        elseif uniqueSlices==length(zVals)
            mask3M(:,:,2) = zeros(size(mask3M));
            uniqueSlices = [uniqueSlices uniqueSlices-1];
        else
            mask3M(:,:,2) = zeros(size(mask3M));
            uniqueSlices = [uniqueSlices uniqueSlices+1];
        end
    end
    calllib('libMeshContour','loadVolumeAndGenerateSurface',structUID,xVals,yVals,zVals(uniqueSlices), double(mask3M),0.5, uint16(smoothIter))
    %Store mesh under planC
    planC{indexS.structures}(structNum).meshS = calllib('libMeshContour','getSurface',structUID);
    clearMeshFlag = 1;
end

%Get transformation matrix
if ~isfield(planC{indexS.scan}(scanNum),'transM') | isempty(planC{indexS.scan}(scanNum).transM)
    transMnew = eye(4);
else
    transMnew = planC{indexS.scan}(scanNum).transM;
end
if ~isfield(planC{indexS.scan}(assocScanNum),'transM') | isempty(planC{indexS.scan}(assocScanNum).transM)
    transMold = eye(4);
else
    transMold = planC{indexS.scan}(assocScanNum).transM;
end
transM = inv(transMnew)*transMold;

%Get z-coordinates of scan
[jnk1,jnk2,scanZv] = getScanXYZVals(planC{indexS.scan}(scanNum));
for i = 1:length(scanZv)
    coord = scanZv(i);
    pointOnPlane = [0 0 coord] - transM(1:3,4)';
    planeNormal = (inv(transM(1:3,1:3))*[0 0 1]')';
    pointOnPlane = (inv(transM(1:3,1:3))*pointOnPlane')';
    structUID   = planC{indexS.structures}(structNum).strUID;
    contourS    = calllib('libMeshContour','getContours',structUID,single(pointOnPlane),single(planeNormal),single([0 1 0]),single([1 0 0]));
    if ~isempty(contourS) && length(length(contourS.segments)) > 0
        for segNum = 1:length(contourS.segments)
            pointsM = applyTransM(transM,contourS.segments(segNum).points);
            contour(i).segments(segNum).points(:,1) = pointsM(:,1);
            contour(i).segments(segNum).points(:,2) = pointsM(:,2);
            contour(i).segments(segNum).points(:,3) = coord*pointsM(:,1).^0;
        end
    else
        contour(i).segments(1).points = [];
    end
end

%Clear Surface Mesh
unloadlibrary('libMeshContour')
if clearMeshFlag
    planC{indexS.structures}(structNum).meshRep = 0;
    planC{indexS.structures}(structNum).meshS = [];
end

%Change directory back
cd(currDir)

strname = [planC{indexS.structures}(structNum).structureName,' asoc ',num2str(scanNum)];

newstr = newCERRStructure(scanNum);
newstr.contour = contour;
newstr.structureName = strname;
newstr.associatedScan = scanNum;
newstr.assocScanUID = planC{indexS.scan}(scanNum).scanUID;
newstr.meshRep = 0;
numStructs = length(planC{indexS.structures});

%Append new structure to planC.
planC{indexS.structures} = dissimilarInsert(planC{indexS.structures}, newstr, numStructs+1, []);

%Create Raster Segments
planC = getRasterSegs(planC, numStructs+1);

%Update uniformized data.
[jnk, relStructNum] = getStructureAssociatedScan(numStructs+1,planC);
if relStructNum==1
    planC = setUniformizedData(planC);
else
    planC = updateStructureMatrices(planC, numStructs+1);
end

if isfield(stateS,'handle') && ishandle(stateS.handle.CERRSliceViewer)
    stateS.structsChanged = 1;
    CERRRefresh
end

return;


function asa226_test ( )

%*****************************************************************************80
%
%% ASA226_TEST tests ASA226.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 February 2003
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'ASA226_TEST\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Test the ASA226 library.\n' );

  asa226_test01 ( );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'ASA226_TEST\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


function fix_lines(fname, fname2)
%FIX_LINES  Improves the line style of eps files generated by print
%
% Examples:
%   fix_lines fname
%   fix_lines fname fname2
%
% This function improves the style of lines in eps files generated by
% MATLAB's print function, making them more similar to those seen on
% screen. Grid lines are also changed from a dashed style to a dotted
% style, for greater differentiation from dashed lines.
%
% The function also places embedded fonts after the postscript header, in
% versions of MATLAB which place the fonts first (R2006b and earlier), in
% order to allow programs such as Ghostscript to find the bounding box
% information.
%
% IN:
%   fname - Name or path of source eps file.
%   fname2 - Name or path of destination eps file. Default: same as fname.

% Copyright: (C) Oliver Woodford, 2008-2010

% The idea of editing the EPS file to change line styles comes from Jiro
% Doke's FIXPSLINESTYLE (fex id: 17928)
% The idea of changing dash length with line width came from comments on
% fex id: 5743, but the implementation is mine :)

% Thank you to Sylvain Favrot for bringing the embedded font/bounding box
% interaction in older versions of MATLAB to my attention.
% Thank you to D Ko for bringing an error with eps files with tiff previews
% to my attention.
% Thank you to Laurence K for suggesting the check to see if the file was
% opened.

% Read in the file
fh = fopen(fname, 'r');
if fh == -1
    error('File %s not found.', fname);
end
try
    fstrm = fread(fh, '*char')';
catch ex
    fclose(fh);
    rethrow(ex);
end
fclose(fh);

% Move any embedded fonts after the postscript header
if strcmp(fstrm(1:15), '%!PS-AdobeFont-')
    % Find the start and end of the header
    ind = regexp(fstrm, '[\n\r]%!PS-Adobe-');
    [ind2 ind2] = regexp(fstrm, '[\n\r]%%EndComments[\n\r]+');
    % Put the header first
    if ~isempty(ind) && ~isempty(ind2) && ind(1) < ind2(1)
        fstrm = fstrm([ind(1)+1:ind2(1) 1:ind(1) ind2(1)+1:end]);
    end
end

% Make sure all line width commands come before the line style definitions,
% so that dash lengths can be based on the correct widths
% Find all line style sections
ind = [regexp(fstrm, '[\n\r]SO[\n\r]'),... % This needs to be here even though it doesn't have dots/dashes!
       regexp(fstrm, '[\n\r]DO[\n\r]'),...
       regexp(fstrm, '[\n\r]DA[\n\r]'),...
       regexp(fstrm, '[\n\r]DD[\n\r]')];
ind = sort(ind);
% Find line width commands
[ind2 ind3] = regexp(fstrm, '[\n\r]\d* w[\n\r]');
% Go through each line style section and swap with any line width commands
% near by
b = 1;
m = numel(ind);
n = numel(ind2);
for a = 1:m
    % Go forwards width commands until we pass the current line style
    while b <= n && ind2(b) < ind(a)
        b = b + 1;
    end
    if b > n
        % No more width commands
        break;
    end
    % Check we haven't gone past another line style (including SO!)
    if a < m && ind2(b) > ind(a+1)
        continue;
    end
    % Are the commands close enough to be confident we can swap them?
    if (ind2(b) - ind(a)) > 8
        continue;
    end
    % Move the line style command below the line width command
    fstrm(ind(a)+1:ind3(b)) = [fstrm(ind(a)+4:ind3(b)) fstrm(ind(a)+1:ind(a)+3)];
    b = b + 1;
end

% Find any grid line definitions and change to GR format
% Find the DO sections again as they may have moved
ind = int32(regexp(fstrm, '[\n\r]DO[\n\r]'));
if ~isempty(ind)
    % Find all occurrences of what are believed to be axes and grid lines
    ind2 = int32(regexp(fstrm, '[\n\r] *\d* *\d* *mt *\d* *\d* *L[\n\r]'));
    if ~isempty(ind2)
        % Now see which DO sections come just before axes and grid lines
        ind2 = repmat(ind2', [1 numel(ind)]) - repmat(ind, [numel(ind2) 1]);
        ind2 = any(ind2 > 0 & ind2 < 12); % 12 chars seems about right
        ind = ind(ind2);
        % Change any regions we believe to be grid lines to GR
        fstrm(ind+1) = 'G';
        fstrm(ind+2) = 'R';
    end
end

% Isolate line style definition section
first_sec = strfind(fstrm, '% line types:');
[second_sec remaining] = strtok(fstrm(first_sec+1:end), '/');
[remaining remaining] = strtok(remaining, '%');

% Define the new styles, including the new GR format
% Dot and dash lengths have two parts: a constant amount plus a line width
% variable amount. The constant amount comes after dpi2point, and the
% variable amount comes after currentlinewidth. If you want to change
% dot/dash lengths for a one particular line style only, edit the numbers
% in the /DO (dotted lines), /DA (dashed lines), /DD (dot dash lines) and
% /GR (grid lines) lines for the style you want to change.
new_style = {'/dom { dpi2point 1 currentlinewidth 0.08 mul add mul mul } bdef',... % Dot length macro based on line width
             '/dam { dpi2point 2 currentlinewidth 0.04 mul add mul mul } bdef',... % Dash length macro based on line width
             '/SO { [] 0 setdash 0 setlinecap } bdef',... % Solid lines
             '/DO { [1 dom 1.2 dom] 0 setdash 0 setlinecap } bdef',... % Dotted lines
             '/DA { [4 dam 1.5 dam] 0 setdash 0 setlinecap } bdef',... % Dashed lines
             '/DD { [1 dom 1.2 dom 4 dam 1.2 dom] 0 setdash 0 setlinecap } bdef',... % Dot dash lines
             '/GR { [0 dpi2point mul 4 dpi2point mul] 0 setdash 1 setlinecap } bdef'}; % Grid lines - dot spacing remains constant

if nargin < 2
    % Overwrite the input file
    fname2 = fname;
end

% Save the file with the section replaced
fh = fopen(fname2, 'w');
if fh == -1
    error('Unable to open %s for writing.', fname2);
end
try
    fwrite(fh, fstrm(1:first_sec), 'char*1');
    fwrite(fh, second_sec, 'char*1');
    fprintf(fh, '%s\r', new_style{:});
    fwrite(fh, remaining, 'char*1');
catch ex
    fclose(fh);
    rethrow(ex);
end
fclose(fh);
return


function seq = report_tracking_result(seq, result)

if strcmpi(seq.format, 'otb')
    seq.rect_position(seq.frame,:) = round([result.center_pos([2,1]) - (result.target_size([2,1]) - 1)/2, result.target_size([2,1])]);
elseif strcmpi(seq.format, 'vot')
    if seq.frame > 1
        bb_scale = 1;
        sz = result.target_size / bb_scale;
        tl = result.center_pos - (sz - 1)/2;
        br = result.center_pos + (sz - 1)/2;
        x1 = tl(2); y1 = tl(1);
        x2 = br(2); y2 = br(1);
        result_box = round(double([x1 y1 x2 y1 x2 y2 x1 y2]));
        if any(isnan(result_box) | isinf(result_box))
            error('Illegal values in the result.')
        end
%         if any(result_box < 0)
%             error('Negative values')
%         end
        seq.handle = seq.handle.report(seq.handle, result_box);
    end
else
    error('Uknown sequence format');
end


function option_num = p00_option_num ( problem )

%*****************************************************************************80
%
%% P00_OPTION_NUM returns the number of options available for a problem.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 October 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer PROBLEM, the problem index.
%
%    Output, integer OPTION_NUM, the number of options available for
%    this problem.  OPTION_NUM is always at least 1.
%
  if (  problem == 1 )
    option_num = p01_option_num ( );
  elseif ( problem == 2 )
    option_num = p02_option_num ( );
  elseif ( problem == 3 )
    option_num = p03_option_num ( );
  elseif ( problem == 4 )
    option_num = p04_option_num ( );
  elseif ( problem == 5 )
    option_num = p05_option_num ( );
  elseif ( problem == 6 )
    option_num = p06_option_num ( );
  elseif ( problem == 7 )
    option_num = p07_option_num ( );
  elseif ( problem == 8 )
    option_num = p08_option_num ( );
  elseif ( problem == 9 )
    option_num = p09_option_num ( );
  elseif ( problem == 10 )
    option_num = p10_option_num ( );
  elseif ( problem == 11 )
    option_num = p11_option_num ( );
  elseif ( problem == 12 )
    option_num = p12_option_num ( );
  elseif ( problem == 13 )
    option_num = p13_option_num ( );
  elseif ( problem == 14 )
    option_num = p14_option_num ( );
  elseif ( problem == 15 )
    option_num = p15_option_num ( );
  elseif ( problem == 16 )
    option_num = p16_option_num ( );
  elseif ( problem == 17 )
    option_num = p17_option_num ( );
  elseif ( problem == 18 )
    option_num = p18_option_num ( );
  elseif ( problem == 19 )
    option_num = p19_option_num ( );
  elseif ( problem == 20 )
    option_num = p20_option_num ( );
  else
    fprintf ( 1, '\n' );
    fprintf ( 1, 'P00_OPTION_NUM - Fatal error!\n' );
    fprintf ( 1, '  Unrecognized problem index = %d\n', problem );
    error ( 'P00_OPTION_NUM - Fatal error!' );
  end

  return
end


function name = p19_name ( )

%*****************************************************************************80
%
%% P19_NAME returns the name of problem 19.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    18 March 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, string NAME, the name of the problem.
%
  name = 'Sqrt-Prod';

  return
end


function res = imdirfilter(img, varargin)
%IMDIRFILTER Apply and combine several directional filters
%
%   Deprecated, use "imDirectionlFilter" instead.
%
%   ---------
%   author : David Legland
%   INRA - TPV URPOI - BIA IMASTE
%   created the 16/02/2004.
%

%   HISTORY
%   17/02/2004 debug, added some doc, manage different types of images
%   26/02/2007 cleanup code
%   03/10/2007 update doc
%   19/08/2009 fix bug in parsing arguments
%   18/06/2010 fix initialization for 'min' operator, update doc
%   02/12/2011 deprecated and replace by imDirectionalFilter

warning('imael:deprecated', ...
    'function "imdirfilter" has been replaced by "imDirectionalFilter"');

res = imDirectionalFilter(img, varargin{:});


function gamsWrite(prob,filename)
%gamsWrite  Write a GAMS Model from MATLAB data
%
% gamsWrite(prob,filename) writes the OPTI problem to a GAMS model (.gms)
% and optionally a GDX file if SCIP is not used.
%
% You may specify a full path to the file, or if you specify a filename
% only, it will be written to the current directory.

%   Copyright (C) 2013 Jonathan Currie (IPL)

ext = 'gms';

%Quick Checks
if(~ischar(filename))
    error('Filename must be a char array!');
end
if(~isempty(prob.sdcone))
    error('Semidefinite problems cannot be written by this interface');
end
% Make sure we have file extension for GAMS model
if(isempty(strfind(lower(filename),['.' ext])))
    gdxname = filename;
    filename = [filename '.' ext];
else
    % Remove file extension for GDX file
    ind = strfind(lower(filename),['.' ext]);
    gdxname = filename(1:ind-1);
end

% Check for full filepath
if(isempty(strfind(filename,':')))
    filename = [cd filesep filename];
    gdxname = [cd filesep gdxname];
end

%If we have SCIP installed, use that (much easier, and does nonlinear models)
if(optiSolver('scip',0))
    opts = optiset('solver','scip','warnings','none','display','off','solverOpts',scipset('gamsfile',filename));
    if(isstruct(prob.int) && isfield(prob.int,'str'))
        prob.int = prob.int.str;
    end
    if(isempty(prob.x0) || all(isnan(prob.x0))), prob.x0 = randn(prob.sizes.ndec,1); end
    Opt = opti(prob,opts);
    try
        solve(Opt);
    catch ME
        if(strcmpi(ME.identifier,'OPTI:SCIPVAR'))
            throwAsCaller(MException('OPTI:SCIPVAR','AN ERROR OCCURED WHILE PRE-PROCESSING YOUR MATLAB FUNCTION(S) - PLEASE EXAMINE THE SCIP ERROR BELOW:\n\n%s',ME.message));
        else
            throw(ME);
        end
    end
    return;
end

%Check not nonlinear
if(~isempty(prob.fun) && isa(prob.fun,'function_handle'))
    error('The OPTI GAMS Writer only works for problems up to MIQCQP complexity.\n\nFor general nonlinear problems you must have %s installed to write nonlinear GAMS problems','SCIP');
end

%Check GAMS routines are available
if(~exist(['rgdx.' mexext],'file') || ~exist(['wgdx.' mexext],'file'))
    error('Could not find the required GAMS routines on your PC [wgdx,rgdx]!\n\n%s',...
          'Please download a current GAMS distribution from "http://www.gams.com/download/", then add the GAMS install folder to the MATLAB path.');
end

%Check for SOS constraints (not yet implemented)
if(~isempty(prob.sos))
    optiwarn('OPTI:GamsWriteSOS','SOS constraints are not currently supported by this interface, so they will be skipped!');
end

%Determine number of decision variables
if(isfield(prob,'sizes'))
    ndec = prob.sizes.ndec;
elseif(~isempty(prob.f))
    ndec = numel(prob.f);
elseif(~isempty(prob.x0))
    ndec = numel(prob.x0);
elseif(~isempty(prob.H))
    ndec = size(prob.H,1);
else
    error('Could not determine the number of decision variables!');
end

%Convert linear constraints to row format
if(~isempty(prob.b) || ~isempty(prob.beq))
    [prob.A,prob.rl,prob.ru] = gen2row(prob.A,prob.b,prob.Aeq,prob.beq);
end

%Convert integer constraints to string
if(~isempty(prob.int) && ~isstruct(prob.int))
    if(ischar(prob.int))
        str = prob.int;
        prob.int = struct('str',str);
    elseif(isnumeric(prob.int))
        str = repmat('C',1,ndec);
        str(prob.int) = 'I';
        prob.int = struct('str',str);
    else
        error('Unknown integer format');
    end
elseif(isempty(prob.int))
    prob.int.str = [];
end
prob.int.str = upper(prob.int.str);
nint = sum(prob.int.str == 'I');
nbin = sum(prob.int.str == 'B');

%Starting writing GAMS Model File
fid = fopen(filename,'w');
if(fid < 0), error('Error creating GAMS Model: %s',filename); end

name = regexprep(prob.Name,' ','_');

fprintf(fid,'* OPTI Generated GAMS Model (%s)\n',datestr(now));
fprintf(fid,'*   Model Name             : %s\n',name);
if(isfield(prob,'type') && ~isempty(prob.type))
    fprintf(fid,'*   Model Classification   : %s\n',prob.type);
end
fprintf(fid,'*   Variables              : %d (%d Integer, %d Binary)\n',ndec,nint,nbin);
if(~isempty(prob.rl)),  fprintf(fid,'*   Linear Constraints     : %d\n',numel(prob.rl)); end
if(~isempty(prob.qrl)), fprintf(fid,'*   Quadratic Constraints  : %d\n',numel(prob.qrl)); end
if(~isempty(prob.cl)),  fprintf(fid,'*   Nonlinear Constraints  : %d\n',numel(prob.cl)); end
fprintf(fid,'\n');

try
    model = 'lp';
    %Check for integer and binary constraints
    if(~all(prob.int.str == 'C'))
        int = struct('name','int','type','set','dim',1,'uels',{{find(prob.int.str ~= 'C')}},'form','full','ts','integer and binary indices');
        if(any(prob.int.str == 'B'))
            %Force binary bounds
            ind = (prob.int.str == 'B')';
            if(isempty(prob.lb)), prob.lb = -Inf(ndec,1); end
            if(isempty(prob.ub)), prob.ub = Inf(ndec,1); end
            %Set bin indicies which are infinite or bounds > 1 or < 0 to 1/0
            prob.lb((isinf(prob.lb) | (prob.lb < 0)) & ind) = 0;
            prob.ub((isinf(prob.ub) | (prob.ub > 1)) & ind) = 1;
        end
    else
        int = [];
    end
    %Check for bounds
    if(~isempty(prob.lb))
        lb = struct('name','lb','type','parameter','dim',1,'val',full(prob.lb),'form','full','ts','decision variable lower bound');
    else
        lb = [];
    end
    if(~isempty(prob.ub))
        ub = struct('name','ub','type','parameter','dim',1,'val',full(prob.ub),'form','full','ts','decision variable upper bound');
    else
        ub = [];
    end
    %Check for initial guess
    if(~isempty(prob.x0) && all(~isnan(prob.x0)))
        x0 = struct('name','x0','type','parameter','dim',1,'val',full(prob.x0),'form','full','ts','decision variable initial guess');
    else
        x0 = [];
    end
    %Check for linear objective
    if(~isempty(prob.f) && isnumeric(prob.f))
        f = struct('name','f','type','parameter','dim',1,'val',full(prob.f),'form','full','ts','linear objective vector');
    else
        f = [];
    end
    %Check for quadratic objective
    if(~isempty(prob.H) && isnumeric(prob.H))
        %We require all elements of H, see if we have a saved copy before
        %triu/tril
        if(isfield(prob,'save') && isfield(prob.save,'H') && ~isempty(prob.save.H) && isnumeric(prob.save.H))
            H = prob.save.H;
        else
            H = prob.H;
        end
        [i,j,v] = find(sparse(H));
        H = struct('name','H','type','parameter','dim',2,'val',[i j v],'form','sparse','ts','quadratic objective matrix');
        model = 'qp';
    else
        H = [];
    end
    %Check for linear constraints
    if(~isempty(prob.A))
        [i,j,v] = find(sparse(prob.A));
        A = struct('name','A','type','parameter','dim',2,'val',[i j v],'form','sparse','ts','linear constraint matrix');
        rl = struct('name','rl','type','parameter','dim',1,'val',full(prob.rl),'form','full','ts','linear constraint lower bound');
        ru = struct('name','ru','type','parameter','dim',1,'val',full(prob.ru),'form','full','ts','linear constraint upper bound');
    else
        A = []; rl = []; ru = [];
    end
    %Check for quadratic constraints
    if(~isempty(prob.Q))
        %Concatenate each Q matrix into a 3D array
        if(iscell(prob.Q))
            i = []; j = []; k = []; v = [];
            for n = 1:length(prob.Q) %could preallocate...
                [I,J,V] = find(sparse(prob.Q{n}));
                i = [i;I]; %#ok<AGROW>
                j = [j;J]; %#ok<AGROW>
                k = [k;n*ones(size(I))]; %#ok<AGROW>
                v = [v;V]; %#ok<AGROW>
            end
        else
            [i,j,v] = find(sparse(prob.Q));
            k = ones(size(i));
        end
        Q = struct('name','Q','type','parameter','dim',3,'val',[i j k v],'form','sparse','ts','quadratic constraint matrix');
        [i,j,v] = find(sparse(prob.l));
        l = struct('name','l','type','parameter','dim',2,'val',[i j v],'form','sparse','ts','quadratic constraint linear matrix');
        qrl = struct('name','qrl','type','parameter','dim',1,'val',full(prob.qrl),'form','full','ts','quadratic constraint lower bound');
        qru = struct('name','qru','type','parameter','dim',1,'val',full(prob.qru),'form','full','ts','quadratic constraint upper bound');
        model = 'qcqp';
    else
        Q = []; l = []; qrl = []; qru = [];
    end

    %Write GAMS Data
    writeGDX(gdxname,H,f,lb,ub,x0,int,A,rl,ru,Q,l,qrl,qru);

    %Write set definitions
    fprintf(fid,'Sets\n');
    fprintf(fid,' n /1*%d/\n',ndec);
    if(~isempty(int)), fprintf(fid,' ni(n)\n'); end
    if(~isempty(prob.rl)), fprintf(fid,' mlin /1*%d/\n',numel(prob.rl)); end
    if(~isempty(prob.qrl)), fprintf(fid,' mquad /1*%d/\n',numel(prob.qrl)); end
    if(~isempty(prob.cl)), fprintf(fid,' mnlin /1*%d/\n',numel(prob.cl)); end
    fprintf(fid,';\n');

    %Alias for QP, QC
    if(~isempty(H)), fprintf(fid,'Alias (n,n1);\n\n'); end

    %Write parameter definitions
    fprintf(fid,'Parameters\n');
    if(~isempty(H)), fprintf(fid,' H(n,n1)\n'); end
    if(~isempty(f)), fprintf(fid,' f(n)\n'); end
    if(~isempty(lb) && ~isempty(ub))
        fprintf(fid,' lb(n), ub(n)\n');
    elseif(~isempty(lb))
        fprintf(fid,' lb(n)\n');
    elseif(~isempty(ub))
        fprintf(fid,' ub(n)\n');
    end
    if(~isempty(x0)), fprintf(fid,' x0(n)\n'); end
    if(~isempty(A)), fprintf(fid,' A(mlin,n), rl(mlin), ru(mlin)\n'); end
    if(~isempty(Q)), fprintf(fid,' Q(n,n1,mquad), l(n,mquad), qrl(mquad), qru(mquad)\n'); end
    fprintf(fid,';\n');

    %Enter Variables to Import
    fprintf(fid,'* Load Parameters from GDX\n');
    fprintf(fid,'$gdxin %s.gdx\n',gdxname);
    if(~isempty(H)), fprintf(fid,'$load H\n'); end
    if(~isempty(f)), fprintf(fid,'$load f\n'); end
    if(~isempty(lb) && ~isempty(ub))
        fprintf(fid,'$load lb,ub\n');
    elseif(~isempty(lb))
        fprintf(fid,'$load lb\n');
    elseif(~isempty(ub))
        fprintf(fid,'$load ub\n');
    end
    if(~isempty(int)), fprintf(fid,'$load ni = int\n'); end
    if(~isempty(x0)), fprintf(fid,'$load x0\n'); end
    if(~isempty(A)), fprintf(fid,'$load A,rl,ru\n'); end
    if(~isempty(Q)), fprintf(fid,'$load Q,l,qrl,qru\n'); end
    fprintf(fid,'$gdxin\n\n');

    %Complete GAMS file
    %Variable Definition
    fprintf(fid, 'Variables\n x(n)\n');
    fprintf(fid, ' obj;\n\n');

    %Integer and binary def
    if(~isempty(int))
        fprintf(fid,'Integer Variables\n x;\n');
        fprintf(fid,' x.prior(n) = inf;\n');
        fprintf(fid,' x.prior(ni) = 1;\n\n');
    end

    %Equations
    fprintf(fid, 'Equations\n');
    if(~isempty(A))
        fprintf(fid, ' linconLB(mlin)\n');
        fprintf(fid, ' linconUB(mlin)\n');
    end
    if(~isempty(Q))
        fprintf(fid, ' quadconLB(mquad)\n');
        fprintf(fid, ' quadconUB(mquad)\n');
    end
    fprintf(fid, ' cost;\n\n');

    %Objective
    fprintf(fid, '* Cost Function\n');
    switch(model)
        case 'lp'
            fprintf(fid, ' cost.. obj =e= sum(n, f(n)*x(n));\n\n');
        case {'qp','qcqp'}
            fprintf(fid, ' cost.. obj =e= 0.5*sum(n,x(n)*sum(n1,H(n,n1)*x(n1))) + sum(n,f(n)*x(n));\n\n');
        otherwise
            error('Problem type ''%s'' not yet supported',prob.type);
    end

    %Bounds
    if(~isempty(lb) || ~isempty(ub))
        fprintf(fid, '* Decision Variable Bounds\n');
        if(~isempty(lb)), fprintf(fid, ' x.lo(n) = lb(n);\n'); end
        if(~isempty(ub)), fprintf(fid, ' x.up(n) = ub(n);\n'); end
        fprintf(fid,'\n');
    end

    %Initial Guess
    if(~isempty(x0))
        fprintf(fid, '* Initial Solution Guess\n');
        fprintf(fid, ' x.l(n) = x0(n);\n\n');
    end

    %Linear Constraints
    if(~isempty(A))
        fprintf(fid,'* Linear Constraints\n');
        fprintf(fid,' linconLB(mlin).. rl(mlin) =l= sum(n, A(mlin,n)*x(n));\n');
        fprintf(fid,' linconUB(mlin).. sum(n, A(mlin,n)*x(n)) =l= ru(mlin);\n\n');
    end

    %Quadratic Constraints
    if(~isempty(Q))
        fprintf(fid,'* Quadratic Constraints\n');
        fprintf(fid,' quadconLB(mquad).. qrl(mquad) =l= sum(n,x(n)*sum(n1,Q(n,n1,mquad)*x(n1))) + sum(n,l(n,mquad)*x(n));\n');
        fprintf(fid,' quadconUB(mquad).. sum(n,x(n)*sum(n1,Q(n,n1,mquad)*x(n1))) + sum(n,l(n,mquad)*x(n)) =l= qru(mquad);\n\n');
    end

    %Write model declaration
    fprintf(fid,'\nModel %s / all /;\n\n',name);

    %Determine which GAMS solver type to use
    switch(model)
        case 'lp'
            if(isempty(int))
                fprintf(fid,'Solve %s using %s minimizing obj;\n',name,'LP');
            else
                fprintf(fid,'Solve %s using %s minimizing obj;\n',name,'MIP');
            end
        case {'qp','qcqp'}
            if(isempty(int))
                fprintf(fid,'Solve %s using %s minimizing obj;\n',name,'QCP');
            else
                fprintf(fid,'Solve %s using %s minimizing obj;\n',name,'MIQCP');
            end
    end

catch ME
    fclose(fid);
    rethrow(ME);
end

fclose(fid);

function writeGDX(name,H,f,lb,ub,x0,int,A,rl,ru,Q,l,qrl,qru)

args = {};
if(~isempty(H)),    args = [args H]; end
if(~isempty(f)),    args = [args f]; end
if(~isempty(lb)),   args = [args lb]; end
if(~isempty(ub)),   args = [args ub]; end
if(~isempty(x0)),   args = [args x0]; end
if(~isempty(int)),  args = [args int]; end
if(~isempty(A)),    args = [args A]; end
if(~isempty(rl)),   args = [args rl]; end
if(~isempty(ru)),   args = [args ru]; end
if(~isempty(Q)),    args = [args Q]; end
if(~isempty(l)),    args = [args l]; end
if(~isempty(qrl)),  args = [args qrl]; end
if(~isempty(qru)),  args = [args qru]; end

if(~isempty(args))
    wgdx(name,args{:});
end


function rgb = ind2color(ind,varargin)
% convert ind to rgb values

cmap = getMTEXpref('colors');

if check_option(varargin,'ordered')
  order = [1,6,19,12,20,22,3,11,18,16,...
    23,8,7,2,14,15,9,5,21,4,24,13,10,17];

  iorder(order) = 1:24;

  cmap = cmap(order,:);

elseif nargin > 1 && isa(varargin{1},'double')

  cmap = varargin{1};

end

isInd = ind > 0 & ~isnan(ind);
rgb = nan(numel(ind),3);

rgb(isInd,:) = cmap(ind(isInd),:);