129 const Eigen::MatrixX3f &vertices,
130 const Eigen::MatrixX3f &normals,
131 const Eigen::MatrixX3i &triangles)
133 QMutexLocker locker(&m_mutex);
134 m_megSurfaceKey = surfaceKey;
135 m_megVertices = vertices;
136 m_megNormals = normals;
137 m_megTriangles = triangles;
138 m_hasMegSurface = (vertices.rows() > 0);
167 bool applySensorTrans;
169 QString megSurfaceKey, eegSurfaceKey;
170 Eigen::MatrixX3f megVerts, megNorms, eegVerts;
171 Eigen::MatrixX3i megTris;
172 bool hasMegSurface, hasEegSurface, hasEvoked;
176 QMutexLocker locker(&m_mutex);
178 hasEvoked = m_hasEvoked;
179 headToMriTrans = m_headToMriTrans;
180 applySensorTrans = m_applySensorTrans;
181 megOnHead = m_megOnHead;
182 megSurfaceKey = m_megSurfaceKey;
183 eegSurfaceKey = m_eegSurfaceKey;
184 megVerts = m_megVertices;
185 megNorms = m_megNormals;
186 megTris = m_megTriangles;
187 hasMegSurface = m_hasMegSurface;
188 eegVerts = m_eegVertices;
189 hasEegSurface = m_hasEegSurface;
194 qDebug() <<
"RtSensorInterpolationMatWorker: No evoked data set, skipping.";
198 qDebug() <<
"RtSensorInterpolationMatWorker: Computing mapping matrices...";
201 bool hasDevHead =
false;
202 QMatrix4x4 devHeadQt;
211 QMatrix4x4 headToMri;
212 if (applySensorTrans && !headToMriTrans.
isEmpty()) {
213 headToMri = toQMatrix4x4(headToMriTrans.
trans);
217 QList<FiffChInfo> megChs, eegChs;
218 QVector<int> megPick, eegPick;
220 for (
int k = 0; k < evoked.
info.
chs.size(); ++k) {
221 const auto &ch = evoked.
info.
chs[k];
222 if (bads.contains(ch.ch_name))
continue;
224 QVector3D pos(ch.chpos.r0(0), ch.chpos.r0(1), ch.chpos.r0(2));
227 if (hasDevHead) pos = devHeadQt.map(pos);
228 if (applySensorTrans && !headToMriTrans.
isEmpty()) pos = headToMri.map(pos);
232 if (applySensorTrans && !headToMriTrans.
isEmpty()) pos = headToMri.map(pos);
239 constexpr float kIntrad = 0.06f;
240 constexpr float kMegMiss = 1e-4f;
241 constexpr float kEegMiss = 1e-3f;
242 const Eigen::Vector3f defaultOrigin(0.0f, 0.0f, 0.04f);
252 if (hasMegSurface && !megChs.isEmpty()) {
253 Eigen::MatrixX3f norms = megNorms;
256 if (norms.rows() != megVerts.rows()) {
257 if (megTris.rows() > 0) {
262 if (megVerts.rows() > 0 && norms.rows() == megVerts.rows()) {
263 const QString coilPath = QCoreApplication::applicationDirPath()
264 +
"/../resources/general/coilDefinitions/coil_def.dat";
265 std::unique_ptr<FWDLIB::FwdCoilSet> templates(
270 if (megOnHead && !headMri.
isEmpty()) {
276 }
else if (!devHead.
isEmpty()) {
277 devToTarget = devHead;
280 Eigen::Vector3f origin = defaultOrigin;
281 if (megOnHead && !headMri.
isEmpty()) {
282 origin = applyTransform(origin, headMri);
285 std::unique_ptr<FWDLIB::FwdCoilSet> coils(templates->create_meg_coils(
288 if (coils && coils->ncoil > 0) {
290 *coils, megVerts, norms, origin, kIntrad, kMegMiss);
292 if (mat && mat->rows() > 0) {
293 qDebug() <<
"RtSensorInterpolationMatWorker: MEG mapping computed:"
294 << mat->rows() <<
"x" << mat->cols();
303 if (hasEegSurface && !eegChs.isEmpty()) {
304 if (eegVerts.rows() > 0) {
305 Eigen::Vector3f origin = defaultOrigin;
306 if (!headMri.
isEmpty()) origin = applyTransform(origin, headMri);
308 std::unique_ptr<FWDLIB::FwdCoilSet> eegCoils(
310 eegChs, eegChs.size(), headMri));
312 if (eegCoils && eegCoils->ncoil > 0) {
314 *eegCoils, eegVerts, origin, kIntrad, kEegMiss);
316 if (mat && mat->rows() > 0) {
317 qDebug() <<
"RtSensorInterpolationMatWorker: EEG mapping computed:"
318 << mat->rows() <<
"x" << mat->cols();
325 qDebug() <<
"RtSensorInterpolationMatWorker: Mapping computation complete.";