function layout=cosmo_meeg_read_layout(fn)
% Read FieldTrip layout
%
% layout=cosmo_meeg_read_layout(fn)
%
% Inputs:
% fn Filename of layout file, or a string containing the
% layout. In the latter case fn must contain at least
% one newline ('\n') character.
% A layout file is a text file with one line per
% sensor, with each line containing the following
% data separated by white-space:
% 1) sensor number (integer)
% 2) horizontal position (float)
% 3) vertical position (float)
% 4) width (float)
% 5) height (float)
% 6) label (string)
%
% Output:
% layout struct with fields containing data for N sensors:
% .pos Nx2 matrix with x and y position
% .width Nx1 vector
% .height Nx1 vector
% .label Nx1 cell string with channel labels
%
% Notes:
% - whitespace is trimmed from the labels
% - the sensor number is not used; the order of the sensors in layout is
% the same as in the layout file
%
% # For CoSMoMVPA's copyright information and license terms, #
% # see the COPYING file distributed with CoSMoMVPA. #
check_layout_input(fn)
if string_contains_newline(fn)
lay_string=fn;
fn_descr=@()sprintf('input:\n''%s''',lay_string);
else
lay_string=read_lay_string_from_file(fn);
fn_descr=@()sprintf('file %s',fn);
end
layout=parse_layout(lay_string, fn_descr);
function lay_string=read_lay_string_from_file(fn)
if ~exist(fn,'file')
error('layout file %s does ont exist', fn);
end
% read FT layout (.lay) file
fid=fopen(fn);
file_closer=onCleanup(@()fclose(fid));
lay_string=fread(fid,inf,'char=>char')';
function check_layout_input(fn)
if ~ischar(fn)
error('first argument must be string, found %s', class(fn));
end
function tf=string_contains_newline(fn)
tf=any(fn==sprintf('\n'));
function layout=parse_layout(lay_string, fn_descr)
% pattern to match is integer, then 4 numeric values followed by a
% string that can contain whitespaces and plus characters, followed by
% newline
integer='(\d+)';
float='([\d\.-]+)';
space='\s+';
channel_label='([\w \t\r\f\v\+\-]+)';
single_newline='\n';
pat=[integer, space, ...
float, space, ...
float, space, ...
float, space, ...
float, space, ...
channel_label, single_newline];
matches=regexp(sprintf('%s\n',lay_string),pat,'tokens');
if isempty(matches)
error('No valid layout definition found in %s', fn_descr());
end
% convert to (nchannel x 6) matrix
layout_matrix=cat(1,matches{:});
% convert values in first five columns to numeric
num_values_cell=layout_matrix(:,1:5)';
str_values=sprintf('%s %s %s %s %s; ', num_values_cell{:});
num_values=str2num(str_values);
% store layout information (omit channel number in first column)
layout.pos = num_values(:,2:3);
layout.width = num_values(:,4);
layout.height = num_values(:,5);
% trim whitespace around channel names
label=layout_matrix(:,6);
label=regexprep(label,'^\s*','');
label=regexprep(label,'\s*$','');
layout.label = label;