107 const Eigen::MatrixX3f &vertices,
108 const Eigen::MatrixX3f &normals,
109 const Eigen::MatrixX3i &triangles)
111 QMutexLocker locker(&m_mutex);
112 m_megSurfaceKey = surfaceKey;
113 m_megVertices = vertices;
114 m_megNormals = normals;
115 m_megTriangles = triangles;
116 m_hasMegSurface = (vertices.rows() > 0);
145 bool applySensorTrans;
147 QString megSurfaceKey, eegSurfaceKey;
148 Eigen::MatrixX3f megVerts, megNorms, eegVerts;
149 Eigen::MatrixX3i megTris;
150 bool hasMegSurface, hasEegSurface, hasEvoked;
154 QMutexLocker locker(&m_mutex);
156 hasEvoked = m_hasEvoked;
157 headToMriTrans = m_headToMriTrans;
158 applySensorTrans = m_applySensorTrans;
159 megOnHead = m_megOnHead;
160 megSurfaceKey = m_megSurfaceKey;
161 eegSurfaceKey = m_eegSurfaceKey;
162 megVerts = m_megVertices;
163 megNorms = m_megNormals;
164 megTris = m_megTriangles;
165 hasMegSurface = m_hasMegSurface;
166 eegVerts = m_eegVertices;
167 hasEegSurface = m_hasEegSurface;
172 qDebug() <<
"RtSensorInterpolationMatWorker: No evoked data set, skipping.";
176 qDebug() <<
"RtSensorInterpolationMatWorker: Computing mapping matrices...";
179 bool hasDevHead =
false;
180 QMatrix4x4 devHeadQt;
189 QMatrix4x4 headToMri;
190 if (applySensorTrans && !headToMriTrans.
isEmpty()) {
191 headToMri = toQMatrix4x4(headToMriTrans.
trans);
195 QList<FiffChInfo> megChs, eegChs;
196 QVector<int> megPick, eegPick;
198 for (
int k = 0; k < evoked.
info.
chs.size(); ++k) {
199 const auto &ch = evoked.
info.
chs[k];
200 if (bads.contains(ch.ch_name))
continue;
202 QVector3D pos(ch.chpos.r0(0), ch.chpos.r0(1), ch.chpos.r0(2));
205 if (hasDevHead) pos = devHeadQt.map(pos);
206 if (applySensorTrans && !headToMriTrans.
isEmpty()) pos = headToMri.map(pos);
210 if (applySensorTrans && !headToMriTrans.
isEmpty()) pos = headToMri.map(pos);
217 constexpr float kIntrad = 0.06f;
218 constexpr float kMegMiss = 1e-4f;
219 constexpr float kEegMiss = 1e-3f;
220 const Eigen::Vector3f defaultOrigin(0.0f, 0.0f, 0.04f);
230 if (hasMegSurface && !megChs.isEmpty()) {
231 Eigen::MatrixX3f norms = megNorms;
234 if (norms.rows() != megVerts.rows()) {
235 if (megTris.rows() > 0) {
240 if (megVerts.rows() > 0 && norms.rows() == megVerts.rows()) {
241 const QString coilPath = QCoreApplication::applicationDirPath()
242 +
"/../resources/general/coilDefinitions/coil_def.dat";
248 if (megOnHead && !headMri.
isEmpty()) {
254 }
else if (!devHead.
isEmpty()) {
255 devToTarget = devHead;
258 Eigen::Vector3f origin = defaultOrigin;
259 if (megOnHead && !headMri.
isEmpty()) {
260 origin = applyTransform(origin, headMri);
263 auto coils = templates->create_meg_coils(
266 if (coils && coils->ncoil() > 0) {
268 *coils, megVerts, norms, origin, kIntrad, kMegMiss);
270 if (mat && mat->rows() > 0) {
271 qDebug() <<
"RtSensorInterpolationMatWorker: MEG mapping computed:"
272 << mat->rows() <<
"x" << mat->cols();
274 std::shared_ptr<Eigen::MatrixXf>(std::move(mat)), megPick);
282 if (hasEegSurface && !eegChs.isEmpty()) {
283 if (eegVerts.rows() > 0) {
284 Eigen::Vector3f origin = defaultOrigin;
285 if (!headMri.
isEmpty()) origin = applyTransform(origin, headMri);
289 eegChs, eegChs.size(), headMri);
291 if (eegCoils && eegCoils->ncoil() > 0) {
293 *eegCoils, eegVerts, origin, kIntrad, kEegMiss);
295 if (mat && mat->rows() > 0) {
296 qDebug() <<
"RtSensorInterpolationMatWorker: EEG mapping computed:"
297 << mat->rows() <<
"x" << mat->cols();
299 std::shared_ptr<Eigen::MatrixXf>(std::move(mat)), eegPick);
305 qDebug() <<
"RtSensorInterpolationMatWorker: Mapping computation complete.";