v2.0.0
Loading...
Searching...
No Matches
standard_montage.cpp
Go to the documentation of this file.
1//=============================================================================================================
17
18//=============================================================================================================
19// INCLUDES
20//=============================================================================================================
21
22#include "standard_montage.h"
23
24#include <QFile>
25#include <QTextStream>
26
27//=============================================================================================================
28// USED NAMESPACES
29//=============================================================================================================
30
31using namespace UTILSLIB;
32using namespace Eigen;
33
34//=============================================================================================================
35// STATIC HELPERS
36//=============================================================================================================
37
38// Q_INIT_RESOURCE must not be expanded inside a namespace; static builds need it.
39static void initStandardMontageResource()
40{
41 Q_INIT_RESOURCE(standard_montage);
42}
43
44namespace
45{
46
47// Every position of standard_1005.elc in metres, fiducials included, read as mne's _mgh_or_standard does.
48const QList<ElectrodePosition>& standard1005Table()
49{
50 static const QList<ElectrodePosition> table = [] {
51 initStandardMontageResource();
52 QList<ElectrodePosition> positions;
53 QFile file(QStringLiteral(":/utils/montages/standard_1005.elc"));
54 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
55 qWarning("[StandardMontage] the built-in standard_1005 table is missing");
56 return positions;
57 }
58 QTextStream in(&file);
59 while (!in.atEnd() && in.readLine() != QLatin1String("Positions")) {
60 }
61 QList<Vector3d> coordinates;
62 for (QString line = in.readLine(); !in.atEnd() && line != QLatin1String("Labels"); line = in.readLine()) {
63 const QStringList fields = line.split(QLatin1Char(' '), Qt::SkipEmptyParts);
64 if (fields.size() == 3)
65 coordinates.append(Vector3d(fields[0].toDouble(), fields[1].toDouble(), fields[2].toDouble()) / 1000.0);
66 }
67 for (const Vector3d& r : coordinates) {
68 const QString name = in.readLine().trimmed();
69 if (name.isEmpty())
70 break;
71 positions.append({name, r});
72 }
73 return positions;
74 }();
75 return table;
76}
77
78// The positions of the named electrodes, in the order given.
79QList<ElectrodePosition> pick(const QStringList& names)
80{
81 QList<ElectrodePosition> positions;
82 for (const QString& name : names) {
83 for (const ElectrodePosition& electrode : standard1005Table()) {
84 if (electrode.name == name) {
85 positions.append(electrode);
86 break;
87 }
88 }
89 }
90 return positions;
91}
92
93const QStringList& names1020()
94{
95 static const QStringList names{"Fp1", "Fp2", "F7", "F3", "Fz", "F4", "F8", "T7", "C3", "Cz", "C4",
96 "T8", "P7", "P3", "Pz", "P4", "P8", "O1", "O2", "A1", "A2"};
97 return names;
98}
99
100const QStringList& names1010()
101{
102 static const QStringList names = names1020() + QStringList{"AF7", "AF3", "AFz", "AF4", "AF8", "F5", "F1", "F2", "F6", "FT7", "FC5", "FC3", "FC1", "FCz", "FC2", "FC4", "FC6", "FT8", "C5", "C1", "C2", "C6", "TP7", "CP5", "CP3", "CP1", "CPz", "CP2", "CP4", "CP6", "TP8", "P5", "P1", "P2", "P6", "PO7", "PO3", "POz", "PO4", "PO8", "Oz", "FT9", "FT10", "TP9", "TP10", "Fpz", "Iz", "Nz", "F9", "F10", "P9", "P10"};
103 return names;
104}
105
106} // anonymous namespace
107
108//=============================================================================================================
109// DEFINE MEMBER METHODS
110//=============================================================================================================
111
112QList<ElectrodePosition> StandardMontage::getMontage(System system)
113{
114 switch (system) {
116 return pick(names1020());
118 return pick(names1010());
120 // mne's standard_1005 montage: every electrode, the fiducials are not channels
121 QList<ElectrodePosition> positions = standard1005Table();
122 positions.removeIf([](const ElectrodePosition& electrode) {
123 return electrode.name == QLatin1String("LPA") || electrode.name == QLatin1String("RPA") || electrode.name == QLatin1String("Nz");
124 });
125 return positions;
126 }
127 }
128 return {};
129}
130
131//=============================================================================================================
132
134{
135 QStringList names;
136 for (const auto& ep : getMontage(system)) {
137 names << ep.name;
138 }
139 return names;
140}
141
142//=============================================================================================================
143
144bool StandardMontage::findElectrode(const QString& name, Vector3d& pos)
145{
146 for (const auto& ep : standard1005Table()) {
147 if (ep.name.compare(name, Qt::CaseInsensitive) == 0) {
148 pos = ep.pos;
149 return true;
150 }
151 }
152 return false;
153}
154
155//=============================================================================================================
156
158{
159 return getMontage(system).size();
160}
Standard 10-20 / 10-10 / 10-05 EEG electrode positions of MNE-Python's standard_1005 montage.
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
Represents an electrode position in a montage.
static QList< ElectrodePosition > getMontage(System system)
Get a standard montage by system name.
System
Supported standard montage systems.
static bool findElectrode(const QString &name, Eigen::Vector3d &pos)
Look up a single electrode position by name.
static int electrodeCount(System system)
Get the number of electrodes in a montage.
static QStringList getElectrodeNames(System system)
Get electrode names for a standard montage.