v2.0.0
Loading...
Searching...
No Matches
rtfiffrawview.cpp
Go to the documentation of this file.
1//=============================================================================================================
15
16//=============================================================================================================
17// INCLUDES
18//=============================================================================================================
19
20#include "rtfiffrawview.h"
21
24
25#include <dsp/filterkernel.h>
26#include <fiff/fiff_info.h>
27#include <fiff/fiff_explain.h>
28
29//=============================================================================================================
30// QT INCLUDES
31//=============================================================================================================
32
33#include <QGridLayout>
34#include <QHeaderView>
35#include <QTableView>
36#include <QMenu>
37#include <QSvgGenerator>
38#include <QSettings>
39#include <QScrollBar>
40#include <QMouseEvent>
41#include <QRhiWidget>
42
43
44//=============================================================================================================
45// USED NAMESPACES
46//=============================================================================================================
47
48using namespace DISPLIB;
49using namespace FIFFLIB;
50using namespace Eigen;
51using namespace RTPROCESSINGLIB;
52using namespace UTILSLIB;
53
54//=============================================================================================================
55// DEFINE MEMBER METHODS
56//=============================================================================================================
57
58RtFiffRawView::RtFiffRawView(const QString& sSettingsPath,
59 QWidget* parent,
60 Qt::WindowFlags f)
61: AbstractView(parent, f)
62, m_iT(10)
63, m_fSamplingRate(1024)
64, m_fZoomFactor(1.0f)
65, m_bHideBadChannels(false)
67, m_iClickPosX(0)
69{
70 m_sSettingsPath = sSettingsPath;
71 m_pTableView = new QTableView;
73
74 // Set layout
75 QVBoxLayout* neLayout = new QVBoxLayout(this);
76 neLayout->addWidget(m_pTableView);
77 neLayout->setContentsMargins(0, 0, 0, 0);
78 this->setLayout(neLayout);
79
81}
82
83//=============================================================================================================
84
89
90//=============================================================================================================
91
93{
94 if (m_pTableView) {
95 auto* rhiViewport = new QRhiWidget;
96#if defined(WASMBUILD) || defined(__EMSCRIPTEN__)
97 rhiViewport->setApi(QRhiWidget::Api::OpenGL);
98#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
99 rhiViewport->setApi(QRhiWidget::Api::Metal);
100#elif defined(Q_OS_WIN)
101 rhiViewport->setApi(QRhiWidget::Api::Direct3D11);
102#else
103 rhiViewport->setApi(QRhiWidget::Api::OpenGL);
104#endif
105 m_pTableView->setViewport(rhiViewport);
106
107 // Mouse moves drive the crosshair
108 rhiViewport->installEventFilter(this);
109 rhiViewport->setMouseTracking(true);
110 }
111}
112
113//=============================================================================================================
114
115void RtFiffRawView::setSettingsPath(const QString& sSettingsPath)
116{
117 m_sSettingsPath = sSettingsPath;
118 loadSettings();
119}
120
121//=============================================================================================================
122
123void RtFiffRawView::init(QSharedPointer<FIFFLIB::FiffInfo>& info)
124{
125 m_pFiffInfo = info;
127
128 //Init the model
129 m_pModel = new RtFiffRawViewModel(this);
130 m_pModel->setFiffInfo(m_pFiffInfo);
131 m_pModel->setSamplingInfo(m_fSamplingRate, m_iT, true);
134 connect(this, &RtFiffRawView::addSampleAsEvent,
135 m_pModel, &RtFiffRawViewModel::addEvent, Qt::UniqueConnection);
136
137 //Init bad channel list
138 m_qListBadChannels.clear();
139 for (int i = 0; i < m_pModel->rowCount(); i++) {
140 if (m_pModel->data(m_pModel->index(i, 2)).toBool()) {
142 }
143 }
144
145 //Init the delegate
147 m_pDelegate->initPainterPaths(m_pModel);
148
149 connect(this, &RtFiffRawView::markerMoved,
151
152 //Init the view
153 m_pTableView->setModel(m_pModel);
154 m_pTableView->setItemDelegate(m_pDelegate);
155 m_pTableView->setContextMenuPolicy(Qt::CustomContextMenu);
156
157 connect(m_pTableView.data(), &QTableView::doubleClicked,
159
160 connect(m_pTableView.data(), &QTableView::customContextMenuRequested,
162
163 //set some size settings for m_pTableView
164 m_pTableView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
165 m_pTableView->setShowGrid(false);
166 m_pTableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); //Stretch 2 column to maximal width
167 m_pTableView->horizontalHeader()->hide();
168 m_pTableView->verticalHeader()->setDefaultSectionSize(m_pTableView->height() / m_fZoomFactor); //Row Height
169 m_pTableView->setAutoScroll(false);
170 m_pTableView->setColumnHidden(0, true); //because content is plotted jointly with column=1
171 m_pTableView->setColumnHidden(2, true);
172 m_pTableView->resizeColumnsToContents();
173 m_pTableView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
174
175 connect(m_pTableView->verticalScrollBar(), &QScrollBar::valueChanged,
177}
178
179//=============================================================================================================
180
181void RtFiffRawView::addData(const QList<Eigen::MatrixXd>& lMatData)
182{
183 if (!lMatData.isEmpty()) {
184 m_pModel->addData(lMatData);
185
186 if (m_qListBadChannels.size() != m_pFiffInfo->bads.size()) {
187 m_qListBadChannels.clear();
188 for (int i = 0; i < m_pModel->rowCount(); i++) {
189 if (m_pModel->data(m_pModel->index(i, 2)).toBool()) {
191 }
192 }
193
194 //Hide non selected channels/rows in the lMatData views
195 for (int i = 0; i < m_qListBadChannels.size(); i++) {
196 if (m_bHideBadChannels) {
197 m_pTableView->hideRow(m_qListBadChannels.at(i));
198 } else {
199 m_pTableView->showRow(m_qListBadChannels.at(i));
200 }
201 }
202
203 //The set of visible rows changed, so the row height has to follow
205 }
206 } else {
207 qWarning() << "[RtFiffRawView::addData] Received lMatData list is empty.";
208 }
209}
210
211//=============================================================================================================
212
214{
215 return m_pModel->getLastBlock();
216}
217
218//=============================================================================================================
219
220bool RtFiffRawView::eventFilter(QObject* object, QEvent* event)
221{
222 if (m_bCrosshairEnabled && m_pModel && object == m_pTableView->viewport()) {
223 if (event->type() == QEvent::MouseMove) {
224 updateCrosshair(static_cast<QMouseEvent*>(event)->position().toPoint());
225 } else if (event->type() == QEvent::Leave) {
226 emit markerMoved(QPoint(), -1);
227 m_pTableView->viewport()->update();
228 }
229 }
230
231 return QWidget::eventFilter(object, event);
232}
233
234//=============================================================================================================
235
237{
238 m_bCrosshairEnabled = enabled;
239
240 if (!enabled) {
241 emit markerMoved(QPoint(), -1);
242 m_pTableView->viewport()->update();
243 }
244}
245
246//=============================================================================================================
247
249{
250 return m_bCrosshairEnabled;
251}
252
253//=============================================================================================================
254
255int RtFiffRawView::columnAt(int iX) const
256{
257 const double dDx = static_cast<double>(m_pTableView->columnWidth(1)) / static_cast<double>(m_pModel->getMaxSamples());
258
259 return static_cast<int>((iX - m_pTableView->columnViewportPosition(1)) / dDx);
260}
261
262//=============================================================================================================
263
264void RtFiffRawView::updateCrosshair(const QPoint& position)
265{
266 const int iRow = m_pTableView->rowAt(position.y());
267 emit markerMoved(position, iRow);
268 m_pTableView->viewport()->update();
269
270 const int iColumn = columnAt(position.x());
271 const int iSample = m_pModel->getSampleAtColumn(iColumn);
272 if (iRow < 0 || iSample < 0) {
273 return;
274 }
275
276 // "NA" for unitless channels, as MNE-Python labels them
277 const QString unit = FiffExplain::unit(m_pModel->getUnit(iRow));
278 emit cursorDataChanged(static_cast<float>(iSample / static_cast<double>(m_fSamplingRate)),
279 static_cast<float>(m_pModel->getValueAtColumn(iRow, iColumn)),
280 m_pModel->data(m_pModel->index(iRow, 0)).toString(),
281 unit.isEmpty() ? QStringLiteral("NA") : unit);
282}
283
284//=============================================================================================================
285
286void RtFiffRawView::setBackgroundColor(const QColor& backgroundColor)
287{
288 m_backgroundColor = backgroundColor;
289
290 if (m_pModel) {
291 m_pModel->setBackgroundColor(m_backgroundColor);
292 }
293
294 // QPalette pal;
295 // pal.setColor(QPalette::Window, m_backgroundColor);
296 // m_pTableView->viewport()->setPalette(pal);
297 // m_pTableView->viewport()->setBackgroundRole(QPalette::Window);
298}
299
300//=============================================================================================================
301
306
307//=============================================================================================================
308
309QMap<qint32, float> RtFiffRawView::getScalingMap()
310{
311 return m_qMapChScaling;
312}
313
314//=============================================================================================================
315
316void RtFiffRawView::setScalingMap(const QMap<qint32, float>& scaleMap)
317{
318 m_qMapChScaling = scaleMap;
319 m_pModel->setScaling(scaleMap);
320}
321
322//=============================================================================================================
323
324void RtFiffRawView::setSignalColor(const QColor& signalColor)
325{
326 m_pDelegate->setSignalColor(signalColor);
327}
328
329//=============================================================================================================
330
332{
333 return m_pDelegate->getSignalColor();
334}
335
336//=============================================================================================================
337
339{
340 if (m_bHideBadChannels) {
341 m_bHideBadChannels = false;
342 } else {
343 m_bHideBadChannels = true;
344 }
345
346 //Hide non selected channels/rows in the data views
347 for (int i = 0; i < m_qListBadChannels.size(); i++) {
348 if (m_bHideBadChannels) {
349 m_pTableView->hideRow(m_qListBadChannels.at(i));
350 } else {
351 m_pTableView->showRow(m_qListBadChannels.at(i));
352 }
353 }
354
355 //The rows that remain have to share the freed space
357
358 //Update the visible channel list which are to be filtered
360}
361
362//=============================================================================================================
363
365{
366 if (!m_pTableView || !m_pModel) {
367 return;
368 }
369
370 //
371 // The row height is derived from the height of the whole view, so it has to
372 // be recomputed whenever rows appear or disappear. Otherwise hiding a
373 // channel leaves the remaining rows at their previous height and the view
374 // no longer fills the widget.
375 //
376 int iVisibleRows = 0;
377 for (int i = 0; i < m_pModel->rowCount(); ++i) {
378 if (!m_pTableView->isRowHidden(i)) {
379 ++iVisibleRows;
380 }
381 }
382
383 if (iVisibleRows <= 0) {
384 return;
385 }
386
387 const int iHeight = static_cast<int>(static_cast<float>(m_pTableView->height() * m_pModel->rowCount()) / (static_cast<float>(iVisibleRows) * m_fZoomFactor));
388
389 m_pTableView->verticalHeader()->setDefaultSectionSize(iHeight);
390}
391
392//=============================================================================================================
393
398
399//=============================================================================================================
400
401void RtFiffRawView::showSelectedChannelsOnly(const QStringList& selectedChannels)
402{
403 m_slSelectedChannels = selectedChannels;
404
405 //Hide non selected channels/rows in the data views
406 for (int i = 0; i < m_pModel->rowCount(); i++) {
407 QString channel = m_pModel->data(m_pModel->index(i, 0), Qt::DisplayRole).toString();
408
409 //if channel is a bad channel and bad channels are to be hidden -> do not show
410 if (!selectedChannels.contains(channel) || (m_qListBadChannels.contains(i) && m_bHideBadChannels)) {
411 m_pTableView->hideRow(i);
412 } else {
413 m_pTableView->showRow(i);
414 }
415 }
416
417 //The rows that remain have to share the freed space
419
420 //Update the visible channel list which are to be filtered
422}
423
424//=============================================================================================================
425
426void RtFiffRawView::setZoom(double zoomFac)
427{
428 m_fZoomFactor = zoomFac;
429
431}
432
433//=============================================================================================================
434
436{
437 return m_fZoomFactor;
438}
439
440//=============================================================================================================
441
443{
444 m_iT = T;
445
446 m_pModel->setSamplingInfo(m_fSamplingRate, T);
447}
448
449//=============================================================================================================
450
452{
453 return m_iT;
454}
455
456//=============================================================================================================
457
459{
460 return m_fSamplingRate;
461}
462
463//=============================================================================================================
464
465void RtFiffRawView::takeScreenshot(const QString& fileName)
466{
467 // m_pTableView is a QPointer and is only created once a model has been set.
468 // Taking a screenshot before that, or after the view was destroyed, would
469 // otherwise dereference a null pointer.
470 if (m_pTableView.isNull()) {
471 qWarning() << "[RtFiffRawView::takeScreenshot] No data view available yet"
472 << "- no screenshot was taken.";
473 return;
474 }
475
476 if (fileName.contains(".svg", Qt::CaseInsensitive)) {
477 // Generate screenshot
478 QSvgGenerator svgGen;
479 svgGen.setFileName(fileName);
480 svgGen.setSize(m_pTableView->size());
481 svgGen.setViewBox(m_pTableView->rect());
482
483 m_pTableView->render(&svgGen);
484 }
485
486 if (fileName.contains(".png", Qt::CaseInsensitive)) {
487 QPixmap pixMap(m_pTableView->grab());
488 pixMap.save(fileName);
489 }
490}
491
492//=============================================================================================================
493
494void RtFiffRawView::updateProjection(const QList<FIFFLIB::FiffProj>& projs)
495{
496 m_pModel->updateProjection(projs);
497}
498
499//=============================================================================================================
500
502{
503 m_pModel->updateCompensator(to);
504}
505
506//=============================================================================================================
507
509{
510 m_pModel->updateSpharaActivation(state);
511}
512
513//=============================================================================================================
514
515void RtFiffRawView::updateSpharaOptions(const QString& sSytemType, int nBaseFctsFirst, int nBaseFctsSecond)
516{
517 m_pModel->updateSpharaOptions(sSytemType, nBaseFctsFirst, nBaseFctsSecond);
518}
519
520//=============================================================================================================
521
523{
524 m_pModel->setFilter(QList<FilterKernel>() << filterData);
525}
526
527//=============================================================================================================
528
530{
531 m_pModel->setFilterActive(state);
532}
533
534//=============================================================================================================
535
536void RtFiffRawView::setFilterChannelType(const QString& channelType)
537{
538 m_pModel->setFilterChannelType(channelType);
539}
540
541//=============================================================================================================
542
543void RtFiffRawView::triggerInfoChanged(const QMap<double, QColor>& colorMap,
544 bool active,
545 const QString& triggerCh,
546 double threshold)
547{
548 m_pModel->triggerInfoChanged(colorMap, active, triggerCh, threshold);
549}
550
551//=============================================================================================================
552
554{
555 m_iDistanceTimeSpacer = value;
556 m_pModel->distanceTimeSpacerChanged(value);
557}
558
559//=============================================================================================================
560
565
566//=============================================================================================================
567
569{
570 m_pModel->resetTriggerCounter();
571}
572
573//=============================================================================================================
574
576{
577 if (m_sSettingsPath.isEmpty()) {
578 return;
579 }
580
581 QSettings settings("MNECPP");
582}
583
584//=============================================================================================================
585
587{
588 if (m_sSettingsPath.isEmpty()) {
589 return;
590 }
591
592 QSettings settings("MNECPP");
593}
594
595//=============================================================================================================
596
598{
599 switch (mode) {
601 break;
602 default: // default is research mode
603 break;
604 }
605}
606
607//=============================================================================================================
608
610{
611 switch (mode) {
613 break;
614 default: // default is realtime mode
615 break;
616 }
617}
618
619//=============================================================================================================
620
622{
623 m_iClickPosX = pos.x();
624
625 //obtain index where index was clicked
626 QModelIndex index = m_pTableView->indexAt(pos);
627
628 //get selected items
629 QModelIndexList selected = m_pTableView->selectionModel()->selectedIndexes();
630
631 //create custom context menu and actions
632 QMenu* menu = new QMenu(this);
633 menu->setAttribute(Qt::WA_DeleteOnClose);
634
635 menu->addSection("Events");
636
637 QAction* addEventMarker = menu->addAction(tr("Add event"));
638 connect(addEventMarker, &QAction::triggered,
640
641 //Marking
642
643 menu->addSection("Channel Marking");
644
645 if (!m_qListBadChannels.contains(index.row())) {
646 QAction* doMarkChBad = menu->addAction(tr("Mark as bad"));
647 connect(doMarkChBad, &QAction::triggered,
649 } else {
650 QAction* doMarkChGood = menu->addAction(tr("Mark as good"));
651 connect(doMarkChGood, &QAction::triggered,
653 }
654
655 // non C++11 alternative
657 for (qint32 i = 0; i < selected.size(); ++i)
658 if (selected[i].column() == 1)
659 m_qListCurrentSelection.append(m_pModel->getIdxSelMap()[selected[i].row()]);
660
661 menu->addSection("Selection");
662
663 QAction* doSelection = menu->addAction(tr("Only show selection"));
664 connect(doSelection, &QAction::triggered,
666
667 //select channels
668 QAction* hideSelection = menu->addAction(tr("Hide selection"));
669 connect(hideSelection, &QAction::triggered, this,
671
672 //undo selection
673 QAction* resetAppliedSelection = menu->addAction(tr("Reset selection"));
674 connect(resetAppliedSelection, &QAction::triggered,
676 connect(resetAppliedSelection, &QAction::triggered,
678
679 //show context menu
680 menu->popup(m_pTableView->viewport()->mapToGlobal(pos));
681}
682
683//=============================================================================================================
684
686{
687 //Hide non selected channels/rows in the data views
688 for (int i = 0; i < m_pModel->rowCount(); i++) {
689 //if channel is a bad channel and bad channels are to be hidden -> do not show
690 if (m_qListCurrentSelection.contains(i)) {
691 m_pTableView->showRow(i);
692 } else {
693 m_pTableView->hideRow(i);
694 }
695 }
696
697 //Update the visible channel list which are to be filtered
698 //visibleRowsChanged();
699
700 //m_pModel->selectRows(m_qListCurrentSelection);
701}
702
703//=============================================================================================================
704
706{
707 for (int i = 0; i < m_qListCurrentSelection.size(); i++) {
709 }
710
711 //Update the visible channel list which are to be filtered
712 //visibleRowsChanged();
713}
714
715//=============================================================================================================
716
718{
719 for (qint32 i = 0; i < m_pFiffInfo->chs.size(); ++i) {
720 if (m_qListBadChannels.contains(i)) {
721 if (!m_bHideBadChannels) {
722 m_pTableView->showRow(i);
723 }
724 } else {
725 m_pTableView->showRow(i);
726 }
727 }
728}
729
730//=============================================================================================================
731
733{
734 if (!m_pTableView || !m_pModel || !m_pDelegate) {
735 return;
736 }
737
738 m_pDelegate->setUpperItemIndex(m_pTableView->rowAt(0));
739}
740
741//=============================================================================================================
742
744{
745 QModelIndexList selected = m_pTableView->selectionModel()->selectedIndexes();
746
747 for (int i = 0; i < selected.size(); i++) {
748 if (m_qListBadChannels.contains(selected[i].row())) { //mark as good
749 m_pModel->markChBad(selected[i], false);
750 m_qListBadChannels.removeAll(selected[i].row());
751 } else {
752 m_pModel->markChBad(selected[i], true);
753 m_qListBadChannels.append(selected[i].row());
754 }
755 }
756
757 m_pModel->updateProjection(m_pFiffInfo->projs);
758
759 //Hide non selected channels/rows in the data views
760 for (int i = 0; i < m_qListBadChannels.size(); i++) {
761 if (m_bHideBadChannels) {
762 m_pTableView->hideRow(m_qListBadChannels.at(i));
763 } else {
764 m_pTableView->showRow(m_qListBadChannels.at(i));
765 }
766 }
767
769}
770
771//=============================================================================================================
772
776
777//=============================================================================================================
778
779void RtFiffRawView::onAddEvent(bool bChecked)
780{
781 Q_UNUSED(bChecked)
782
783 // No events on the blank space before the first sweep has filled the window
784 const int iSample = m_pModel->getSampleAtColumn(columnAt(m_iClickPosX));
785 if (iSample >= 0) {
786 emit addSampleAsEvent(iSample);
787 }
788}
Full FIFF measurement metadata: everything from FIFFB_MEAS / FIFFB_MEAS_INFO needed to interpret a re...
Human-readable names of FIFF tag kinds, block kinds, units, unit multipliers and channel kinds.
Real-time FIFF raw-data table browser backed by DISPLIB::RtFiffRawViewModel + DISPLIB::RtFiffRawViewD...
QAbstractItemDelegate painting one FIFF channel's signal trace inside DISPLIB::RtFiffRawView.
Circular-buffer QAbstractTableModel feeding the real-time FIFF raw browser.
Linear-phase FIR filter kernel with overlap-add FFT convolution back-end.
FIFF file I/O, in-memory data structures and high-level readers/writers.
2-D display widgets and visualisation helpers (charts, topography, colour maps).
DSPSHARED_EXPORT Eigen::MatrixXd filterData(const Eigen::MatrixXd &matData, int type, double dCenterfreq, double dBandwidth, double dTransition, double dSFreq, int iOrder=1024, int designMethod=UTILSLIB::FilterKernel::m_designMethods.indexOf(UTILSLIB::FilterParameter("Cosine")), const Eigen::RowVectorXi &vecPicks=Eigen::RowVectorXi(), bool bUseThreads=true, bool bKeepOverhead=false)
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
AbstractView(QWidget *parent=0, Qt::WindowFlags f=Qt::Widget)
QAbstractItemDelegate painting one FIFF channel's signal trace inside RtFiffRawView.
void markerMoved(QPoint position, int activeRow)
Circular-buffer QAbstractTableModel feeding the real-time FIFF raw browser.
void toggleFreeze(const QModelIndex &index)
void triggerDetected(int numberDetectedTriggers, const QMap< int, QList< QPair< int, double > > > &mapDetectedTriggers)
void setFilterChannelType(const QString &channelType)
void cursorDataChanged(float timeSec, float amplitude, const QString &channelName, const QString &unitLabel)
QPointer< DISPLIB::RtFiffRawViewModel > m_pModel
void init(QSharedPointer< FIFFLIB::FiffInfo > &info)
QMap< qint32, float > getScalingMap()
RtFiffRawView(const QString &sSettingsPath="", QWidget *parent=0, Qt::WindowFlags f=Qt::Widget)
void takeScreenshot(const QString &fileName)
void updateGuiMode(GuiMode mode)
bool eventFilter(QObject *object, QEvent *event)
void addData(const QList< Eigen::MatrixXd > &lMatData)
void triggerDetected(int numberDetectedTriggers, const QMap< int, QList< QPair< int, double > > > &mapDetectedTriggers)
QMap< qint32, float > m_qMapChScaling
void setBackgroundColor(const QColor &backgroundColor)
void addSampleAsEvent(int iSample)
void updateSpharaOptions(const QString &sSytemType, int nBaseFctsFirst, int nBaseFctsSecond)
void setDistanceTimeSpacer(int value)
QList< qint32 > m_qListBadChannels
float getSamplingFreq() const
QStringList m_slSelectedChannels
void channelContextMenu(QPoint pos)
Eigen::MatrixXd getLastBlock()
QPointer< QTableView > m_pTableView
int columnAt(int iX) const
void markerMoved(QPoint position, int activeRow)
void updateProcessingMode(ProcessingMode mode)
void showSelectedChannelsOnly(const QStringList &selectedChannels)
void updateSpharaActivation(bool state)
void setCrosshairEnabled(bool enabled)
QSharedPointer< FIFFLIB::FiffInfo > m_pFiffInfo
void triggerInfoChanged(const QMap< double, QColor > &colorMap, bool active, const QString &triggerCh, double threshold)
void setSignalColor(const QColor &signalColor)
void setSettingsPath(const QString &sSettingsPath)
QPointer< DISPLIB::RtFiffRawViewDelegate > m_pDelegate
void updateCrosshair(const QPoint &position)
void onAddEvent(bool bChecked)
void setFilterActive(bool state)
void setFilter(const UTILSLIB::FilterKernel &filterData)
QList< qint32 > m_qListCurrentSelection
void updateProjection(const QList< FIFFLIB::FiffProj > &projs)
void setZoom(double zoomFac)
void setScalingMap(const QMap< qint32, float > &scaleMap)
The FilterKernel class provides methods to create/design a FIR filter kernel.
static QString unit(int unit)