v2.0.0
Loading...
Searching...
No Matches
frequencyspectrumdelegate.cpp
Go to the documentation of this file.
1//=============================================================================================================
14
15//=============================================================================================================
16// INCLUDES
17//=============================================================================================================
18
20
22
23#include <fiff/fiff_info.h>
24
25//=============================================================================================================
26// QT INCLUDES
27//=============================================================================================================
28
29#include <QPainter>
30#include <QTableView>
31#include <QPainterPath>
32
33#include <limits>
34
35//=============================================================================================================
36// USED NAMESPACES
37//=============================================================================================================
38
39using namespace DISPLIB;
40using namespace Eigen;
41
42//=============================================================================================================
43// DEFINE MEMBER METHODS
44//=============================================================================================================
45
46FrequencySpectrumDelegate::FrequencySpectrumDelegate(QTableView* m_pTableView, QObject* parent)
47: QAbstractItemDelegate(parent)
48, m_tableview_row(0)
49, m_mousex(0)
50, m_mousey(0)
51, m_x_rate(0.0)
52, m_fMaxValue(0.0)
53, m_fScaleY(0.0)
54, m_iScaleType(0)
55{
56 m_tableview = m_pTableView;
57 m_tableview->setMouseTracking(true);
58}
59
60//=============================================================================================================
61
63{
64 m_iScaleType = ScaleType;
65}
66
67//=============================================================================================================
68
69void FrequencySpectrumDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
70{
71 float t_fPlotHeight = option.rect.height();
72 switch (index.column()) {
73 case 0: { //chnames
74 painter->save();
75
76 painter->rotate(-90);
77 painter->drawText(QRectF(-option.rect.y() - t_fPlotHeight, 0, t_fPlotHeight, 20), Qt::AlignCenter, index.model()->data(index, Qt::DisplayRole).toString());
78
79 painter->restore();
80 break;
81 }
82 case 1: { //data plot
83 painter->save();
84
85 //draw special background when channel is marked as bad
86 // QVariant v = index.model()->data(index,Qt::BackgroundRole);
87 // if(v.canConvert<QBrush>() && !(option.state & QStyle::State_Selected)) {
88 // QPointF oldBO = painter->brushOrigin();
89 // painter->setBrushOrigin(option.rect.topLeft());
90 // painter->fillRect(option.rect, qvariant_cast<QBrush>(v));
91 // painter->setBrushOrigin(oldBO);
92 // }
93
94 // //Highlight selected channels
95 // if(option.state & QStyle::State_Selected) {
96 // QPointF oldBO = painter->brushOrigin();
97 // painter->setBrushOrigin(option.rect.topLeft());
98 // painter->fillRect(option.rect, option.palette.highlight());
99 // painter->setBrushOrigin(oldBO);
100 // }
101
102 //Get data
103 QVariant variant = index.model()->data(index, Qt::DisplayRole);
104 RowVectorXd data = variant.value<RowVectorXd>();
105
106 const FrequencySpectrumModel* t_pModel = static_cast<const FrequencySpectrumModel*>(index.model());
107
108 if (data.size() > 0) {
109 QPainterPath path(QPointF(option.rect.x(), option.rect.y())); //QPointF(option.rect.x()+t_rtmsaModel->relFiffCursor()-1,option.rect.y()));
110
111 //Plot grid
112 painter->setRenderHint(QPainter::Antialiasing, false);
113 createGridPath(index, option, path, data);
114 createGridTick(index, option, painter);
115
116 //capture the mouse
117 capturePoint(index, option, path, data, painter);
118
119 painter->save();
120 QPen pen;
121 pen.setStyle(Qt::DotLine);
122 pen.setWidthF(0.5);
123 painter->setPen(pen);
124 painter->drawPath(path);
125 painter->restore();
126
127 //Plot data path
128 path = QPainterPath(QPointF(option.rect.x(), option.rect.y())); //QPointF(option.rect.x()+t_rtmsaModel->relFiffCursor(),option.rect.y()));
129
130 createPlotPath(index, option, path, data);
131
132 painter->save();
133 painter->translate(0, t_fPlotHeight / 2);
134 painter->setRenderHint(QPainter::Antialiasing, true);
135
136 if (option.state & QStyle::State_Selected)
137 painter->setPen(QPen(t_pModel->isFreezed() ? Qt::darkRed : Qt::red, 1, Qt::SolidLine));
138 else
139 painter->setPen(QPen(t_pModel->isFreezed() ? Qt::darkGray : Qt::darkBlue, 1, Qt::SolidLine));
140
141 painter->drawPath(path);
142 painter->restore();
143 }
144 painter->restore();
145 break;
146 }
147 }
148}
149
150//=============================================================================================================
151
152QSize FrequencySpectrumDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
153{
154 QSize size;
155
156 switch (index.column()) {
157 case 0:
158 size = QSize(20, option.rect.height());
159 break;
160 case 1:
161 RowVectorXd data = index.model()->data(index).value<RowVectorXd>();
162 // qint32 nsamples = (static_cast<const FrequencySpectrumModel*>(index.model()))->lastSample()-(static_cast<const FrequencySpectrumModel*>(index.model()))->firstSample();
163
164 // size = QSize(nsamples*m_dDx,m_dPlotHeight);
165 Q_UNUSED(option);
166 break;
167 }
168
169 return size;
170}
171
172//=============================================================================================================
173
174void FrequencySpectrumDelegate::rcvMouseLoc(int tableview_row, int mousex, int mousey, QRect visRect)
175{
176 if (mousex != m_mousex) {
177 m_tableview_row = tableview_row;
178 m_mousex = mousex;
179 m_mousey = mousey;
180 m_visRect = visRect;
181
182 m_x_rate = (float)m_mousex / (float)m_visRect.width();
183
184 m_tableview->viewport()->repaint();
185 }
186}
187
188//=============================================================================================================
189
190void FrequencySpectrumDelegate::capturePoint(const QModelIndex& index, const QStyleOptionViewItem& option, QPainterPath& path, RowVectorXd& data, QPainter* painter) const
191{
192 Q_UNUSED(option);
193 Q_UNUSED(path);
194
195 if (m_tableview_row == index.row()) {
196 const FrequencySpectrumModel* t_pModel = static_cast<const FrequencySpectrumModel*>(index.model());
197
198 qint32 i;
199
200 RowVectorXd org_vecFreqScale = t_pModel->getFreqScale();
201 RowVectorXd vecFreqScale = t_pModel->getFreqScaleBound();
202
203 qint32 lowerIdx = t_pModel->getLowerFrqBound();
204 qint32 upperIdx = t_pModel->getUpperFrqBound();
205
206 //qint32 numbins = vecFreqScale.size();// data.size();
207
208 //qDebug() << "numbins" << numbins;
209 //qDebug() << "lowerIdx" << lowerIdx << "upperIdx" << upperIdx;
210
211 // find the bin nearest to the current mouse cursor location
212 i = lowerIdx;
213 double dBestDistance = std::numeric_limits<double>::max();
214 for (qint32 j = lowerIdx; j <= upperIdx; ++j) {
215 const double dRate = (vecFreqScale[j] - vecFreqScale[lowerIdx]) / (vecFreqScale[upperIdx] - vecFreqScale[lowerIdx]);
216 if (std::abs(dRate - m_x_rate) < dBestDistance) {
217 dBestDistance = std::abs(dRate - m_x_rate);
218 i = j;
219 }
220 }
221
222 /***************************************************
223 * Mouse moving showing the frequency and value
224 *
225 * *************************************************/
226
227 unsigned short usPosY = m_visRect.bottom();
228 unsigned short usPosX = m_visRect.left();
229 unsigned short usHeight = m_visRect.height();
230 unsigned short usWidth = m_visRect.width();
231
232 int iPosX = m_mousex;
233 int iPosY = m_mousey;
234
235 if (iPosX > usPosX && iPosX < usPosX + usWidth && iPosY > (usPosY - usHeight) && iPosY < usPosY) {
236 //qDebug()<<" index row" << index.row()<< "i"<< i << "iPosX,iposY" << iPosX << iPosY << "usPosY"<<usPosY<<"usHeight"<<usHeight;
237 //Horizontal line
238 painter->setPen(QPen(Qt::gray, 1, Qt::DashLine));
239
240 QPoint start(iPosX - 25, iPosY); //iStartY-5);//paint measure line vertical direction
241 QPoint end(iPosX + 25, iPosY); //iStartY+5);
242
243 // painter->drawLine(start, end);
244
245 //vertical line
246 start.setX(iPosX);
247 start.setY(usPosY - usHeight); // iPosY - 25);//iStartY - 5);
248 end.setX(iPosX);
249 end.setY(usPosY); //iPosY + 25);//iStartY + 5);
250 painter->drawLine(start, end);
251 // Draw text
252 painter->setPen(QPen(Qt::black, 1, Qt::SolidLine));
253
254 // cal the frequency according to the iPosX
255 double fs = t_pModel->getInfo()->sfreq / 2;
256
257 //RowVectorXd vecFreqScale = t_pModel->getFreqScale();
258 //RowVectorXd vecFreqScale = t_pModel->getFreqScaleBound();
259 double freq;
260 if (m_iScaleType) // log
261 {
262 double max = log10(fs + 1);
263 org_vecFreqScale *= max;
264
265 freq = pow(10, org_vecFreqScale[i]) - 1;
266 } else //normal
267 {
268 org_vecFreqScale *= fs;
269
270 freq = org_vecFreqScale[i];
271 }
272
273 QString tx = QString("%1 [DB], %2 [Hz]").arg(data[i]).arg(freq);
274
275 if (iPosX > usPosX + usWidth - tx.size() * 8)
276 painter->drawText(iPosX - tx.size() * 8, iPosY - 8, tx); // ToDo Precision should be part of preferences
277 else
278 painter->drawText(iPosX + 8, iPosY - 8, tx); // ToDo Precision should be part of preferences
279 }
280 } //correct row to plot
281}
282
283//=============================================================================================================
284
285void FrequencySpectrumDelegate::createPlotPath(const QModelIndex& index, const QStyleOptionViewItem& option, QPainterPath& path, RowVectorXd& data) const
286{
287 const FrequencySpectrumModel* t_pModel = static_cast<const FrequencySpectrumModel*>(index.model());
288
289 qint32 lowerIdx = t_pModel->getLowerFrqBound();
290 qint32 upperIdx = t_pModel->getUpperFrqBound();
291
292 if (data.size() == 0 || upperIdx < lowerIdx) {
293 return;
294 }
295
296 // Map the visible range into the cell (1 px margin), larger values upwards. The path starts at the cell top and
297 // is drawn translated down by half the cell height, so the cell bottom is at top + height / 2 here.
298 const double dMin = data.segment(lowerIdx, upperIdx - lowerIdx + 1).minCoeff();
299 const double dMax = data.segment(lowerIdx, upperIdx - lowerIdx + 1).maxCoeff();
300 const double dRange = (dMax > dMin) ? dMax - dMin : 1.0;
301 const double dScaleY = (option.rect.height() - 2.0) / dRange;
302 const double dYBottom = path.currentPosition().y() + option.rect.height() / 2.0 - 1.0;
303
304 for (qint32 i = lowerIdx; i <= upperIdx; ++i) {
305 const QPointF qSamplePosition(option.rect.x() + option.rect.width() * t_pModel->getFreqScaleBound()[i],
306 dYBottom - (data[i] - dMin) * dScaleY);
307 if (i == lowerIdx) {
308 path.moveTo(qSamplePosition);
309 } else {
310 path.lineTo(qSamplePosition);
311 }
312 }
313}
314
315//=============================================================================================================
316
317void FrequencySpectrumDelegate::createGridPath(const QModelIndex& index, const QStyleOptionViewItem& option, QPainterPath& path, RowVectorXd& data) const
318{
319 Q_UNUSED(data)
320
321 const FrequencySpectrumModel* t_pModel = static_cast<const FrequencySpectrumModel*>(index.model());
322
323 if (t_pModel->getInfo()) {
324 double nf = t_pModel->getInfo()->sfreq / 2;
325
326 qint32 numLines = (m_iScaleType) ? (qint32)ceil(log10(nf)) : 5;
327
328 QList<qint32> qListLineSamples;
329
330 qListLineSamples << 0;
331
332 if (m_iScaleType) { // log
333 for (qint32 lineIdx = 0; lineIdx < numLines; ++lineIdx) {
334 double val = pow(10, lineIdx);
335 qint32 idx = (qint32)floor(val / ((float)nf / (float)t_pModel->getNumStems()));
336 qListLineSamples.append(idx);
337 }
338 } else { // normal
339 for (qint32 lineIdx = 1; lineIdx < numLines; ++lineIdx) {
340 double val = lineIdx * (nf / numLines);
341 qint32 idx = (qint32)floor(val / ((float)nf / (float)t_pModel->getNumStems()));
342 qListLineSamples.append(idx);
343 }
344 }
345 //vertical lines
346 float yStart = option.rect.topLeft().y();
347
348 float yEnd = option.rect.bottomRight().y();
349
350 for (qint32 i = 0; i < qListLineSamples.size(); ++i) {
351 if (qListLineSamples[i] > t_pModel->getLowerFrqBound() && qListLineSamples[i] < t_pModel->getUpperFrqBound()) {
352 float x = (t_pModel->getFreqScaleBound()[qListLineSamples[i]]) * option.rect.width();
353 path.moveTo(x, yStart);
354 path.lineTo(x, yEnd);
355 }
356 }
357 }
358}
359
360//=============================================================================================================
361
362void FrequencySpectrumDelegate::createGridTick(const QModelIndex& index, const QStyleOptionViewItem& option, QPainter* painter) const
363{
364 const FrequencySpectrumModel* t_pModel = static_cast<const FrequencySpectrumModel*>(index.model());
365
366 if (t_pModel->getInfo()) {
367 double nf = t_pModel->getInfo()->sfreq / 2;
368
369 qint32 numLines = (m_iScaleType) ? (qint32)ceil(log10(nf)) : 5;
370
371 QList<qint32> qListLineSamples;
372
373 qListLineSamples << 0;
374 if (m_iScaleType) { // log
375 for (qint32 lineIdx = 0; lineIdx < numLines; ++lineIdx) {
376 double val = pow(10, lineIdx);
377 qint32 idx = (qint32)floor(val / ((float)nf / (float)t_pModel->getNumStems()));
378 qListLineSamples.append(idx);
379 }
380 } else { // normal
381 for (qint32 lineIdx = 1; lineIdx < numLines; ++lineIdx) {
382 double val = lineIdx * (nf / numLines);
383 qint32 idx = (qint32)floor(val / ((float)nf / (float)t_pModel->getNumStems()));
384 qListLineSamples.append(idx);
385 }
386 }
387
388 // XTick
389 float yStart = 1.0 * option.rect.topLeft().y();
390
391 if (qListLineSamples[0] > t_pModel->getLowerFrqBound() && qListLineSamples[0] < t_pModel->getUpperFrqBound()) {
392 double val = 0.0;
393 float x = (t_pModel->getFreqScaleBound()[qListLineSamples[0]]) * option.rect.width();
394 painter->drawText(x, yStart, QString("%1Hz").arg(val));
395 }
396
397 for (qint32 i = 1; i < qListLineSamples.size(); ++i) {
398 if (qListLineSamples[i] > t_pModel->getLowerFrqBound() && qListLineSamples[i] < t_pModel->getUpperFrqBound()) {
399 double val = (m_iScaleType) ? pow(10, i - 1) : t_pModel->getFreqScaleBound()[qListLineSamples[i]] * nf;
400 float x = (t_pModel->getFreqScaleBound()[qListLineSamples[i]]) * option.rect.width();
401 painter->drawText(x, yStart, QString("%1Hz").arg(val));
402 }
403 }
404
405 // YTick
406 }
407}
Full FIFF measurement metadata: everything from FIFFB_MEAS / FIFFB_MEAS_INFO needed to interpret a re...
QAbstractItemDelegate painting one row of the DISPLIB::SpectrumView as a horizontal frequency band.
QAbstractTableModel storing per-channel FFT magnitudes for DISPLIB::SpectrumView.
2-D display widgets and visualisation helpers (charts, topography, colour maps).
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
void rcvMouseLoc(int row, int x, int y, QRect visRect)
FrequencySpectrumDelegate(QTableView *m_pTableView, QObject *parent=0)
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
QAbstractTableModel storing per-channel FFT magnitudes for SpectrumView.
QSharedPointer< FIFFLIB::FiffInfo > getInfo() const
Eigen::RowVectorXd getFreqScaleBound() const
Eigen::RowVectorXd getFreqScale() const