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
156 double dRotation)
157{
158 m_pUi->m_qLineEdit_moveResult->setText(QString::number(dMovement * 1000, 'f', 2) + QString(" mm"));
159 m_pUi->m_qLineEdit_rotResult->setText(QString::number(dRotation, 'f', 2) + QString(" °"));
160
161 if (dMovement * 1000 > m_pUi->m_doubleSpinBox_moveThreshold->value() || dRotation > m_pUi->m_doubleSpinBox_rotThreshold->value()) {
162 m_pUi->m_label_movementFeedback->setText("Big");
163 m_pUi->m_label_movementFeedback->setStyleSheet("QLabel { background-color : red;}");
164 } else {
165 m_pUi->m_label_movementFeedback->setText("Small");
166 m_pUi->m_label_movementFeedback->setStyleSheet("QLabel { background-color : green;}");
167 }
168}
169
170//=============================================================================================================
171
173{
174 return m_pUi->m_checkBox_useSSP->isChecked();
175}
176
177//=============================================================================================================
178
180{
181 return m_pUi->m_checkBox_useComp->isChecked();
182}
183
184//=============================================================================================================
185
187{
188 return m_pUi->m_doubleSpinBox_maxHPIContinousDist->value();
189}
190
191//=============================================================================================================
192
194{
195 return m_pUi->m_doubleSpinBox_moveThreshold->value();
196}
197
198//=============================================================================================================
199
201{
202 return m_pUi->m_doubleSpinBox_rotThreshold->value();
203}
204
205//=============================================================================================================
206
208{
209 return m_pUi->m_checkBox_continousHPI->isChecked();
210}
211
212//=============================================================================================================
213
215{
216 return m_pUi->m_spinBox_samplesToFit->value();
217}
218
219//=============================================================================================================
220
222{
223 if (m_sSettingsPath.isEmpty()) {
224 return;
225 }
226
227 QSettings settings("MNECPP");
228
229 settings.setValue(m_sSettingsPath + QString("/HpiSettingsView/coilFreqs"),
230 QVariant::fromValue(m_vCoilFreqs));
231
232 settings.setValue(m_sSettingsPath + QString("/HpiSettingsView/useSSP"),
233 QVariant::fromValue(m_pUi->m_checkBox_useSSP->isChecked()));
234
235 settings.setValue(m_sSettingsPath + QString("/HpiSettingsView/useCOMP"),
236 QVariant::fromValue(m_pUi->m_checkBox_useComp->isChecked()));
237
238 settings.setValue(m_sSettingsPath + QString("/HpiSettingsView/continousHPI"),
239 QVariant::fromValue(m_pUi->m_checkBox_continousHPI->isChecked()));
240
241 settings.setValue(m_sSettingsPath + QString("/HpiSettingsView/maxError"),
242 QVariant::fromValue(m_pUi->m_doubleSpinBox_maxHPIContinousDist->value()));
243
244 settings.setValue(m_sSettingsPath + QString("/HpiSettingsView/fittingWindowSize"),
245 QVariant::fromValue(m_pUi->m_spinBox_samplesToFit->value()));
246}
247
248//=============================================================================================================
249
251{
252 if (m_sSettingsPath.isEmpty()) {
253 return;
254 }
255
256 QSettings settings("MNECPP");
257 QVariant defaultData;
258
259 defaultData.setValue(m_vCoilFreqs);
260 m_vCoilFreqs = settings.value(m_sSettingsPath + QString("/HpiSettingsView/coilFreqs"), defaultData).value<QVector<int>>();
262
263 m_pUi->m_checkBox_useSSP->setChecked(settings.value(m_sSettingsPath + QString("/HpiSettingsView/useSSP"), false).toBool());
264 m_pUi->m_checkBox_useComp->setChecked(settings.value(m_sSettingsPath + QString("/HpiSettingsView/useCOMP"), false).toBool());
265 m_pUi->m_checkBox_continousHPI->setChecked(settings.value(m_sSettingsPath + QString("/HpiSettingsView/continousHPI"), false).toBool());
266 m_pUi->m_doubleSpinBox_maxHPIContinousDist->setValue(settings.value(m_sSettingsPath + QString("/HpiSettingsView/maxError"), 10.0).toDouble());
267 m_pUi->m_spinBox_samplesToFit->setValue(settings.value(m_sSettingsPath + QString("/HpiSettingsView/fittingWindowSize"), 300).toInt());
268}
269
270//=============================================================================================================
271
273{
274 switch (mode) {
276 break;
277 default: // default is research mode
278 break;
279 }
280}
281
282//=============================================================================================================
283
285{
286 switch (mode) {
288 break;
289 default: // default is realtime mode
290 break;
291 }
292}
293
294//=============================================================================================================
295
297{
298 //Get file location
299 QString fileName_HPI = QFileDialog::getOpenFileName(this,
300 tr("Open digitizer file"),
301 "",
302 tr("Fiff file (*.fif)"));
303
304 if (!fileName_HPI.isEmpty()) {
305 m_pUi->m_lineEdit_filePath->setText(fileName_HPI);
306 }
307
308 //Load Polhemus file
309 if (!fileName_HPI.isEmpty()) {
310 fileName_HPI = fileName_HPI.trimmed();
311 QFileInfo checkFile(fileName_HPI);
312
313 if (checkFile.exists() && checkFile.isFile()) {
314 // Stop cont HPI first
315 m_pUi->m_checkBox_continousHPI->setChecked(false);
316 emit digitizersChanged(readDigitizersFromFile(fileName_HPI), fileName_HPI);
317 } else {
318 QMessageBox msgBox;
319 msgBox.setText("File could not be loaded!");
320 msgBox.exec();
321 return;
322 }
323 }
324}
325
326//=============================================================================================================
327
329 int col)
330{
331 if (col != 1 || row >= m_vCoilFreqs.size()) {
332 return;
333 }
334
335 if (QTableWidgetItem* pItem = m_pUi->m_tableWidget_Frequencies->item(row, col)) {
336 if (pItem->text() == "none") {
337 m_vCoilFreqs[row] = -1;
338 } else {
339 m_vCoilFreqs[row] = pItem->text().toInt();
340 }
341
343 }
344}
345
346//=============================================================================================================
347
349{
350 if (m_pUi->m_tableWidget_Frequencies->rowCount() + 1 > m_pUi->m_label_numberLoadedCoils->text().toInt()) {
351 QMessageBox msgBox;
352 msgBox.setText("Cannot add more HPI coils. Not enough digitzed HPI coils loaded.");
353 msgBox.exec();
354 return;
355 }
356
357 // Add column 0 in freq table widget
358 m_pUi->m_tableWidget_Frequencies->insertRow(m_pUi->m_tableWidget_Frequencies->rowCount());
359 QTableWidgetItem* pTableItemA = new QTableWidgetItem(QString::number(m_pUi->m_tableWidget_Frequencies->rowCount()));
360 pTableItemA->setFlags(Qt::ItemIsEnabled);
361 m_pUi->m_tableWidget_Frequencies->setItem(m_pUi->m_tableWidget_Frequencies->rowCount() - 1,
362 0,
363 pTableItemA);
364
365 // Add column 1 in freq table widget
366 if (m_vCoilFreqs.size() >= m_pUi->m_tableWidget_Frequencies->rowCount()) {
367 m_pUi->m_tableWidget_Frequencies->setItem(m_pUi->m_tableWidget_Frequencies->rowCount() - 1,
368 1,
369 new QTableWidgetItem(QString::number(m_vCoilFreqs.at(m_pUi->m_tableWidget_Frequencies->rowCount() - 1))));
370 } else {
371 m_pUi->m_tableWidget_Frequencies->setItem(m_pUi->m_tableWidget_Frequencies->rowCount() - 1,
372 1,
373 new QTableWidgetItem("none"));
374 m_vCoilFreqs.append(-1);
375 }
376
377 // Add column 0 in error table widget (coil number)
378 m_pUi->m_tableWidget_results->insertRow(m_pUi->m_tableWidget_results->rowCount());
379 QTableWidgetItem* pTableItemB = new QTableWidgetItem(QString::number(m_pUi->m_tableWidget_Frequencies->rowCount()));
380 pTableItemB->setFlags(Qt::ItemIsEnabled);
381 m_pUi->m_tableWidget_results->setItem(m_pUi->m_tableWidget_results->rowCount() - 1,
382 0,
383 pTableItemB);
384
385 // Add column 1 in error table widget (error)
386 QTableWidgetItem* pTableItemC = new QTableWidgetItem("0mm");
387 pTableItemC->setFlags(Qt::ItemIsEnabled);
388 m_pUi->m_tableWidget_results->setItem(m_pUi->m_tableWidget_results->rowCount() - 1,
389 1,
390 pTableItemC);
391
392 // Add column 2 in error table widget (gof)
393 QTableWidgetItem* pTableItemD = new QTableWidgetItem("00.00");
394 pTableItemD->setFlags(Qt::ItemIsEnabled);
395 m_pUi->m_tableWidget_results->setItem(m_pUi->m_tableWidget_results->rowCount() - 1,
396 2,
397 pTableItemD);
398
400}
401
402//=============================================================================================================
403
405{
406 int row = m_pUi->m_tableWidget_Frequencies->currentRow();
407
408 if (row >= 0 && row < m_vCoilFreqs.size()) {
409 m_vCoilFreqs.remove(row);
410 m_pUi->m_tableWidget_Frequencies->removeRow(row);
411
412 for (int i = 0; i < m_pUi->m_tableWidget_Frequencies->rowCount(); ++i) {
413 m_pUi->m_tableWidget_Frequencies->item(i, 0)->setText(QString::number(i + 1));
414 }
415
416 m_pUi->m_tableWidget_results->removeRow(row);
417
418 for (int i = 0; i < m_pUi->m_tableWidget_results->rowCount(); ++i) {
419 m_pUi->m_tableWidget_results->item(i, 0)->setText(QString::number(i + 1));
420 }
421
423 }
424}
425
426//=============================================================================================================
427
428QList<FiffDigPoint> HpiSettingsView::readDigitizersFromFile(const QString& fileName)
429{
430 clearCoilGUI();
431
432 QFile t_fileDig(fileName);
433 FiffDigPointSet t_digSet(t_fileDig);
434 updateDigitizerInfoGUI(t_digSet);
435
436 return t_digSet.getList();
437}
438
439//=============================================================================================================
440
441void HpiSettingsView::newDigitizerList(QList<FIFFLIB::FiffDigPoint> pointList)
442{
443 clearCoilGUI();
444
445 FiffDigPointSet t_digSet(pointList);
446 updateDigitizerInfoGUI(t_digSet);
447}
448
449//=============================================================================================================
450
452{
453 qint16 numHPI = 0;
454 qint16 numFiducials = 0;
455 qint16 numEEG = 0;
456 qint16 numAdditional = 0;
457
458 for (int i = 0; i < digSet.size(); ++i) {
459 switch (digSet[i].kind) {
460 case FIFFV_POINT_HPI:
461 if (m_vCoilFreqs.size() <= numHPI) {
462 m_vCoilFreqs.append(-1);
463 }
464 numHPI++;
465 break;
467 numFiducials++;
468 break;
469 case FIFFV_POINT_EEG:
470 numEEG++;
471 break;
473 numAdditional++;
474 break;
475 }
476 }
477
478 //Set loaded number of digitizers
479 m_pUi->m_label_numberLoadedCoils->setNum(numHPI);
480 m_pUi->m_label_numberLoadedFiducials->setNum(numFiducials);
481 m_pUi->m_label_numberLoadedEEG->setNum(numEEG);
482 m_pUi->m_label_numberLoadedAdditional->setNum(numAdditional);
483
484 m_vCoilFreqs.resize(numHPI);
486 setupCoilPresets(numHPI);
487
488 // Make sure that the stored coil freqs always match the number of loaded ones
489 m_vCoilFreqs.resize(numHPI);
491}
492
493//=============================================================================================================
494
496{
497 for (int iCoilFreq : m_vCoilFreqs) {
498 addCoilFreqToGUI(iCoilFreq);
500 }
501}
502
503//=============================================================================================================
504
506{
507 // Add column 0 in freq table widget
508 m_pUi->m_tableWidget_Frequencies->insertRow(m_pUi->m_tableWidget_Frequencies->rowCount());
509 QTableWidgetItem* pTableItemA = new QTableWidgetItem(QString::number(m_pUi->m_tableWidget_Frequencies->rowCount()));
510 pTableItemA->setFlags(Qt::ItemIsEnabled);
511 m_pUi->m_tableWidget_Frequencies->setItem(m_pUi->m_tableWidget_Frequencies->rowCount() - 1,
512 0,
513 pTableItemA);
514
515 // Add column 1 in freq table widget
516 m_pUi->m_tableWidget_Frequencies->setItem(m_pUi->m_tableWidget_Frequencies->rowCount() - 1,
517 1,
518 new QTableWidgetItem(QString::number(iCoilFreq)));
519}
520
521//=============================================================================================================
522
524{
525 // Add column 0 in error table widget
526 m_pUi->m_tableWidget_results->insertRow(m_pUi->m_tableWidget_results->rowCount());
527 QTableWidgetItem* pTableItemB = new QTableWidgetItem(QString::number(m_pUi->m_tableWidget_Frequencies->rowCount()));
528 pTableItemB->setFlags(Qt::ItemIsEnabled);
529 m_pUi->m_tableWidget_results->setItem(m_pUi->m_tableWidget_results->rowCount() - 1,
530 0,
531 pTableItemB);
532
533 // Add column 1 in error table widget
534 QTableWidgetItem* pTableItemC = new QTableWidgetItem("0mm");
535 pTableItemC->setFlags(Qt::ItemIsEnabled);
536 m_pUi->m_tableWidget_results->setItem(m_pUi->m_tableWidget_results->rowCount() - 1,
537 1,
538 pTableItemC);
539
540 // Add column 2 in error table widget
541 QTableWidgetItem* pTableItemD = new QTableWidgetItem("00.00%");
542 pTableItemD->setFlags(Qt::ItemIsEnabled);
543 m_pUi->m_tableWidget_results->setItem(m_pUi->m_tableWidget_results->rowCount() - 1,
544 2,
545 pTableItemD);
546}
547
548//=============================================================================================================
549
551{
552 m_pUi->m_tableWidget_Frequencies->clear();
553 m_pUi->m_tableWidget_Frequencies->setRowCount(0);
554 m_pUi->m_tableWidget_Frequencies->setHorizontalHeaderItem(0, new QTableWidgetItem("#Coil"));
555 m_pUi->m_tableWidget_Frequencies->setHorizontalHeaderItem(1, new QTableWidgetItem("Frequency (Hz)"));
556
557 m_pUi->m_tableWidget_results->clear();
558 m_pUi->m_tableWidget_results->setRowCount(0);
559 m_pUi->m_tableWidget_results->setHorizontalHeaderItem(0, new QTableWidgetItem("#Coil"));
560 m_pUi->m_tableWidget_results->setHorizontalHeaderItem(1, new QTableWidgetItem("Error"));
561 m_pUi->m_tableWidget_results->setHorizontalHeaderItem(2, new QTableWidgetItem("GoF"));
562}
563
564//=============================================================================================================
565
569
570//==============================================void populateCoilGUI(int iNumCoils);===============================================================
571
572void HpiSettingsView::loadCoilPresets(const QString& sFilePath)
573{
574 QFile inFile(sFilePath);
575 if (inFile.open(QIODevice::ReadOnly)) {
576 QByteArray inArray = inFile.readAll();
577 m_CoilPresets = QJsonDocument::fromJson(inArray);
578 }
579}
580
581//=============================================================================================================
582
584{
585 if (!m_CoilPresets.isNull()) {
586 QJsonArray presetData = m_CoilPresets.object()[QString::number(iNumCoils)].toArray();
587 populatePresetGUI(presetData);
588 }
589}
590
591//=============================================================================================================
592
593void HpiSettingsView::populatePresetGUI(const QJsonArray& presetData)
594{
595 m_pUi->comboBox_coilPreset->clear();
596 m_pUi->comboBox_coilPreset->addItem("Load preset");
597
598 for (const auto& entry : presetData) {
599 QString name = entry.toObject()["name"].toString();
600 QVector<int> vecCoils;
601
602 for (const auto& coil : entry.toObject()["coils"].toArray()) {
603 vecCoils.append(coil.toInt());
604 }
605
606 m_pUi->comboBox_coilPreset->addItem(name, QVariant::fromValue(vecCoils));
607 }
608}
609
610//=============================================================================================================
611
612void HpiSettingsView::selectCoilPreset(int iCoilPresetIndex)
613{
614 if (iCoilPresetIndex < (m_pUi->comboBox_coilPreset->count())) {
615 auto coilFreqData = m_pUi->comboBox_coilPreset->itemData(iCoilPresetIndex);
616 if (!coilFreqData.isNull() && coilFreqData.canConvert<QVector<int>>()) {
617 m_vCoilFreqs = coilFreqData.value<QVector<int>>();
618 clearCoilGUI();
620
622 }
623 }
624}
#define FIFFV_POINT_EXTRA
#define FIFFV_POINT_CARDINAL
#define FIFFV_POINT_EEG
#define FIFFV_POINT_HPI
Container for the FIFF_DIG_POINT records of a measurement (a parsed FIFFB_ISOTRAK block).
Continuous HPI head-position-indicator configuration panel.
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()