v2.0.0
Loading...
Searching...
No Matches
hpisettingsview.cpp
Go to the documentation of this file.
1//=============================================================================================================
17
18//=============================================================================================================
19// INCLUDES
20//=============================================================================================================
21
22#include "hpisettingsview.h"
23
24#include "ui_hpisettingsview.h"
25
27#include <iostream>
28
29//=============================================================================================================
30// QT INCLUDES
31//=============================================================================================================
32
33#include <QFileInfo>
34#include <QFileDialog>
35#include <QMessageBox>
36#include <QSettings>
37#include <QJsonObject>
38#include <QJsonArray>
39
40//=============================================================================================================
41// EIGEN INCLUDES
42//=============================================================================================================
43
44//=============================================================================================================
45// USED NAMESPACES
46//=============================================================================================================
47
48using namespace DISPLIB;
49using namespace FIFFLIB;
50
51//=============================================================================================================
52// DEFINE MEMBER METHODS
53//=============================================================================================================
54
55HpiSettingsView::HpiSettingsView(const QString& sSettingsPath,
56 QWidget *parent,
57 Qt::WindowFlags f)
58: AbstractView(parent, f)
59, m_pUi(new Ui::HpiSettingsViewWidget)
60{
61 m_sSettingsPath = sSettingsPath;
62 m_pUi->setupUi(this);
63
64 connect(m_pUi->m_pushButton_loadDigitizers, &QPushButton::released,
66 connect(m_pUi->m_pushButton_doFreqOrder, &QPushButton::clicked,
68 connect(m_pUi->m_pushButton_doSingleFit, &QPushButton::clicked,
70 connect(m_pUi->m_tableWidget_Frequencies, &QTableWidget::cellChanged,
72 connect(m_pUi->m_pushButton_addCoil, &QPushButton::clicked,
74 connect(m_pUi->m_pushButton_removeCoil, &QPushButton::clicked,
76 connect(m_pUi->m_checkBox_useSSP, &QCheckBox::clicked,
78 connect(m_pUi->m_checkBox_useComp, &QCheckBox::clicked,
80 connect(m_pUi->m_checkBox_continousHPI, &QCheckBox::clicked,
82 connect(m_pUi->m_spinBox_samplesToFit, QOverload<int>::of(&QSpinBox::valueChanged),
84 connect(m_pUi->m_doubleSpinBox_maxHPIContinousDist, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
86 connect(m_pUi->m_doubleSpinBox_moveThreshold, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
88 connect(m_pUi->m_doubleSpinBox_rotThreshold, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
90 connect(m_pUi->comboBox_coilPreset, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
92
93 //Init coil freqs
94 m_vCoilFreqs << 293 << 307 << 314 << 321;
95
97}
98
99//=============================================================================================================
100
102{
103 saveSettings();
104
105 delete m_pUi;
106}
107
108//=============================================================================================================
109
110void HpiSettingsView::setErrorLabels(const QVector<double>& vError,
111 const double dMeanErrorDist)
112{
113 //Update eror labels and change from m to mm
114 QString sGof("0mm");
115
116 for(int i = 0; i < vError.size(); ++i) {
117 if(i < m_pUi->m_tableWidget_results->rowCount()) {
118 sGof = QString::number(vError[i]*1000,'f',2)+QString(" mm");
119 m_pUi->m_tableWidget_results->item(i, 1)->setText(sGof);
120 }
121 }
122
123 m_pUi->m_label_averagedFitError->setText(QString::number(dMeanErrorDist*1000,'f',2)+QString(" mm"));
124
125 //Update good/bad fit label
126 if(dMeanErrorDist*1000 > m_pUi->m_doubleSpinBox_maxHPIContinousDist->value()) {
127 m_pUi->m_label_fitFeedback->setText("Last fit: Bad");
128 m_pUi->m_label_fitFeedback->setStyleSheet("QLabel { background-color : red;}");
129 } else {
130 m_pUi->m_label_fitFeedback->setText("Last fit: Good");
131 m_pUi->m_label_fitFeedback->setStyleSheet("QLabel { background-color : green;}");
132 }
133}
134
135//=============================================================================================================
136
137void HpiSettingsView::setGoFLabels(const Eigen::VectorXd & vGoF,
138 const double dMeanGof)
139{
140 //Update gof labels and change to %
141 QString sGof("00.00");
142
143 for(int i = 0; i < vGoF.size(); ++i) {
144 if(i < m_pUi->m_tableWidget_results->rowCount()) {
145 sGof = QString::number(vGoF[i]*100,'f',2)+QString(" %");
146 m_pUi->m_tableWidget_results->item(i, 2)->setText(sGof);
147 }
148 }
149
150 m_pUi->m_average_gof_set->setText(QString::number(dMeanGof*100,'f',2)+QString(" %"));
151
152}
153
154//=========================================================================================================
155
157 double dRotation)
158{
159 m_pUi->m_qLineEdit_moveResult->setText(QString::number(dMovement*1000,'f',2) + QString(" mm"));
160 m_pUi->m_qLineEdit_rotResult->setText(QString::number(dRotation,'f',2) + QString(" °"));
161
162 if(dMovement*1000 > m_pUi->m_doubleSpinBox_moveThreshold->value() || dRotation > m_pUi->m_doubleSpinBox_rotThreshold->value()) {
163 m_pUi->m_label_movementFeedback->setText("Big");
164 m_pUi->m_label_movementFeedback->setStyleSheet("QLabel { background-color : red;}");
165 } else {
166 m_pUi->m_label_movementFeedback->setText("Small");
167 m_pUi->m_label_movementFeedback->setStyleSheet("QLabel { background-color : green;}");
168 }
169}
170
171//=============================================================================================================
172
174{
175 return m_pUi->m_checkBox_useSSP->isChecked();
176}
177
178//=============================================================================================================
179
181{
182 return m_pUi->m_checkBox_useComp->isChecked();
183}
184
185//=============================================================================================================
186
188{
189 return m_pUi->m_doubleSpinBox_maxHPIContinousDist->value();
190}
191
192//=============================================================================================================
193
195{
196 return m_pUi->m_doubleSpinBox_moveThreshold->value();
197}
198
199//=============================================================================================================
200
202{
203 return m_pUi->m_doubleSpinBox_rotThreshold->value();
204}
205
206//=============================================================================================================
207
209{
210 return m_pUi->m_checkBox_continousHPI->isChecked();
211}
212
213//=============================================================================================================
214
216{
217 return m_pUi->m_spinBox_samplesToFit->value();
218}
219
220//=============================================================================================================
221
223{
224 if(m_sSettingsPath.isEmpty()) {
225 return;
226 }
227
228 QSettings settings("MNECPP");
229
230 settings.setValue(m_sSettingsPath + QString("/HpiSettingsView/coilFreqs"),
231 QVariant::fromValue(m_vCoilFreqs));
232
233 settings.setValue(m_sSettingsPath + QString("/HpiSettingsView/useSSP"),
234 QVariant::fromValue(m_pUi->m_checkBox_useSSP->isChecked()));
235
236 settings.setValue(m_sSettingsPath + QString("/HpiSettingsView/useCOMP"),
237 QVariant::fromValue(m_pUi->m_checkBox_useComp->isChecked()));
238
239 settings.setValue(m_sSettingsPath + QString("/HpiSettingsView/continousHPI"),\
240 QVariant::fromValue(m_pUi->m_checkBox_continousHPI->isChecked()));
241
242 settings.setValue(m_sSettingsPath + QString("/HpiSettingsView/maxError"),
243 QVariant::fromValue(m_pUi->m_doubleSpinBox_maxHPIContinousDist->value()));
244
245 settings.setValue(m_sSettingsPath + QString("/HpiSettingsView/fittingWindowSize"),
246 QVariant::fromValue(m_pUi->m_spinBox_samplesToFit->value()));
247}
248
249//=============================================================================================================
250
252{
253 if(m_sSettingsPath.isEmpty()) {
254 return;
255 }
256
257 QSettings settings("MNECPP");
258 QVariant defaultData;
259
260 defaultData.setValue(m_vCoilFreqs);
261 m_vCoilFreqs = settings.value(m_sSettingsPath + QString("/HpiSettingsView/coilFreqs"), defaultData).value<QVector<int> >();
263
264 m_pUi->m_checkBox_useSSP->setChecked(settings.value(m_sSettingsPath + QString("/HpiSettingsView/useSSP"), false).toBool());
265 m_pUi->m_checkBox_useComp->setChecked(settings.value(m_sSettingsPath + QString("/HpiSettingsView/useCOMP"), false).toBool());
266 m_pUi->m_checkBox_continousHPI->setChecked(settings.value(m_sSettingsPath + QString("/HpiSettingsView/continousHPI"), false).toBool());
267 m_pUi->m_doubleSpinBox_maxHPIContinousDist->setValue(settings.value(m_sSettingsPath + QString("/HpiSettingsView/maxError"), 10.0).toDouble());
268 m_pUi->m_spinBox_samplesToFit->setValue(settings.value(m_sSettingsPath + QString("/HpiSettingsView/fittingWindowSize"), 300).toInt());
269}
270
271//=============================================================================================================
272
274{
275 switch(mode) {
277 break;
278 default: // default is research mode
279 break;
280 }
281}
282
283//=============================================================================================================
284
286{
287 switch(mode) {
289 break;
290 default: // default is realtime mode
291 break;
292 }
293}
294
295//=============================================================================================================
296
298{
299 //Get file location
300 QString fileName_HPI = QFileDialog::getOpenFileName(this,
301 tr("Open digitizer file"),
302 "",
303 tr("Fiff file (*.fif)"));
304
305 if(!fileName_HPI.isEmpty()) {
306 m_pUi->m_lineEdit_filePath->setText(fileName_HPI);
307 }
308
309 //Load Polhemus file
310 if (!fileName_HPI.isEmpty()) {
311 fileName_HPI = fileName_HPI.trimmed();
312 QFileInfo checkFile(fileName_HPI);
313
314 if (checkFile.exists() && checkFile.isFile()) {
315 // Stop cont HPI first
316 m_pUi->m_checkBox_continousHPI->setChecked(false);
317 emit digitizersChanged(readDigitizersFromFile(fileName_HPI), fileName_HPI);
318 } else {
319 QMessageBox msgBox;
320 msgBox.setText("File could not be loaded!");
321 msgBox.exec();
322 return;
323 }
324 }
325}
326
327//=============================================================================================================
328
330 int col)
331{
332 if(col != 1 || row >= m_vCoilFreqs.size()) {
333 return;
334 }
335
336 if(QTableWidgetItem *pItem = m_pUi->m_tableWidget_Frequencies->item(row, col)) {
337 if(pItem->text() == "none") {
338 m_vCoilFreqs[row] = -1;
339 } else {
340 m_vCoilFreqs[row] = pItem->text().toInt();
341 }
342
344 }
345}
346
347//=============================================================================================================
348
350{
351 if(m_pUi->m_tableWidget_Frequencies->rowCount() + 1 > m_pUi->m_label_numberLoadedCoils->text().toInt()) {
352 QMessageBox msgBox;
353 msgBox.setText("Cannot add more HPI coils. Not enough digitzed HPI coils loaded.");
354 msgBox.exec();
355 return;
356 }
357
358 // Add column 0 in freq table widget
359 m_pUi->m_tableWidget_Frequencies->insertRow(m_pUi->m_tableWidget_Frequencies->rowCount());
360 QTableWidgetItem* pTableItemA = new QTableWidgetItem(QString::number(m_pUi->m_tableWidget_Frequencies->rowCount()));
361 pTableItemA->setFlags(Qt::ItemIsEnabled);
362 m_pUi->m_tableWidget_Frequencies->setItem(m_pUi->m_tableWidget_Frequencies->rowCount()-1,
363 0,
364 pTableItemA);
365
366 // Add column 1 in freq table widget
367 if(m_vCoilFreqs.size() >= m_pUi->m_tableWidget_Frequencies->rowCount()) {
368 m_pUi->m_tableWidget_Frequencies->setItem(m_pUi->m_tableWidget_Frequencies->rowCount()-1,
369 1,
370 new QTableWidgetItem(QString::number(m_vCoilFreqs.at(m_pUi->m_tableWidget_Frequencies->rowCount()-1))));
371 } else {
372 m_pUi->m_tableWidget_Frequencies->setItem(m_pUi->m_tableWidget_Frequencies->rowCount()-1,
373 1,
374 new QTableWidgetItem("none"));
375 m_vCoilFreqs.append(-1);
376 }
377
378 // Add column 0 in error table widget (coil number)
379 m_pUi->m_tableWidget_results->insertRow(m_pUi->m_tableWidget_results->rowCount());
380 QTableWidgetItem* pTableItemB = new QTableWidgetItem(QString::number(m_pUi->m_tableWidget_Frequencies->rowCount()));
381 pTableItemB->setFlags(Qt::ItemIsEnabled);
382 m_pUi->m_tableWidget_results->setItem(m_pUi->m_tableWidget_results->rowCount()-1,
383 0,
384 pTableItemB);
385
386 // Add column 1 in error table widget (error)
387 QTableWidgetItem* pTableItemC = new QTableWidgetItem("0mm");
388 pTableItemC->setFlags(Qt::ItemIsEnabled);
389 m_pUi->m_tableWidget_results->setItem(m_pUi->m_tableWidget_results->rowCount()-1,
390 1,
391 pTableItemC);
392
393 // Add column 2 in error table widget (gof)
394 QTableWidgetItem* pTableItemD = new QTableWidgetItem("00.00");
395 pTableItemD->setFlags(Qt::ItemIsEnabled);
396 m_pUi->m_tableWidget_results->setItem(m_pUi->m_tableWidget_results->rowCount()-1,
397 2,
398 pTableItemD);
399
401}
402
403//=============================================================================================================
404
406{
407 int row = m_pUi->m_tableWidget_Frequencies->currentRow();
408
409 if(row >= 0 && row < m_vCoilFreqs.size()) {
410 m_vCoilFreqs.remove(row);
411 m_pUi->m_tableWidget_Frequencies->removeRow(row);
412
413 for (int i = 0; i < m_pUi->m_tableWidget_Frequencies->rowCount(); ++i) {
414 m_pUi->m_tableWidget_Frequencies->item(i, 0)->setText(QString::number(i+1));
415 }
416
417 m_pUi->m_tableWidget_results->removeRow(row);
418
419 for (int i = 0; i < m_pUi->m_tableWidget_results->rowCount(); ++i) {
420 m_pUi->m_tableWidget_results->item(i, 0)->setText(QString::number(i+1));
421 }
422
424 }
425}
426
427//=============================================================================================================
428
429QList<FiffDigPoint> HpiSettingsView::readDigitizersFromFile(const QString& fileName)
430{
431 clearCoilGUI();
432
433 QFile t_fileDig(fileName);
434 FiffDigPointSet t_digSet(t_fileDig);
435 updateDigitizerInfoGUI(t_digSet);
436
437 return t_digSet.getList();
438}
439
440//=============================================================================================================
441
442void HpiSettingsView::newDigitizerList(QList<FIFFLIB::FiffDigPoint> pointList)
443{
444 clearCoilGUI();
445
446 FiffDigPointSet t_digSet(pointList);
447 updateDigitizerInfoGUI(t_digSet);
448}
449
450//=============================================================================================================
451
453{
454 qint16 numHPI = 0;
455 qint16 numFiducials = 0;
456 qint16 numEEG = 0;
457 qint16 numAdditional = 0;
458
459 for(int i = 0; i < digSet.size(); ++i) {
460 switch(digSet[i].kind) {
461 case FIFFV_POINT_HPI:
462 if(m_vCoilFreqs.size() <= numHPI) {
463 m_vCoilFreqs.append(-1);
464 }
465 numHPI++;
466 break;
468 numFiducials++;
469 break;
470 case FIFFV_POINT_EEG:
471 numEEG++;
472 break;
474 numAdditional++;
475 break;
476 }
477 }
478
479 //Set loaded number of digitizers
480 m_pUi->m_label_numberLoadedCoils->setNum(numHPI);
481 m_pUi->m_label_numberLoadedFiducials->setNum(numFiducials);
482 m_pUi->m_label_numberLoadedEEG->setNum(numEEG);
483 m_pUi->m_label_numberLoadedAdditional->setNum(numAdditional);
484
485 m_vCoilFreqs.resize(numHPI);
487 setupCoilPresets(numHPI);
488
489 // Make sure that the stored coil freqs always match the number of loaded ones
490 m_vCoilFreqs.resize(numHPI);
492}
493
494//=============================================================================================================
495
497{
498 for(int iCoilFreq : m_vCoilFreqs){
499 addCoilFreqToGUI(iCoilFreq);
501 }
502}
503
504//=============================================================================================================
505
507{
508 // Add column 0 in freq table widget
509 m_pUi->m_tableWidget_Frequencies->insertRow(m_pUi->m_tableWidget_Frequencies->rowCount());
510 QTableWidgetItem* pTableItemA = new QTableWidgetItem(QString::number(m_pUi->m_tableWidget_Frequencies->rowCount()));
511 pTableItemA->setFlags(Qt::ItemIsEnabled);
512 m_pUi->m_tableWidget_Frequencies->setItem(m_pUi->m_tableWidget_Frequencies->rowCount()-1,
513 0,
514 pTableItemA);
515
516 // Add column 1 in freq table widget
517 m_pUi->m_tableWidget_Frequencies->setItem(m_pUi->m_tableWidget_Frequencies->rowCount()-1,
518 1,
519 new QTableWidgetItem(QString::number(iCoilFreq)));
520}
521
522//=============================================================================================================
523
525{
526 // Add column 0 in error table widget
527 m_pUi->m_tableWidget_results->insertRow(m_pUi->m_tableWidget_results->rowCount());
528 QTableWidgetItem* pTableItemB = new QTableWidgetItem(QString::number(m_pUi->m_tableWidget_Frequencies->rowCount()));
529 pTableItemB->setFlags(Qt::ItemIsEnabled);
530 m_pUi->m_tableWidget_results->setItem(m_pUi->m_tableWidget_results->rowCount()-1,
531 0,
532 pTableItemB);
533
534 // Add column 1 in error table widget
535 QTableWidgetItem* pTableItemC = new QTableWidgetItem("0mm");
536 pTableItemC->setFlags(Qt::ItemIsEnabled);
537 m_pUi->m_tableWidget_results->setItem(m_pUi->m_tableWidget_results->rowCount()-1,
538 1,
539 pTableItemC);
540
541 // Add column 2 in error table widget
542 QTableWidgetItem* pTableItemD = new QTableWidgetItem("00.00%");
543 pTableItemD->setFlags(Qt::ItemIsEnabled);
544 m_pUi->m_tableWidget_results->setItem(m_pUi->m_tableWidget_results->rowCount()-1,
545 2,
546 pTableItemD);
547}
548
549//=============================================================================================================
550
552{
553 m_pUi->m_tableWidget_Frequencies->clear();
554 m_pUi->m_tableWidget_Frequencies->setRowCount(0);
555 m_pUi->m_tableWidget_Frequencies->setHorizontalHeaderItem(0, new QTableWidgetItem("#Coil"));
556 m_pUi->m_tableWidget_Frequencies->setHorizontalHeaderItem(1, new QTableWidgetItem("Frequency (Hz)"));
557
558 m_pUi->m_tableWidget_results->clear();
559 m_pUi->m_tableWidget_results->setRowCount(0);
560 m_pUi->m_tableWidget_results->setHorizontalHeaderItem(0, new QTableWidgetItem("#Coil"));
561 m_pUi->m_tableWidget_results->setHorizontalHeaderItem(1, new QTableWidgetItem("Error"));
562 m_pUi->m_tableWidget_results->setHorizontalHeaderItem(2, new QTableWidgetItem("GoF"));
563
564}
565
566//=============================================================================================================
567
569{
570
571}
572
573//==============================================void populateCoilGUI(int iNumCoils);===============================================================
574
575void HpiSettingsView::loadCoilPresets(const QString &sFilePath)
576{
577 QFile inFile(sFilePath);
578 if (inFile.open(QIODevice::ReadOnly)){
579 QByteArray inArray = inFile.readAll();
580 m_CoilPresets = QJsonDocument::fromJson(inArray);
581 }
582}
583
584//=============================================================================================================
585
587{
588 if(!m_CoilPresets.isNull()){
589 QJsonArray presetData = m_CoilPresets.object()[QString::number(iNumCoils)].toArray();
590 populatePresetGUI(presetData);
591 }
592}
593
594//=============================================================================================================
595
596void HpiSettingsView::populatePresetGUI(const QJsonArray& presetData)
597{
598 m_pUi->comboBox_coilPreset->clear();
599 m_pUi->comboBox_coilPreset->addItem("Load preset");
600
601 for(const auto& entry : presetData){
602 QString name = entry.toObject()["name"].toString();
603 QVector<int> data;
604
605 for (const auto& coil : entry.toObject()["coils"].toArray()){
606 data.append(coil.toInt());
607 }
608
609 m_pUi->comboBox_coilPreset->addItem(name, QVariant::fromValue(data));
610 }
611}
612
613//=============================================================================================================
614
615void HpiSettingsView::selectCoilPreset(int iCoilPresetIndex)
616{
617 if (iCoilPresetIndex < (m_pUi->comboBox_coilPreset->count())){
618 auto coilFreqData = m_pUi->comboBox_coilPreset->itemData(iCoilPresetIndex);
619 if (!coilFreqData.isNull() && coilFreqData.canConvert<QVector<int>>()){
620 m_vCoilFreqs = coilFreqData.value<QVector<int>>();
621 clearCoilGUI();
623
625 }
626 }
627}
Continuous HPI head-position-indicator configuration panel.
Container for the FIFF_DIG_POINT records of a measurement (a parsed FIFFB_ISOTRAK block).
#define FIFFV_POINT_EXTRA
#define FIFFV_POINT_CARDINAL
#define FIFFV_POINT_EEG
#define FIFFV_POINT_HPI
FIFF file I/O, in-memory data structures and high-level readers/writers.
2-D display widgets and visualisation helpers (charts, topography, colour maps).
AbstractView(QWidget *parent=0, Qt::WindowFlags f=Qt::Widget)
void allowedRotationChanged(double dAllowedRotation)
void updateProcessingMode(ProcessingMode mode)
void sspStatusChanged(bool bChecked)
void updateDigitizerInfoGUI(const FIFFLIB::FiffDigPointSet &digSet)
void fittingWindowSizeChanged(int iFitsPerSecond)
void setMovementResults(double dMovement, double dRotation)
void loadCoilPresets(const QString &sFilePath)
void coilFrequenciesChanged(const QVector< int > &vCoilFreqs)
void newDigitizerList(QList< FIFFLIB::FiffDigPoint > pointList)
void addCoilFreqToGUI(int iCoilFreq)
void updateGuiMode(GuiMode mode)
void populatePresetGUI(const QJsonArray &presetData)
void setGoFLabels(const Eigen::VectorXd &vGoF, const double dMeanGof)
void compStatusChanged(bool bChecked)
void setupCoilPresets(int iNumCoils)
void onFrequencyCellChanged(int row, int col)
void setErrorLabels(const QVector< double > &vError, const double dMeanErrorDist)
void addCoilErrorToGUI()
addCoilErrorToGUI
HpiSettingsView(const QString &sSettingsPath="", QWidget *parent=0, Qt::WindowFlags f=Qt::Widget)
void allowedMovementChanged(double dAllowedMovement)
void allowedMeanErrorDistChanged(double dAllowedMeanErrorDist)
void selectCoilPreset(int iCoilPresetIndex)
Ui::HpiSettingsViewWidget * m_pUi
QList< FIFFLIB::FiffDigPoint > readDigitizersFromFile(const QString &fileName)
void digitizersChanged(const QList< FIFFLIB::FiffDigPoint > &lDigitzers, const QString &sFilePath)
void contHpiStatusChanged(bool bChecked)
Collection of FiffDigPoint records as parsed from a FIFFB_ISOTRAK block.
QList< FiffDigPoint > getList()