cm_eeg_readlocs_20140226.m 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. % readlocs() - read electrode location coordinates and other information from a file.
  2. % Several standard file formats are supported. Users may also specify
  3. % a custom column format. Defined format examples are given below
  4. % (see File Formats).
  5. % Usage:
  6. % >> eloc = readlocs( filename );
  7. % >> EEG.chanlocs = readlocs( filename, 'key', 'val', ... );
  8. % >> [eloc, labels, theta, radius, indices] = ...
  9. % readlocs( filename, 'key', 'val', ... );
  10. % Inputs:
  11. % filename - Name of the file containing the electrode locations
  12. % {default: 2-D polar coordinates} (see >> help topoplot )
  13. %
  14. % Optional inputs:
  15. % 'filetype' - ['loc'|'sph'|'sfp'|'xyz'|'asc'|'polhemus'|'besa'|'chanedit'|'custom']
  16. % Type of the file to read. By default the file type is determined
  17. % using the file extension (see below under File Formats),
  18. % 'loc' an EEGLAB 2-D polar coordinates channel locations file
  19. % Coordinates are theta and radius (see definitions below).
  20. % 'sph' Matlab spherical coordinates (Note: spherical
  21. % coordinates used by Matlab functions are different
  22. % from spherical coordinates used by BESA - see below).
  23. % 'sfp' EGI Cartesian coordinates (NOT Matlab Cartesian - see below).
  24. % 'xyz' Matlab/EEGLAB Cartesian coordinates (NOT EGI Cartesian).
  25. % z is toward nose; y is toward left ear; z is toward vertex
  26. % 'asc' Neuroscan polar coordinates.
  27. % 'polhemus' or 'polhemusx' - Polhemus electrode location file recorded
  28. % with 'X' on sensor pointing to subject (see below and readelp()).
  29. % 'polhemusy' - Polhemus electrode location file recorded with
  30. % 'Y' on sensor pointing to subject (see below and readelp()).
  31. % 'besa' BESA-'.elp' spherical coordinates. (Not MATLAB spherical -
  32. % see below).
  33. % 'chanedit' - EEGLAB channel location file created by pop_chanedit().
  34. % 'custom' - Ascii file with columns in user-defined 'format' (see below).
  35. % 'importmode' - ['eeglab'|'native'] for location files containing 3-D cartesian electrode
  36. % coordinates, import either in EEGLAB format (nose pointing toward +X).
  37. % This may not always be possible since EEGLAB might not be able to
  38. % determine the nose direction for scanned electrode files. 'native' import
  39. % original carthesian coordinates (user can then specify the position of
  40. % the nose when calling the topoplot() function; in EEGLAB the position
  41. % of the nose is stored in the EEG.chaninfo structure). {default 'eeglab'}
  42. % 'format' - [cell array] Format of a 'custom' channel location file (see above).
  43. % {default: if no file type is defined. The cell array contains
  44. % labels defining the meaning of each column of the input file.
  45. % 'channum' [positive integer] channel number.
  46. % 'labels' [string] channel name (no spaces).
  47. % 'theta' [real degrees] 2-D angle in polar coordinates.
  48. % positive => rotating from nose (0) toward left ear
  49. % 'radius' [real] radius for 2-D polar coords; 0.5 is the head
  50. % disk radius and limit for topoplot() plotting).
  51. % 'X' [real] Matlab-Cartesian X coordinate (to nose).
  52. % 'Y' [real] Matlab-Cartesian Y coordinate (to left ear).
  53. % 'Z' [real] Matlab-Cartesian Z coordinate (to vertex).
  54. % '-X','-Y','-Z' Matlab-Cartesian coordinates pointing opposite
  55. % to the above.
  56. % 'sph_theta' [real degrees] Matlab spherical horizontal angle.
  57. % positive => rotating from nose (0) toward left ear.
  58. % 'sph_phi' [real degrees] Matlab spherical elevation angle.
  59. % positive => rotating from horizontal (0) upwards.
  60. % 'sph_radius' [real] distance from head center (unused).
  61. % 'sph_phi_besa' [real degrees] BESA phi angle from vertical.
  62. % positive => rotating from vertex (0) towards right ear.
  63. % 'sph_theta_besa' [real degrees] BESA theta horiz/azimuthal angle.
  64. % positive => rotating from right ear (0) toward nose.
  65. % 'ignore' ignore column}.
  66. % The input file may also contain other channel information fields.
  67. % 'type' channel type: 'EEG', 'MEG', 'EMG', 'ECG', others ...
  68. % 'calib' [real near 1.0] channel calibration value.
  69. % 'gain' [real > 1] channel gain.
  70. % 'custom1' custom field #1.
  71. % 'custom2', 'custom3', 'custom4', etc. more custom fields
  72. % 'skiplines' - [integer] Number of header lines to skip (in 'custom' file types only).
  73. % Note: Characters on a line following '%' will be treated as comments.
  74. % 'readchans' - [integer array] indices of electrodes to read. {default: all}
  75. % 'center' - [(1,3) real array or 'auto'] center of xyz coordinates for conversion
  76. % to spherical or polar, Specify the center of the sphere here, or 'auto'.
  77. % This uses the center of the sphere that best fits all the electrode
  78. % locations read. {default: [0 0 0]}
  79. % Outputs:
  80. % eloc - structure containing the channel names and locations (if present).
  81. % It has three fields: 'eloc.labels', 'eloc.theta' and 'eloc.radius'
  82. % identical in meaning to the EEGLAB struct 'EEG.chanlocs'.
  83. % labels - cell array of strings giving the names of the electrodes. NOTE: Unlike the
  84. % three outputs below, includes labels of channels *without* location info.
  85. % theta - vector (in degrees) of polar angles of the electrode locations.
  86. % radius - vector of polar-coordinate radii (arc_lengths) of the electrode locations
  87. % indices - indices, k, of channels with non-empty 'locs(k).theta' coordinate
  88. %
  89. % File formats:
  90. % If 'filetype' is unspecified, the file extension determines its type.
  91. %
  92. % '.loc' or '.locs' or '.eloc':
  93. % polar coordinates. Notes: angles in degrees:
  94. % right ear is 90; left ear -90; head disk radius is 0.5.
  95. % Fields: N angle radius label
  96. % Sample: 1 -18 .511 Fp1
  97. % 2 18 .511 Fp2
  98. % 3 -90 .256 C3
  99. % 4 90 .256 C4
  100. % ...
  101. % Note: In previous releases, channel labels had to contain exactly
  102. % four characters (spaces replaced by '.'). This format still works,
  103. % though dots are no longer required.
  104. % '.sph':
  105. % Matlab spherical coordinates. Notes: theta is the azimuthal/horizontal angle
  106. % in deg.: 0 is toward nose, 90 rotated to left ear. Following this, performs
  107. % the elevation (phi). Angles in degrees.
  108. % Fields: N theta phi label
  109. % Sample: 1 18 -2 Fp1
  110. % 2 -18 -2 Fp2
  111. % 3 90 44 C3
  112. % 4 -90 44 C4
  113. % ...
  114. % '.elc':
  115. % Cartesian 3-D electrode coordinates scanned using the EETrak software.
  116. % See readeetraklocs().
  117. % '.elp':
  118. % Polhemus-.'elp' Cartesian coordinates. By default, an .elp extension is read
  119. % as PolhemusX-elp in which 'X' on the Polhemus sensor is pointed toward the
  120. % subject. Polhemus files are not in columnar format (see readelp()).
  121. % '.elp':
  122. % BESA-'.elp' spherical coordinates: Need to specify 'filetype','besa'.
  123. % The elevation angle (phi) is measured from the vertical axis. Positive
  124. % rotation is toward right ear. Next, perform azimuthal/horizontal rotation
  125. % (theta): 0 is toward right ear; 90 is toward nose, -90 toward occiput.
  126. % Angles are in degrees. If labels are absent or weights are given in
  127. % a last column, readlocs() adjusts for this. Default labels are E1, E2, ...
  128. % Fields: label phi theta
  129. % Sample: Fp1 -92 -72
  130. % Fp2 92 72
  131. % C3 -46 0
  132. % C4 46 0
  133. % ...
  134. % '.xyz':
  135. % Matlab/EEGLAB Cartesian coordinates. Here. x is towards the nose,
  136. % y is towards the left ear, and z towards the vertex. Note that the first
  137. % column (x) is -Y in a Matlab 3-D plot, the second column (y) is X in a
  138. % matlab 3-D plot, and the third column (z) is Z.
  139. % Fields: channum x y z label
  140. % Sample: 1 .950 .308 -.035 Fp1
  141. % 2 .950 -.308 -.035 Fp2
  142. % 3 0 .719 .695 C3
  143. % 4 0 -.719 .695 C4
  144. % ...
  145. % '.asc', '.dat':
  146. % Neuroscan-.'asc' or '.dat' Cartesian polar coordinates text file.
  147. % '.sfp':
  148. % BESA/EGI-xyz Cartesian coordinates. Notes: For EGI, x is toward right ear,
  149. % y is toward the nose, z is toward the vertex. EEGLAB converts EGI
  150. % Cartesian coordinates to Matlab/EEGLAB xyz coordinates.
  151. % Fields: label x y z
  152. % Sample: Fp1 -.308 .950 -.035
  153. % Fp2 .308 .950 -.035
  154. % C3 -.719 0 .695
  155. % C4 .719 0 .695
  156. % ...
  157. % '.ced':
  158. % ASCII file saved by pop_chanedit(). Contains multiple MATLAB/EEGLAB formats.
  159. % Cartesian coordinates are as in the 'xyz' format (above).
  160. % Fields: channum label theta radius x y z sph_theta sph_phi ...
  161. % Sample: 1 Fp1 -18 .511 .950 .308 -.035 18 -2 ...
  162. % 2 Fp2 18 .511 .950 -.308 -.035 -18 -2 ...
  163. % 3 C3 -90 .256 0 .719 .695 90 44 ...
  164. % 4 C4 90 .256 0 -.719 .695 -90 44 ...
  165. % ...
  166. % The last columns of the file may contain any other defined fields (gain,
  167. % calib, type, custom).
  168. %
  169. % Author: Arnaud Delorme, Salk Institute, 8 Dec 2002 (expanded from the previous EEG/ICA
  170. % toolbox function)
  171. %
  172. % See also: readelp(), writelocs(), topo2sph(), sph2topo(), sph2cart()
  173. % Copyright (C) Arnaud Delorme, CNL / Salk Institute, 28 Feb 2002
  174. %
  175. % This program is free software; you can redistribute it and/or modify
  176. % it under the terms of the GNU General Public License as published by
  177. % the Free Software Foundation; either version 2 of the License, or
  178. % (at your option) any later version.
  179. %
  180. % This program is distributed in the hope that it will be useful,
  181. % but WITHOUT ANY WARRANTY; without even the implied warranty of
  182. % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  183. % GNU General Public License for more details.
  184. %
  185. % You should have received a copy of the GNU General Public License
  186. % along with this program; if not, write to the Free Software
  187. % Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  188. function [eloc, labels, theta, radius, indices] = cm_eeg_readlocs_20140226( filename, varargin );
  189. if nargin < 1
  190. help readlocs;
  191. return;
  192. end;
  193. % NOTE: To add a new channel format:
  194. % ----------------------------------
  195. % 1) Add a new element to the structure 'chanformat' (see 'ADD NEW FORMATS HERE' below):
  196. % 2) Enter a format 'type' for the new file format,
  197. % 3) Enter a (short) 'typestring' description of the format
  198. % 4) Enter a longer format 'description' (possibly multiline, see ex. (1) below)
  199. % 5) Enter format file column labels in the 'importformat' field (see ex. (2) below)
  200. % 6) Enter the number of header lines to skip (if any) in the 'skipline' field
  201. % 7) Document the new channel format in the help message above.
  202. % 8) After testing, please send the new version of readloca.m to us
  203. % at eeglab@sccn.ucsd.edu with a sample locs file.
  204. % The 'chanformat' structure is also used (automatically) by the writelocs()
  205. % and pop_readlocs() functions. You do not need to edit these functions.
  206. chanformat(1).type = 'polhemus';
  207. chanformat(1).typestring = 'Polhemus native .elp file';
  208. chanformat(1).description = [ 'Polhemus native coordinate file containing scanned electrode positions. ' ...
  209. 'User must select the direction ' ...
  210. 'for the nose after importing the data file.' ];
  211. chanformat(1).importformat = 'readelp() function';
  212. % ---------------------------------------------------------------------------------------------------
  213. chanformat(2).type = 'besa';
  214. chanformat(2).typestring = 'BESA spherical .elp file';
  215. chanformat(2).description = [ 'BESA spherical coordinate file. Note that BESA spherical coordinates ' ...
  216. 'are different from Matlab spherical coordinates' ];
  217. chanformat(2).skipline = 0; % some BESA files do not have headers
  218. chanformat(2).importformat = { 'type' 'labels' 'sph_theta_besa' 'sph_phi_besa' 'sph_radius' };
  219. % ---------------------------------------------------------------------------------------------------
  220. chanformat(3).type = 'xyz';
  221. chanformat(3).typestring = 'Matlab .xyz file';
  222. chanformat(3).description = [ 'Standard 3-D cartesian coordinate files with electrode labels in ' ...
  223. 'the first column and X, Y, and Z coordinates in columns 2, 3, and 4' ];
  224. chanformat(3).importformat = { 'channum' '-Y' 'X' 'Z' 'labels'};
  225. % ---------------------------------------------------------------------------------------------------
  226. chanformat(4).type = 'sfp';
  227. chanformat(4).typestring = 'BESA or EGI 3-D cartesian .sfp file';
  228. chanformat(4).description = [ 'Standard BESA 3-D cartesian coordinate files with electrode labels in ' ...
  229. 'the first column and X, Y, and Z coordinates in columns 2, 3, and 4.' ...
  230. 'Coordinates are re-oriented to fit the EEGLAB standard of having the ' ...
  231. 'nose along the +X axis.' ];
  232. chanformat(4).importformat = { 'labels' '-Y' 'X' 'Z' };
  233. chanformat(4).skipline = 0;
  234. % ---------------------------------------------------------------------------------------------------
  235. chanformat(5).type = 'loc';
  236. chanformat(5).typestring = 'EEGLAB polar .loc file';
  237. chanformat(5).description = [ 'EEGLAB polar .loc file' ];
  238. chanformat(5).importformat = { 'channum' 'theta' 'radius' 'labels' };
  239. % ---------------------------------------------------------------------------------------------------
  240. chanformat(6).type = 'sph';
  241. chanformat(6).typestring = 'Matlab .sph spherical file';
  242. chanformat(6).description = [ 'Standard 3-D spherical coordinate files in Matlab format' ];
  243. chanformat(6).importformat = { 'channum' 'sph_theta' 'sph_phi' 'labels' };
  244. % ---------------------------------------------------------------------------------------------------
  245. chanformat(7).type = 'asc';
  246. chanformat(7).typestring = 'Neuroscan polar .asc file';
  247. chanformat(7).description = [ 'Neuroscan polar .asc file, automatically recentered to fit EEGLAB standard' ...
  248. 'of having ''Cz'' at (0,0).' ];
  249. chanformat(7).importformat = 'readneurolocs';
  250. % ---------------------------------------------------------------------------------------------------
  251. chanformat(8).type = 'dat';
  252. chanformat(8).typestring = 'Neuroscan 3-D .dat file';
  253. chanformat(8).description = [ 'Neuroscan 3-D cartesian .dat file. Coordinates are re-oriented to fit ' ...
  254. 'the EEGLAB standard of having the nose along the +X axis.' ];
  255. chanformat(8).importformat = 'readneurolocs';
  256. % ---------------------------------------------------------------------------------------------------
  257. chanformat(9).type = 'elc';
  258. chanformat(9).typestring = 'ASA .elc 3-D file';
  259. chanformat(9).description = [ 'ASA .elc 3-D coordinate file containing scanned electrode positions. ' ...
  260. 'User must select the direction ' ...
  261. 'for the nose after importing the data file.' ];
  262. chanformat(9).importformat = 'readeetraklocs';
  263. % ---------------------------------------------------------------------------------------------------
  264. chanformat(10).type = 'chanedit';
  265. chanformat(10).typestring = 'EEGLAB complete 3-D file';
  266. chanformat(10).description = [ 'EEGLAB file containing polar, cartesian 3-D, and spherical 3-D ' ...
  267. 'electrode locations.' ];
  268. chanformat(10).importformat = { 'channum' 'labels' 'theta' 'radius' 'X' 'Y' 'Z' 'sph_theta' 'sph_phi' ...
  269. 'sph_radius' 'type' };
  270. chanformat(10).skipline = 1;
  271. % ---------------------------------------------------------------------------------------------------
  272. chanformat(11).type = 'custom';
  273. chanformat(11).typestring = 'Custom file format';
  274. chanformat(11).description = 'Custom ASCII file format where user can define content for each file columns.';
  275. chanformat(11).importformat = '';
  276. % ---------------------------------------------------------------------------------------------------
  277. % ----- ADD MORE FORMATS HERE -----------------------------------------------------------------------
  278. % ---------------------------------------------------------------------------------------------------
  279. listcolformat = { 'labels' 'channum' 'theta' 'radius' 'sph_theta' 'sph_phi' ...
  280. 'sph_radius' 'sph_theta_besa' 'sph_phi_besa' 'gain' 'calib' 'type' ...
  281. 'X' 'Y' 'Z' '-X' '-Y' '-Z' 'custom1' 'custom2' 'custom3' 'custom4' 'ignore' 'not def' };
  282. % ----------------------------------
  283. % special mode for getting the info
  284. % ----------------------------------
  285. if isstr(filename) & strcmp(filename, 'getinfos')
  286. eloc = chanformat;
  287. labels = listcolformat;
  288. return;
  289. end;
  290. g = cm_eeg_finputcheck_20140226( varargin, ...
  291. { 'filetype' 'string' {} '';
  292. 'importmode' 'string' { 'eeglab' 'native' } 'eeglab';
  293. 'defaultelp' 'string' { 'besa' 'polhemus' } 'polhemus';
  294. 'skiplines' 'integer' [0 Inf] [];
  295. 'elecind' 'integer' [1 Inf] [];
  296. 'format' 'cell' [] {} }, 'readlocs');
  297. if isstr(g), error(g); end;
  298. if isstr(filename)
  299. % format auto detection
  300. % --------------------
  301. if strcmpi(g.filetype, 'autodetect'), g.filetype = ''; end;
  302. g.filetype = strtok(g.filetype);
  303. periods = find(filename == '.');
  304. fileextension = filename(periods(end)+1:end);
  305. g.filetype = lower(g.filetype);
  306. if isempty(g.filetype)
  307. switch lower(fileextension),
  308. case {'loc' 'locs' }, g.filetype = 'loc';
  309. case 'xyz', g.filetype = 'xyz';
  310. fprintf( [ 'WARNING: Matlab Cartesian coord. file extension (".xyz") detected.\n' ...
  311. 'If importing EGI Cartesian coords, force type "sfp" instead.\n'] );
  312. case 'sph', g.filetype = 'sph';
  313. case 'ced', g.filetype = 'chanedit';
  314. case 'elp', g.filetype = g.defaultelp;
  315. case 'asc', g.filetype = 'asc';
  316. case 'dat', g.filetype = 'dat';
  317. case 'elc', g.filetype = 'elc';
  318. case 'eps', g.filetype = 'besa';
  319. case 'sfp', g.filetype = 'sfp';
  320. otherwise, g.filetype = '';
  321. end;
  322. fprintf('readlocs(): ''%s'' format assumed from file extension\n', g.filetype);
  323. else
  324. if strcmpi(g.filetype, 'locs'), g.filetype = 'loc'; end
  325. if strcmpi(g.filetype, 'eloc'), g.filetype = 'loc'; end
  326. end;
  327. % assign format from filetype
  328. % ---------------------------
  329. if ~isempty(g.filetype) & ~strcmpi(g.filetype, 'custom') ...
  330. & ~strcmpi(g.filetype, 'asc') & ~strcmpi(g.filetype, 'elc') & ~strcmpi(g.filetype, 'dat')
  331. indexformat = strmatch(lower(g.filetype), { chanformat.type }, 'exact');
  332. g.format = chanformat(indexformat).importformat;
  333. if isempty(g.skiplines)
  334. g.skiplines = chanformat(indexformat).skipline;
  335. end;
  336. if isempty(g.filetype)
  337. error( ['readlocs() error: The filetype cannot be detected from the \n' ...
  338. ' file extension, and custom format not specified']);
  339. end;
  340. end;
  341. % import file
  342. % -----------
  343. if strcmp(g.filetype, 'asc') | strcmp(g.filetype, 'dat')
  344. eloc = readneurolocs( filename );
  345. eloc = rmfield(eloc, 'sph_theta'); % for the conversion below
  346. eloc = rmfield(eloc, 'sph_theta_besa'); % for the conversion below
  347. if isfield(eloc, 'type')
  348. for index = 1:length(eloc)
  349. type = eloc(index).type;
  350. if type == 69, eloc(index).type = 'EEG';
  351. elseif type == 88, eloc(index).type = 'REF';
  352. elseif type >= 76 & type <= 82, eloc(index).type = 'FID';
  353. else eloc(index).type = num2str(eloc(index).type);
  354. end;
  355. end;
  356. end;
  357. elseif strcmp(g.filetype, 'elc')
  358. eloc = readeetraklocs( filename );
  359. %eloc = read_asa_elc( filename ); % from fieldtrip
  360. %eloc = struct('labels', eloc.label, 'X', mattocell(eloc.pnt(:,1)'), 'Y', ...
  361. % mattocell(eloc.pnt(:,2)'), 'Z', mattocell(eloc.pnt(:,3)'));
  362. eloc = convertlocs(eloc, 'cart2all');
  363. eloc = rmfield(eloc, 'sph_theta'); % for the conversion below
  364. eloc = rmfield(eloc, 'sph_theta_besa'); % for the conversion below
  365. elseif strcmp(lower(g.filetype(1:end-1)), 'polhemus') | ...
  366. strcmp(g.filetype, 'polhemus')
  367. try,
  368. [eloc labels X Y Z]= readelp( filename );
  369. if strcmp(g.filetype, 'polhemusy')
  370. tmp = X; X = Y; Y = tmp;
  371. end;
  372. for index = 1:length( eloc )
  373. eloc(index).X = X(index);
  374. eloc(index).Y = Y(index);
  375. eloc(index).Z = Z(index);
  376. end;
  377. catch,
  378. disp('readlocs(): Could not read Polhemus coords. Trying to read BESA .elp file.');
  379. [eloc, labels, theta, radius, indices] = readlocs( filename, 'defaultelp', 'besa', varargin{:} );
  380. end;
  381. else
  382. % importing file
  383. % --------------
  384. if isempty(g.skiplines), g.skiplines = 0; end;
  385. if strcmpi(g.filetype, 'chanedit')
  386. array = loadtxt( filename, 'delim', 9, 'skipline', g.skiplines, 'blankcell', 'off');
  387. else
  388. array = load_file_or_array( filename, g.skiplines);
  389. end;
  390. if size(array,2) < length(g.format)
  391. fprintf(['readlocs() warning: Fewer columns in the input than expected.\n' ...
  392. ' See >> help readlocs\n']);
  393. elseif size(array,2) > length(g.format)
  394. fprintf(['readlocs() warning: More columns in the input than expected.\n' ...
  395. ' See >> help readlocs\n']);
  396. end;
  397. % removing lines BESA
  398. % -------------------
  399. if isempty(array{1,2})
  400. disp('BESA header detected, skipping three lines...');
  401. array = load_file_or_array( filename, g.skiplines-1);
  402. if isempty(array{1,2})
  403. array = load_file_or_array( filename, g.skiplines-1);
  404. end;
  405. end;
  406. % xyz format, is the first col absent
  407. % -----------------------------------
  408. if strcmp(g.filetype, 'xyz')
  409. if size(array, 2) == 4
  410. array(:, 2:5) = array(:, 1:4);
  411. end;
  412. end;
  413. % removing comments and empty lines
  414. % ---------------------------------
  415. indexbeg = 1;
  416. while isempty(array{indexbeg,1}) | ...
  417. (isstr(array{indexbeg,1}) & array{indexbeg,1}(1) == '%' )
  418. indexbeg = indexbeg+1;
  419. end;
  420. array = array(indexbeg:end,:);
  421. % converting file
  422. % ---------------
  423. for indexcol = 1:min(size(array,2), length(g.format))
  424. [str mult] = checkformat(g.format{indexcol});
  425. for indexrow = 1:size( array, 1)
  426. if mult ~= 1
  427. eval ( [ 'eloc(indexrow).' str '= -array{indexrow, indexcol};' ]);
  428. else
  429. eval ( [ 'eloc(indexrow).' str '= array{indexrow, indexcol};' ]);
  430. end;
  431. end;
  432. end;
  433. end;
  434. % handling BESA coordinates
  435. % -------------------------
  436. if isfield(eloc, 'sph_theta_besa')
  437. if isfield(eloc, 'type')
  438. if isnumeric(eloc(1).type)
  439. disp('BESA format detected ( Theta | Phi )');
  440. for index = 1:length(eloc)
  441. eloc(index).sph_phi_besa = eloc(index).labels;
  442. eloc(index).sph_theta_besa = eloc(index).type;
  443. eloc(index).labels = '';
  444. eloc(index).type = '';
  445. end;
  446. eloc = rmfield(eloc, 'labels');
  447. end;
  448. end;
  449. if isfield(eloc, 'labels')
  450. if isnumeric(eloc(1).labels)
  451. disp('BESA format detected ( Elec | Theta | Phi )');
  452. for index = 1:length(eloc)
  453. eloc(index).sph_phi_besa = eloc(index).sph_theta_besa;
  454. eloc(index).sph_theta_besa = eloc(index).labels;
  455. eloc(index).labels = eloc(index).type;
  456. eloc(index).type = '';
  457. eloc(index).radius = 1;
  458. end;
  459. end;
  460. end;
  461. try
  462. eloc = convertlocs(eloc, 'sphbesa2all');
  463. eloc = convertlocs(eloc, 'topo2all'); % problem with some EGI files (not BESA files)
  464. catch, disp('Warning: coordinate conversion failed'); end;
  465. fprintf('Readlocs: BESA spherical coords. converted, now deleting BESA fields\n');
  466. fprintf(' to avoid confusion (these fields can be exported, though)\n');
  467. eloc = rmfield(eloc, 'sph_phi_besa');
  468. eloc = rmfield(eloc, 'sph_theta_besa');
  469. % converting XYZ coordinates to polar
  470. % -----------------------------------
  471. elseif isfield(eloc, 'sph_theta')
  472. try
  473. eloc = convertlocs(eloc, 'sph2all');
  474. catch, disp('Warning: coordinate conversion failed'); end;
  475. elseif isfield(eloc, 'X')
  476. try
  477. eloc = convertlocs(eloc, 'cart2all');
  478. catch, disp('Warning: coordinate conversion failed'); end;
  479. else
  480. try
  481. eloc = convertlocs(eloc, 'topo2all');
  482. catch, disp('Warning: coordinate conversion failed'); end;
  483. end;
  484. % inserting labels if no labels
  485. % -----------------------------
  486. if ~isfield(eloc, 'labels')
  487. fprintf('readlocs(): Inserting electrode labels automatically.\n');
  488. for index = 1:length(eloc)
  489. eloc(index).labels = [ 'E' int2str(index) ];
  490. end;
  491. else
  492. % remove trailing '.'
  493. for index = 1:length(eloc)
  494. if isstr(eloc(index).labels)
  495. tmpdots = find( eloc(index).labels == '.' );
  496. eloc(index).labels(tmpdots) = [];
  497. end;
  498. end;
  499. end;
  500. % resorting electrodes if number not-sorted
  501. % -----------------------------------------
  502. if isfield(eloc, 'channum')
  503. if ~isnumeric(eloc(1).channum)
  504. error('Channel numbers must be numeric');
  505. end;
  506. allchannum = [ eloc.channum ];
  507. if any( sort(allchannum) ~= allchannum )
  508. fprintf('readlocs(): Re-sorting channel numbers based on ''channum'' column indices\n');
  509. [tmp newindices] = sort(allchannum);
  510. eloc = eloc(newindices);
  511. end;
  512. eloc = rmfield(eloc, 'channum');
  513. end;
  514. else
  515. if isstruct(filename)
  516. eloc = filename;
  517. else
  518. disp('readlocs(): input variable must be a string or a structure');
  519. end;
  520. end;
  521. if ~isempty(g.elecind)
  522. eloc = eloc(g.elecind);
  523. end;
  524. if nargout > 2
  525. if isfield(eloc, 'theta')
  526. tmptheta = { eloc.theta }; % check which channels have (polar) coordinates set
  527. else tmptheta = cell(1,length(eloc));
  528. end;
  529. if isfield(eloc, 'theta')
  530. tmpx = { eloc.X }; % check which channels have (polar) coordinates set
  531. else tmpx = cell(1,length(eloc));
  532. end;
  533. indices = find(~cellfun('isempty', tmptheta));
  534. indices = intersect(find(~cellfun('isempty', tmpx)), indices);
  535. indices = sort(indices);
  536. indbad = setdiff(1:length(eloc), indices);
  537. tmptheta(indbad) = { NaN };
  538. theta = [ tmptheta{:} ];
  539. end;
  540. if nargout > 3
  541. if isfield(eloc, 'theta')
  542. tmprad = { eloc.radius }; % check which channels have (polar) coordinates set
  543. else tmprad = cell(1,length(eloc));
  544. end;
  545. tmprad(indbad) = { NaN };
  546. radius = [ tmprad{:} ];
  547. end;
  548. %tmpnum = find(~cellfun('isclass', { eloc.labels }, 'char'));
  549. %disp('Converting channel labels to string');
  550. for index = 1:length(eloc)
  551. if ~isstr(eloc(index).labels)
  552. eloc(index).labels = int2str(eloc(index).labels);
  553. end;
  554. end;
  555. labels = { eloc.labels };
  556. if isfield(eloc, 'ignore')
  557. eloc = rmfield(eloc, 'ignore');
  558. end;
  559. % process fiducials if any
  560. % ------------------------
  561. fidnames = { 'nz' 'lpa' 'rpa' 'nasion' 'left' 'right' 'nazion' 'fidnz' 'fidt9' 'fidt10' };
  562. for index = 1:length(fidnames)
  563. ind = strmatch(fidnames{index}, lower(labels), 'exact');
  564. if ~isempty(ind), eloc(ind).type = 'FID'; end;
  565. end;
  566. return;
  567. % interpret the variable name
  568. % ---------------------------
  569. function array = load_file_or_array( varname, skiplines );
  570. if isempty(skiplines),
  571. skiplines = 0;
  572. end;
  573. if exist( varname ) == 2
  574. array = loadtxt(varname,'verbose','off','skipline',skiplines,'blankcell','off');
  575. else % variable in the global workspace
  576. % --------------------------
  577. try, array = evalin('base', varname);
  578. catch, error('readlocs(): cannot find the named file or variable, check syntax');
  579. end;
  580. end;
  581. return;
  582. % check field format
  583. % ------------------
  584. function [str, mult] = checkformat(str)
  585. mult = 1;
  586. if strcmpi(str, 'labels'), str = lower(str); return; end;
  587. if strcmpi(str, 'channum'), str = lower(str); return; end;
  588. if strcmpi(str, 'theta'), str = lower(str); return; end;
  589. if strcmpi(str, 'radius'), str = lower(str); return; end;
  590. if strcmpi(str, 'ignore'), str = lower(str); return; end;
  591. if strcmpi(str, 'sph_theta'), str = lower(str); return; end;
  592. if strcmpi(str, 'sph_phi'), str = lower(str); return; end;
  593. if strcmpi(str, 'sph_radius'), str = lower(str); return; end;
  594. if strcmpi(str, 'sph_theta_besa'), str = lower(str); return; end;
  595. if strcmpi(str, 'sph_phi_besa'), str = lower(str); return; end;
  596. if strcmpi(str, 'gain'), str = lower(str); return; end;
  597. if strcmpi(str, 'calib'), str = lower(str); return; end;
  598. if strcmpi(str, 'type') , str = lower(str); return; end;
  599. if strcmpi(str, 'X'), str = upper(str); return; end;
  600. if strcmpi(str, 'Y'), str = upper(str); return; end;
  601. if strcmpi(str, 'Z'), str = upper(str); return; end;
  602. if strcmpi(str, '-X'), str = upper(str(2:end)); mult = -1; return; end;
  603. if strcmpi(str, '-Y'), str = upper(str(2:end)); mult = -1; return; end;
  604. if strcmpi(str, '-Z'), str = upper(str(2:end)); mult = -1; return; end;
  605. if strcmpi(str, 'custom1'), return; end;
  606. if strcmpi(str, 'custom2'), return; end;
  607. if strcmpi(str, 'custom3'), return; end;
  608. if strcmpi(str, 'custom4'), return; end;
  609. error(['readlocs(): undefined field ''' str '''']);