66 const QString &megHelmetOverridePath)
71 if (!file.exists())
return result;
80 if (stream->read_meas_info(tree, info, nodeInfo)) {
89 QMatrix4x4 devHeadQTrans;
90 bool hasDevHead =
false;
102 for (
const auto &ch : info.
chs) {
104 QVector3D pos(ch.chpos.r0(0), ch.chpos.r0(1), ch.chpos.r0(2));
107 pos = devHeadQTrans.map(pos);
110 auto *item =
new SensorTreeItem(ch.ch_name, pos, QColor(100, 100, 100), 0.01f);
114 for (
int r = 0; r < 3; ++r)
115 for (
int c = 0; c < 3; ++c)
116 orient(r, c) = ch.coil_trans(r, c);
118 QMatrix4x4 devHeadRot;
119 for (
int r = 0; r < 3; ++r)
120 for (
int c = 0; c < 3; ++c)
121 devHeadRot(r, c) = devHeadQTrans(r, c);
122 orient = devHeadRot * orient;
124 item->setOrientation(orient);
132 QVector3D pos(ch.chpos.r0(0), ch.chpos.r0(1), ch.chpos.r0(2));
139 auto pickHelmetFile = [&info]() -> QString {
142 for (
const auto &ch : info.
chs) {
144 coilType = ch.chpos.coil_type & 0xFFFF;
149 QString fileName =
"306m.fif";
151 fileName =
"BabySQUID.fif";
153 fileName =
"122m.fif";
155 fileName =
"CTF_275.fif";
157 fileName =
"KIT.fif";
159 fileName = (nMeg > 150) ?
"Magnes_3600wh.fif" :
"Magnes_2500wh.fif";
160 }
else if (coilType / 1000 == 3) {
161 fileName =
"306m.fif";
164 return QCoreApplication::applicationDirPath()
165 +
"/../resources/general/sensorSurfaces/" + fileName;
169 if (!megHelmetOverridePath.isEmpty()) {
170 helmetPath = megHelmetOverridePath;
171 if (!QFile::exists(helmetPath)) {
172 qWarning() <<
"MEG helmet override file not found:" << helmetPath
173 <<
"- falling back to auto selection.";
178 if (helmetPath.isEmpty()) {
179 helmetPath = pickHelmetFile();
183 if (!QFile::exists(helmetPath)) {
184 QString fn = QFileInfo(helmetPath).fileName();
185 if (fn.isEmpty()) fn = QStringLiteral(
"306m.fif");
186 helmetPath = QStringLiteral(
"/resources/general/sensorSurfaces/") + fn;
191 if (!QFile::exists(helmetPath)) {
192 QString fallback = QCoreApplication::applicationDirPath()
193 +
"/../resources/general/sensorSurfaces/306m.fif";
194 if (QFile::exists(fallback)) {
195 helmetPath = fallback;
203 if (!QFile::exists(helmetPath)) {
204 QString wasmFallback = QStringLiteral(
"/resources/general/sensorSurfaces/")
205 + QFileInfo(helmetPath).fileName();
206 if (wasmFallback.endsWith(
'/')) wasmFallback +=
"306m.fif";
207 if (QFile::exists(wasmFallback)) {
208 helmetPath = wasmFallback;
213 if (!QFile::exists(helmetPath)) {
214 qWarning() <<
"MEG helmet surface file not found. Checked:" << helmetPath;
217 if (QFile::exists(helmetPath)) {
218 QFile helmetFile(helmetPath);
219 MNEBem helmetBem(helmetFile);
220 if (helmetBem.
size() > 0) {
222 if (helmetSurf.
nn.rows() != helmetSurf.
rr.rows()) {
227 QMatrix3x3 normalMat = devHeadQTrans.normalMatrix();
228 for (
int i = 0; i < helmetSurf.
rr.rows(); ++i) {
229 QVector3D pos(helmetSurf.
rr(i, 0), helmetSurf.
rr(i, 1), helmetSurf.
rr(i, 2));
230 pos = devHeadQTrans.map(pos);
231 helmetSurf.
rr(i, 0) = pos.x();
232 helmetSurf.
rr(i, 1) = pos.y();
233 helmetSurf.
rr(i, 2) = pos.z();
235 QVector3D nn(helmetSurf.
nn(i, 0), helmetSurf.
nn(i, 1), helmetSurf.
nn(i, 2));
236 const float *d = normalMat.constData();
237 float nx = d[0] * nn.x() + d[3] * nn.y() + d[6] * nn.z();
238 float ny = d[1] * nn.x() + d[4] * nn.y() + d[7] * nn.z();
239 float nz = d[2] * nn.x() + d[5] * nn.y() + d[8] * nn.z();
240 QVector3D n = QVector3D(nx, ny, nz).normalized();
241 helmetSurf.
nn(i, 0) = n.x();
242 helmetSurf.
nn(i, 1) = n.y();
243 helmetSurf.
nn(i, 2) = n.z();
247 auto helmetSurface = std::make_shared<BrainSurface>();
248 helmetSurface->fromBemSurface(helmetSurf, QColor(0, 0, 77, 200));
249 helmetSurface->setVisible(
true);
252 qWarning() <<
"DataLoader::loadSensors: helmetBem[0] has 0 verts/tris!";
265 if (digSet.
size() > 0) {
266 for (
int i = 0; i < digSet.
size(); ++i) {
279 const QString &helmetFilePath,
280 const QMatrix4x4 &devHeadTrans,
283 if (!QFile::exists(helmetFilePath)) {
284 qWarning() <<
"DataLoader::loadHelmetSurface: file not found:" << helmetFilePath;
288 QFile helmetFile(helmetFilePath);
289 MNEBem helmetBem(helmetFile);
290 if (helmetBem.
size() == 0) {
291 qWarning() <<
"DataLoader::loadHelmetSurface: no BEM surfaces in" << helmetFilePath;
297 if (helmetSurf.
nn.rows() != helmetSurf.
rr.rows()) {
302 QMatrix3x3 normalMat = devHeadTrans.normalMatrix();
303 for (
int i = 0; i < helmetSurf.
rr.rows(); ++i) {
304 QVector3D pos(helmetSurf.
rr(i, 0), helmetSurf.
rr(i, 1), helmetSurf.
rr(i, 2));
305 pos = devHeadTrans.map(pos);
306 helmetSurf.
rr(i, 0) = pos.x();
307 helmetSurf.
rr(i, 1) = pos.y();
308 helmetSurf.
rr(i, 2) = pos.z();
310 QVector3D nn(helmetSurf.
nn(i, 0), helmetSurf.
nn(i, 1), helmetSurf.
nn(i, 2));
311 const float *d = normalMat.constData();
312 float nx = d[0] * nn.x() + d[3] * nn.y() + d[6] * nn.z();
313 float ny = d[1] * nn.x() + d[4] * nn.y() + d[7] * nn.z();
314 float nz = d[2] * nn.x() + d[5] * nn.y() + d[8] * nn.z();
315 QVector3D n = QVector3D(nx, ny, nz).normalized();
316 helmetSurf.
nn(i, 0) = n.x();
317 helmetSurf.
nn(i, 1) = n.y();
318 helmetSurf.
nn(i, 2) = n.z();
322 auto surface = std::make_shared<BrainSurface>();
323 surface->fromBemSurface(helmetSurf, QColor(0, 0, 77, 200));
324 surface->setVisible(
true);