v2.0.0
Loading...
Searching...
No Matches
bids_electrode.cpp
Go to the documentation of this file.
1//=============================================================================================================
12
13//=============================================================================================================
14// INCLUDES
15//=============================================================================================================
16
17#include "bids_electrode.h"
18#include "bids_tsv.h"
19
20#include <Eigen/Core>
21
22//=============================================================================================================
23// USED NAMESPACES
24//=============================================================================================================
25
26using namespace BIDSLIB;
27
28//=============================================================================================================
29// LOCAL HELPERS
30//=============================================================================================================
31
32namespace
33{
34static const QString NA = QStringLiteral("n/a");
35
36QString naToEmpty(const QString& s)
37{
38 return (s == NA) ? QString() : s;
39}
40} // anonymous namespace
41
42//=============================================================================================================
43// STATIC METHODS
44//=============================================================================================================
45
46QList<BidsElectrode> BidsElectrode::readTsv(const QString& sFilePath)
47{
48 QStringList headers;
49 QList<BidsTsvRow> rawRows = BidsTsv::readTsv(sFilePath, headers);
50
51 QList<BidsElectrode> electrodes;
52 electrodes.reserve(rawRows.size());
53
54 for(const auto& row : rawRows) {
55 BidsElectrode elec;
56 elec.name = row.value(QStringLiteral("name"));
57 elec.x = row.value(QStringLiteral("x"), NA);
58 elec.y = row.value(QStringLiteral("y"), NA);
59 elec.z = row.value(QStringLiteral("z"), NA);
60 elec.size = naToEmpty(row.value(QStringLiteral("size")));
61 elec.type = naToEmpty(row.value(QStringLiteral("type")));
62 elec.material = naToEmpty(row.value(QStringLiteral("material")));
63 elec.impedance = naToEmpty(row.value(QStringLiteral("impedance")));
64 electrodes.append(elec);
65 }
66
67 return electrodes;
68}
69
70//=============================================================================================================
71
72bool BidsElectrode::writeTsv(const QString& sFilePath,
73 const QList<BidsElectrode>& electrodes)
74{
75 QStringList headers = {
76 QStringLiteral("name"),
77 QStringLiteral("x"),
78 QStringLiteral("y"),
79 QStringLiteral("z"),
80 QStringLiteral("size"),
81 QStringLiteral("type"),
82 QStringLiteral("material"),
83 QStringLiteral("impedance"),
84 };
85
86 QList<BidsTsvRow> rows;
87 rows.reserve(electrodes.size());
88
89 for(const auto& elec : electrodes) {
90 BidsTsvRow row;
91 row[QStringLiteral("name")] = elec.name;
92 row[QStringLiteral("x")] = elec.x;
93 row[QStringLiteral("y")] = elec.y;
94 row[QStringLiteral("z")] = elec.z;
95 row[QStringLiteral("size")] = elec.size;
96 row[QStringLiteral("type")] = elec.type;
97 row[QStringLiteral("material")] = elec.material;
98 row[QStringLiteral("impedance")] = elec.impedance;
99 rows.append(row);
100 }
101
102 return BidsTsv::writeTsv(sFilePath, headers, rows);
103}
104
105//=============================================================================================================
106
108 const QList<BidsElectrode>& electrodes,
109 const FIFFLIB::FiffCoordTrans& trans)
110{
111 using namespace FIFFLIB;
112
113 FiffDigPointSet digSet;
114 int ident = 1;
115
116 const bool hasTransform = (trans.from != 0 || trans.to != 0);
117
118 for (const BidsElectrode& elec : electrodes) {
119 // Skip electrodes with "n/a" coordinates
120 bool xOk = false, yOk = false, zOk = false;
121 float xVal = elec.x.toFloat(&xOk);
122 float yVal = elec.y.toFloat(&yOk);
123 float zVal = elec.z.toFloat(&zOk);
124
125 if (!xOk || !yOk || !zOk) {
126 continue;
127 }
128
129 FiffDigPoint point;
130 point.kind = FIFFV_POINT_EEG;
131 point.ident = ident++;
132 point.r[0] = xVal;
133 point.r[1] = yVal;
134 point.r[2] = zVal;
135
136 // Apply coordinate transform if provided
137 if (hasTransform) {
138 Eigen::Vector3f pos(point.r[0], point.r[1], point.r[2]);
139 Eigen::Vector3f transformed = (trans.trans.block<3,3>(0,0).cast<float>() * pos
140 + trans.trans.block<3,1>(0,3).cast<float>());
141 point.r[0] = transformed(0);
142 point.r[1] = transformed(1);
143 point.r[2] = transformed(2);
144 }
145
146 digSet << point;
147 }
148
149 return digSet;
150}
Generic tab-separated-value reader/writer for BIDS sidecars (UTF-8, LF, n/a for missing values,...
Reader/writer for the BIDS _electrodes.tsv sidecar plus a bridge into FIFF digitizer-point space.
#define FIFFV_POINT_EEG
BIDS dataset reading, writing, path construction, and sidecar metadata handling for iEEG/EEG/MEG.
QMap< QString, QString > BidsTsvRow
Definition bids_tsv.h:54
FIFF file I/O, in-memory data structures and high-level readers/writers.
Electrode position record corresponding to one row in *_electrodes.tsv.
static bool writeTsv(const QString &sFilePath, const QList< BidsElectrode > &electrodes)
Write a BIDS *_electrodes.tsv file.
static QList< BidsElectrode > readTsv(const QString &sFilePath)
Read a BIDS *_electrodes.tsv file.
static FIFFLIB::FiffDigPointSet toFiffDigPoints(const QList< BidsElectrode > &electrodes, const FIFFLIB::FiffCoordTrans &trans=FIFFLIB::FiffCoordTrans())
Convert a list of BIDS electrodes to a FIFF digitizer point set.
static QList< BidsTsvRow > readTsv(const QString &sFilePath, QStringList &headers)
Definition bids_tsv.cpp:60
static bool writeTsv(const QString &sFilePath, const QStringList &headers, const QList< BidsTsvRow > &rows)
Definition bids_tsv.cpp:101
Labelled 4x4 FIFF affine: source frame, destination frame, rotation, translation and cached inverse.
Eigen::Matrix< float, 4, 4, Eigen::DontAlign > trans
One digitizer point: kind (cardinal/HPI/EEG/extra), ident, 3D position in FIFFV_COORD_HEAD.
Collection of FiffDigPoint records as parsed from a FIFFB_ISOTRAK block.