46#include <QCoreApplication>
65 const QString &megHelmetOverridePath)
70 if (!file.exists())
return result;
79 if (stream->read_meas_info(tree, info, nodeInfo)) {
88 QMatrix4x4 devHeadQTrans;
89 bool hasDevHead =
false;
101 for (
const auto &ch : info.
chs) {
103 QVector3D pos(ch.chpos.r0(0), ch.chpos.r0(1), ch.chpos.r0(2));
106 pos = devHeadQTrans.map(pos);
109 auto *item =
new SensorTreeItem(ch.ch_name, pos, QColor(100, 100, 100), 0.01f);
113 for (
int r = 0; r < 3; ++r)
114 for (
int c = 0; c < 3; ++c)
115 orient(r, c) = ch.coil_trans(r, c);
117 QMatrix4x4 devHeadRot;
118 for (
int r = 0; r < 3; ++r)
119 for (
int c = 0; c < 3; ++c)
120 devHeadRot(r, c) = devHeadQTrans(r, c);
121 orient = devHeadRot * orient;
123 item->setOrientation(orient);
131 QVector3D pos(ch.chpos.r0(0), ch.chpos.r0(1), ch.chpos.r0(2));
138 auto pickHelmetFile = [&info]() -> QString {
141 for (
const auto &ch : info.
chs) {
143 coilType = ch.chpos.coil_type & 0xFFFF;
148 QString fileName =
"306m.fif";
150 fileName =
"BabySQUID.fif";
152 fileName =
"122m.fif";
154 fileName =
"CTF_275.fif";
156 fileName =
"KIT.fif";
158 fileName = (nMeg > 150) ?
"Magnes_3600wh.fif" :
"Magnes_2500wh.fif";
159 }
else if (coilType / 1000 == 3) {
160 fileName =
"306m.fif";
163 return QCoreApplication::applicationDirPath()
164 +
"/../resources/general/sensorSurfaces/" + fileName;
168 if (!megHelmetOverridePath.isEmpty()) {
169 helmetPath = megHelmetOverridePath;
170 if (!QFile::exists(helmetPath)) {
171 qWarning() <<
"MEG helmet override file not found:" << helmetPath
172 <<
"- falling back to auto selection.";
177 if (helmetPath.isEmpty()) {
178 helmetPath = pickHelmetFile();
181 if (!QFile::exists(helmetPath)) {
182 QString fallback = QCoreApplication::applicationDirPath()
183 +
"/../resources/general/sensorSurfaces/306m.fif";
184 if (QFile::exists(fallback)) {
185 helmetPath = fallback;
189 if (!QFile::exists(helmetPath)) {
190 qWarning() <<
"MEG helmet surface file not found. Checked:" << helmetPath;
193 if (QFile::exists(helmetPath)) {
194 QFile helmetFile(helmetPath);
195 MNEBem helmetBem(helmetFile);
196 if (helmetBem.
size() > 0) {
198 if (helmetSurf.
nn.rows() != helmetSurf.
rr.rows()) {
203 QMatrix3x3 normalMat = devHeadQTrans.normalMatrix();
204 for (
int i = 0; i < helmetSurf.
rr.rows(); ++i) {
205 QVector3D pos(helmetSurf.
rr(i, 0), helmetSurf.
rr(i, 1), helmetSurf.
rr(i, 2));
206 pos = devHeadQTrans.map(pos);
207 helmetSurf.
rr(i, 0) = pos.x();
208 helmetSurf.
rr(i, 1) = pos.y();
209 helmetSurf.
rr(i, 2) = pos.z();
211 QVector3D nn(helmetSurf.
nn(i, 0), helmetSurf.
nn(i, 1), helmetSurf.
nn(i, 2));
212 const float *d = normalMat.constData();
213 float nx = d[0] * nn.x() + d[3] * nn.y() + d[6] * nn.z();
214 float ny = d[1] * nn.x() + d[4] * nn.y() + d[7] * nn.z();
215 float nz = d[2] * nn.x() + d[5] * nn.y() + d[8] * nn.z();
216 QVector3D n = QVector3D(nx, ny, nz).normalized();
217 helmetSurf.
nn(i, 0) = n.x();
218 helmetSurf.
nn(i, 1) = n.y();
219 helmetSurf.
nn(i, 2) = n.z();
223 auto helmetSurface = std::make_shared<BrainSurface>();
224 helmetSurface->fromBemSurface(helmetSurf, QColor(0, 0, 77, 200));
225 helmetSurface->setVisible(
true);
228 qWarning() <<
"DataLoader::loadSensors: helmetBem[0] has 0 verts/tris!";
241 if (digSet.
size() > 0) {
242 for (
int i = 0; i < digSet.
size(); ++i) {
255 const QString &helmetFilePath,
256 const QMatrix4x4 &devHeadTrans,
259 if (!QFile::exists(helmetFilePath)) {
260 qWarning() <<
"DataLoader::loadHelmetSurface: file not found:" << helmetFilePath;
264 QFile helmetFile(helmetFilePath);
265 MNEBem helmetBem(helmetFile);
266 if (helmetBem.
size() == 0) {
267 qWarning() <<
"DataLoader::loadHelmetSurface: no BEM surfaces in" << helmetFilePath;
273 if (helmetSurf.
nn.rows() != helmetSurf.
rr.rows()) {
278 QMatrix3x3 normalMat = devHeadTrans.normalMatrix();
279 for (
int i = 0; i < helmetSurf.
rr.rows(); ++i) {
280 QVector3D pos(helmetSurf.
rr(i, 0), helmetSurf.
rr(i, 1), helmetSurf.
rr(i, 2));
281 pos = devHeadTrans.map(pos);
282 helmetSurf.
rr(i, 0) = pos.x();
283 helmetSurf.
rr(i, 1) = pos.y();
284 helmetSurf.
rr(i, 2) = pos.z();
286 QVector3D nn(helmetSurf.
nn(i, 0), helmetSurf.
nn(i, 1), helmetSurf.
nn(i, 2));
287 const float *d = normalMat.constData();
288 float nx = d[0] * nn.x() + d[3] * nn.y() + d[6] * nn.z();
289 float ny = d[1] * nn.x() + d[4] * nn.y() + d[7] * nn.z();
290 float nz = d[2] * nn.x() + d[5] * nn.y() + d[8] * nn.z();
291 QVector3D n = QVector3D(nx, ny, nz).normalized();
292 helmetSurf.
nn(i, 0) = n.x();
293 helmetSurf.
nn(i, 1) = n.y();
294 helmetSurf.
nn(i, 2) = n.z();
298 auto surface = std::make_shared<BrainSurface>();
299 surface->fromBemSurface(helmetSurf, QColor(0, 0, 77, 200));
300 surface->setVisible(
true);
310 if (ecdSet.
size() == 0) {
311 qWarning() <<
"DataLoader: Failed to load dipoles from" << dipPath;
321 if (!file.exists()) {
322 qWarning() <<
"DataLoader: Source space file not found:" << fwdPath;
328 if (!stream->open()) {
329 qWarning() <<
"DataLoader: Failed to open FIF stream for source space";
334 qWarning() <<
"DataLoader: Failed to read source space from" << fwdPath;
339 qWarning() <<
"DataLoader: Source space is empty";
351 QFile file(transPath);
355 qWarning() <<
"DataLoader: Failed to load transformation from" << transPath;
369 qWarning() <<
"DataLoader: Loaded transformation is not Head<->MRI (from"
370 << raw.
from <<
"to" << raw.
to <<
"). Using as is.";
381 QFile file(evokedPath);
382 if (!file.exists()) {
383 qWarning() <<
"DataLoader: Sensor evoked file not found:" << evokedPath;
389 qWarning() <<
"DataLoader: Failed to read evoked data from" << evokedPath;
399 QFile file(evokedPath);
400 if (!file.exists()) {
405 for (
int i = 0; i < evokedSet.
evoked.size(); ++i) {
406 const auto &ev = evokedSet.
evoked.at(i);
407 QString label = QString(
"%1: %2 (%3, nave=%4)")
409 .arg(ev.comment.isEmpty() ? QStringLiteral(
"Set %1").arg(i) : ev.comment)
410 .arg(ev.aspectKindToString())
412 result.append(label);
FIFF class declaration, which provides static wrapper functions to stay consistent with mne matlab to...
#define FIFFV_COIL_CTF_GRAD
#define FIFFV_COORD_DEVICE
#define FIFFV_COIL_NM_122
#define FIFFV_COIL_MAGNES_MAG
#define FIFFV_COIL_BABY_GRAD
#define FIFFV_COIL_MAGNES_GRAD
#define FIFFV_COIL_KIT_GRAD
FiffStream class declaration.
FiffDigPointSet class declaration.
BrainSurface class declaration.
DataLoader — static helpers for loading MNE data files.
Surface key constants and type-to-key mappings.
SensorTreeItem class declaration.
MNEBem class declaration.
Surface class declaration.
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O and data structures (raw, epochs, evoked, covariance, forward).
QMatrix4x4 toQMatrix4x4(const Eigen::Matrix4f &m)
Inverse source estimation (MNE, dSPM, sLORETA, dipole fitting).
static SensorLoadResult loadSensors(const QString &fifPath, const QString &megHelmetOverridePath={})
static QStringList probeEvokedSets(const QString &evokedPath)
static INVERSELIB::ECDSet loadDipoles(const QString &dipPath)
static MNELIB::MNESourceSpaces loadSourceSpace(const QString &fwdPath)
static bool loadHeadToMriTransform(const QString &transPath, FIFFLIB::FiffCoordTrans &trans)
static std::shared_ptr< BrainSurface > loadHelmetSurface(const QString &helmetFilePath, const QMatrix4x4 &devHeadTrans=QMatrix4x4(), bool applyTrans=false)
static FIFFLIB::FiffEvoked loadEvoked(const QString &evokedPath, int aveIndex=0)
Return value bundling loaded sensor geometry, labels, and channel-to-sensor mapping.
std::shared_ptr< BrainSurface > helmetSurface
May be null.
QList< QStandardItem * > megGradItems
Ownership passes to caller.
FIFFLIB::FiffInfo info
Channel / dig info.
QMatrix4x4 devHeadTrans
Device→Head transform (identity if absent).
QList< QStandardItem * > eegItems
bool hasDevHead
Whether a valid dev→head transform was found.
QList< FIFFLIB::FiffDigPoint > digitizerPoints
QList< QStandardItem * > megMagItems
Tree item representing MEG or EEG sensor positions in the 3-D scene hierarchy.
Coordinate transformation description.
Eigen::Matrix< float, 4, 4, Eigen::DontAlign > trans
Eigen::Matrix< float, 4, 4, Eigen::DontAlign > invtrans
Holds a set of digitizer points.
QSharedPointer< FiffDirNode > SPtr
QList< FiffEvoked > evoked
FIFF measurement file information.
QList< FiffDigPoint > dig
FiffCoordTrans dev_head_t
QSharedPointer< FiffStream > SPtr
static Eigen::MatrixX3f compute_normals(const Eigen::MatrixX3f &rr, const Eigen::MatrixX3i &tris)
Holds a set of Electric Current Dipoles.
static ECDSet read_dipoles_dip(const QString &fileName)
BEM surface provides geometry information.
Source Space descritpion.
static bool readFromStream(FIFFLIB::FiffStream::SPtr &p_pStream, bool add_geom, MNESourceSpaces &p_SourceSpace)
static bool read(QIODevice &p_IODevice, FiffCoordTrans &p_Trans)