UPlot.cpp
Go to the documentation of this file.
1 /*
2 * utilite is a cross-platform library with
3 * useful utilities for fast and small developing.
4 * Copyright (C) 2010 Mathieu Labbe
5 *
6 * utilite is free library: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * utilite is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "rtabmap/utilite/UPlot.h"
22 #include "rtabmap/utilite/UMath.h"
23 
24 #include <QGraphicsScene>
25 #include <QGraphicsView>
26 #include <QGraphicsItem>
27 #include <QGraphicsRectItem>
28 #include <QHBoxLayout>
29 #include <QFormLayout>
30 #include <QtGui/QResizeEvent>
31 #include <QtGui/QMouseEvent>
32 #include <QtCore/QTime>
33 #include <QtCore/QTimer>
34 #include <QtCore/QFileInfo>
35 #include <QPushButton>
36 #include <QToolButton>
37 #include <QLabel>
38 #include <QMenu>
39 #include <QStyle>
40 #include <QActionGroup>
41 #include <QInputDialog>
42 #include <QMessageBox>
43 #include <QFileDialog>
44 #include <QtGui/QClipboard>
45 #include <QApplication>
46 #include <QPrinter>
47 #include <QColorDialog>
48 #include <QToolTip>
49 #ifdef QT_SVG_LIB
50 #include <QtSvg/QSvgGenerator>
51 #endif
52 #include <cmath>
53 #include <limits>
54 
55 #define PRINT_DEBUG 0
56 
57 UPlotItem::UPlotItem(qreal dataX, qreal dataY, qreal width) :
58  QGraphicsEllipseItem(0, 0, width, width, 0),
59  _previousItem(0),
60  _nextItem(0),
61  _text(0),
62  _textBackground(0)
63 {
64  this->init(dataX, dataY);
65 }
66 
67 UPlotItem::UPlotItem(const QPointF & data, qreal width) :
68  QGraphicsEllipseItem(0, 0, width, width, 0),
69  _previousItem(0),
70  _nextItem(0),
71  _text(0),
72  _textBackground(0)
73 {
74  this->init(data.x(), data.y());
75 }
76 
77 void UPlotItem::init(qreal dataX, qreal dataY)
78 {
79  _data.setX(dataX);
80  _data.setY(dataY);
81  this->setAcceptHoverEvents(true);
82  this->setFlag(QGraphicsItem::ItemIsFocusable, true);
83 }
84 
86 {
88  {
91  }
92  else if(_previousItem)
93  {
95  }
96  else if(_nextItem)
97  {
99  }
100 }
101 
102 void UPlotItem::setData(const QPointF & data)
103 {
104  _data = data;
105 }
106 
108 {
109  if(_nextItem != nextItem)
110  {
112  if(nextItem)
113  {
114  nextItem->setPreviousItem(this);
115  }
116  }
117 }
118 
120 {
122  {
124  if(previousItem)
125  {
126  previousItem->setNextItem(this);
127  }
128  }
129 }
130 
132 {
133  if(!_textBackground)
134  {
135  _textBackground = new QGraphicsRectItem(this);
136  _textBackground->setBrush(QBrush(QColor(255, 255, 255, 200)));
137  _textBackground->setPen(Qt::NoPen);
138  _textBackground->setZValue(this->zValue()+1);
139  _textBackground->setVisible(false);
140 
141  _text = new QGraphicsTextItem(_textBackground);
142  }
143 
144  if(this->parentItem() && this->parentItem() != _textBackground->parentItem())
145  {
146  _textBackground->setParentItem(this->parentItem());
147  _textBackground->setZValue(this->zValue()+1);
148  }
149 
150  if(this->scene() && shown)
151  {
152  _textBackground->setVisible(true);
153  _text->setPlainText(QString("(%1,%2)").arg(_data.x()).arg(_data.y()));
154 
155  this->setPen(QPen(this->pen().color(), 2));
156 
157  QRectF rect = this->scene()->sceneRect();
158  QPointF p = this->pos();
159  QRectF br = _text->boundingRect();
160  _textBackground->setRect(QRectF(0,0,br.width(), br.height()));
161 
162  // Make sure the text is always in the scene
163  if(p.x() - br.width() < 0)
164  {
165  p.setX(0);
166  }
167  else if(p.x() > rect.width())
168  {
169  p.setX(rect.width() - br.width());
170  }
171  else
172  {
173  p.setX(p.x() - br.width());
174  }
175 
176  if(p.y() - br.height() < 0)
177  {
178  p.setY(0);
179  }
180  else
181  {
182  p.setY(p.y() - br.height());
183  }
184 
185  _textBackground->setPos(p);
186  }
187  else
188  {
189  this->setPen(QPen(this->pen().color(), 1));
190  _textBackground->setVisible(false);
191  }
192 }
193 
194 void UPlotItem::hoverEnterEvent(QGraphicsSceneHoverEvent * event)
195 {
196  this->showDescription(true);
197  QGraphicsEllipseItem::hoverEnterEvent(event);
198 }
199 
200 void UPlotItem::hoverLeaveEvent(QGraphicsSceneHoverEvent * event)
201 {
202  if(!this->hasFocus())
203  {
204  this->showDescription(false);
205  }
206  QGraphicsEllipseItem::hoverLeaveEvent(event);
207 }
208 
209 void UPlotItem::focusInEvent(QFocusEvent * event)
210 {
211  this->showDescription(true);
212  QGraphicsEllipseItem::focusInEvent(event);
213 }
214 
215 void UPlotItem::focusOutEvent(QFocusEvent * event)
216 {
217  this->showDescription(false);
218  QGraphicsEllipseItem::focusOutEvent(event);
219 }
220 
221 void UPlotItem::keyReleaseEvent(QKeyEvent * keyEvent)
222 {
223  //Get the next/previous visible item
224  if(keyEvent->key() == Qt::Key_Right)
225  {
226  UPlotItem * next = _nextItem;
227  while(next && !next->isVisible())
228  {
229  next = next->nextItem();
230  }
231  if(next && next->isVisible())
232  {
233  this->clearFocus();
234  next->setFocus();
235  }
236  }
237  else if(keyEvent->key() == Qt::Key_Left)
238  {
239  UPlotItem * previous = _previousItem;
240  while(previous && !previous->isVisible())
241  {
242  previous = previous->previousItem();
243  }
244  if(previous && previous->isVisible())
245  {
246  this->clearFocus();
247  previous->setFocus();
248  }
249  }
250  QGraphicsEllipseItem::keyReleaseEvent(keyEvent);
251 }
252 
253 
254 
255 
256 
257 UPlotCurve::UPlotCurve(const QString & name, QObject * parent) :
258  QObject(parent),
259  _plot(0),
260  _name(name),
261  _xIncrement(1),
262  _xStart(0),
263  _visible(true),
264  _valuesShown(false),
265  _itemsColor(0,0,0,150)
266 {
267  _rootItem = new QGraphicsRectItem();
268 }
269 
270 UPlotCurve::UPlotCurve(const QString & name, QVector<UPlotItem *> data, QObject * parent) :
271  QObject(parent),
272  _plot(0),
273  _name(name),
274  _xIncrement(1),
275  _xStart(0),
276  _visible(true),
277  _valuesShown(false),
278  _itemsColor(0,0,0,150)
279 {
280  _rootItem = new QGraphicsRectItem();
281  this->setData(data);
282 }
283 
284 UPlotCurve::UPlotCurve(const QString & name, const QVector<qreal> & x, const QVector<qreal> & y, QObject * parent) :
285  QObject(parent),
286  _plot(0),
287  _name(name),
288  _xIncrement(1),
289  _xStart(0),
290  _visible(true),
291  _valuesShown(false),
292  _itemsColor(0,0,0,150)
293 {
294  _rootItem = new QGraphicsRectItem();
295  this->setData(x, y);
296 }
297 
299 {
300  if(_plot)
301  {
302  _plot->removeCurve(this);
303  }
304 #if PRINT_DEBUG
305  ULOGGER_DEBUG("%s", this->name().toStdString().c_str());
306 #endif
307  this->clear();
308  delete _rootItem;
309 }
310 
312 {
313  if(!plot || plot == _plot)
314  {
315  return;
316  }
317  if(_plot)
318  {
319  _plot->removeCurve(this);
320  }
321  _plot = plot;
323 }
324 
326 {
327 #if PRINT_DEBUG
328  ULOGGER_DEBUG("curve=\"%s\" from plot=\"%s\"", this->objectName().toStdString().c_str(), plot?plot->objectName().toStdString().c_str():"");
329 #endif
330  if(plot && _plot == plot)
331  {
332  _plot = 0;
333  if(_rootItem->scene())
334  {
335  _rootItem->scene()->removeItem(_rootItem);
336  }
337  }
338 }
339 
341 {
342  qreal x,y;
343  const UPlotItem * item;
344  if(!_items.size())
345  {
346  _minMax = QVector<qreal>();
347  }
348  else
349  {
350  _minMax = QVector<qreal>(4);
351  }
352  for(int i=0; i<_items.size(); ++i)
353  {
354  item = qgraphicsitem_cast<const UPlotItem *>(_items.at(i));
355  if(item)
356  {
357  x = item->data().x();
358  y = item->data().y();
359  if(i==0)
360  {
361  _minMax[0] = x;
362  _minMax[1] = x;
363  _minMax[2] = y;
364  _minMax[3] = y;
365  }
366  else
367  {
368  if(x<_minMax[0]) _minMax[0] = x;
369  if(x>_minMax[1]) _minMax[1] = x;
370  if(y<_minMax[2]) _minMax[2] = y;
371  if(y>_minMax[3]) _minMax[3] = y;
372  }
373  }
374  }
375 }
376 
378 {
379  // add item
380  if(data)
381  {
382  qreal x = data->data().x();
383  qreal y = data->data().y();
384 
385  if(_minMax.size() != 4)
386  {
387  _minMax = QVector<qreal>(4);
388  }
389  if(_items.size())
390  {
391  data->setPreviousItem((UPlotItem *)_items.last());
392  QGraphicsLineItem * line = new QGraphicsLineItem(_rootItem);
393  line->setPen(_pen);
394  line->setVisible(false);
395  _items.append(line);
396  //Update min/max
397  if(x<_minMax[0]) _minMax[0] = x;
398  if(x>_minMax[1]) _minMax[1] = x;
399  if(y<_minMax[2]) _minMax[2] = y;
400  if(y>_minMax[3]) _minMax[3] = y;
401  }
402  else
403  {
404  _minMax[0] = x;
405  _minMax[1] = x;
406  _minMax[2] = y;
407  _minMax[3] = y;
408  }
409  data->setParentItem(_rootItem);
410  data->setZValue(1);
411  _items.append(data);
412  data->setVisible(false);
413  QPen pen = data->pen();
414  pen.setColor(_itemsColor);
415  data->setPen(pen);
416  }
417  else
418  {
419  ULOGGER_ERROR("Data is null ?!?");
420  }
421 }
422 
424 {
425  // add item
426  if(data)
427  {
428  this->_addValue(data);
429  Q_EMIT dataChanged(this);
430  }
431 }
432 
433 void UPlotCurve::addValue(qreal x, qreal y)
434 {
435  if(_items.size() &&
436  _minMax[0] != _minMax[1] &&
437  x < _minMax[1])
438  {
439  UWARN("New value (%f) added to curve \"%s\" is smaller "
440  "than the last added (%f). Clearing the curve.",
441  x, this->name().toStdString().c_str(), ((UPlotItem*)_items.back())->data().x());
442  this->clear();
443  }
444 
445  qreal width = 2; // TODO warn : hard coded value!
446  this->addValue(new UPlotItem(x,y,width));
447 }
448 
449 void UPlotCurve::addValue(qreal y)
450 {
451  qreal x = 0;
452  if(_items.size())
453  {
454  UPlotItem * lastItem = (UPlotItem *)_items.last();
455  x = lastItem->data().x() + _xIncrement;
456  }
457  else
458  {
459  x = _xStart;
460  }
461  this->addValue(x,y);
462 }
463 
464 void UPlotCurve::addValue(const QString & value)
465 {
466  bool ok;
467  qreal v = value.toDouble(&ok);
468  if(ok)
469  {
470  this->addValue(v);
471  }
472  else
473  {
474  ULOGGER_ERROR("Value not valid, must be a number, received %s", value.toStdString().c_str());
475  }
476 }
477 
478 void UPlotCurve::addValues(QVector<UPlotItem *> & data)
479 {
480  for(int i=0; i<data.size(); ++i)
481  {
482  this->_addValue(data.at(i));
483  }
484  Q_EMIT dataChanged(this);
485 }
486 
487 void UPlotCurve::addValues(const QVector<qreal> & xs, const QVector<qreal> & ys)
488 {
489  qreal width = 2; // TODO warn : hard coded value!
490  for(int i=0; i<xs.size() && i<ys.size(); ++i)
491  {
492  this->_addValue(new UPlotItem(xs.at(i),ys.at(i),width));
493  }
494  Q_EMIT dataChanged(this);
495 }
496 
497 void UPlotCurve::addValues(const QVector<qreal> & ys)
498 {
499  qreal x = 0;
500  qreal width = 2; // TODO warn : hard coded value!
501  for(int i=0; i<ys.size(); ++i)
502  {
503  if(_items.size())
504  {
505  UPlotItem * lastItem = (UPlotItem *)_items.last();
506  x = lastItem->data().x() + _xIncrement;
507  }
508  else
509  {
510  x = _xStart;
511  }
512  this->_addValue(new UPlotItem(x,ys.at(i),width));
513  }
514  Q_EMIT dataChanged(this);
515 }
516 
517 void UPlotCurve::addValues(const QVector<int> & ys)
518 {
519  qreal x = 0;
520  qreal width = 2; // TODO warn : hard coded value!
521  for(int i=0; i<ys.size(); ++i)
522  {
523  if(_items.size())
524  {
525  UPlotItem * lastItem = (UPlotItem *)_items.last();
526  x = lastItem->data().x() + _xIncrement;
527  }
528  else
529  {
530  x = _xStart;
531  }
532  this->_addValue(new UPlotItem(x,ys.at(i),width));
533  }
534  Q_EMIT dataChanged(this);
535 }
536 
537 void UPlotCurve::addValues(const std::vector<int> & ys)
538 {
539  qreal x = 0;
540  qreal width = 2; // TODO warn : hard coded value!
541  for(unsigned int i=0; i<ys.size(); ++i)
542  {
543  if(_items.size())
544  {
545  UPlotItem * lastItem = (UPlotItem *)_items.last();
546  x = lastItem->data().x() + _xIncrement;
547  }
548  else
549  {
550  x = _xStart;
551  }
552  this->_addValue(new UPlotItem(x,ys.at(i),width));
553  }
554  Q_EMIT dataChanged(this);
555 }
556 
557 void UPlotCurve::addValues(const std::vector<qreal> & ys)
558 {
559  qreal x = 0;
560  qreal width = 2; // TODO warn : hard coded value!
561  for(unsigned int i=0; i<ys.size(); ++i)
562  {
563  if(_items.size())
564  {
565  UPlotItem * lastItem = (UPlotItem *)_items.last();
566  x = lastItem->data().x() + _xIncrement;
567  }
568  else
569  {
570  x = _xStart;
571  }
572  this->_addValue(new UPlotItem(x,ys.at(i),width));
573  }
574  Q_EMIT dataChanged(this);
575 }
576 
578 {
579  if(index >= 0 && index < _items.size())
580  {
581  if(index!=0)
582  {
583  index-=1;
584  delete _items.takeAt(index); // the line
585  }
586  else if(_items.size()>1)
587  {
588  delete _items.takeAt(index+1); // the line
589  }
590  UPlotItem * item = (UPlotItem *)_items.takeAt(index); // the plot item
591  //Update min/max
592  if(_minMax.size() == 4)
593  {
594  if(item->data().x() == _minMax[0] || item->data().x() == _minMax[1] ||
595  item->data().y() == _minMax[2] || item->data().y() == _minMax[3])
596  {
597  if(_items.size())
598  {
599  UPlotItem * tmp = (UPlotItem *)_items.at(0);
600  qreal x = tmp->data().x();
601  qreal y = tmp->data().y();
602  _minMax[0]=x;
603  _minMax[1]=x;
604  _minMax[2]=y;
605  _minMax[3]=y;
606  for(int i = 2; i<_items.size(); i+=2)
607  {
608  tmp = (UPlotItem*)_items.at(i);
609  x = tmp->data().x();
610  y = tmp->data().y();
611  if(x<_minMax[0]) _minMax[0] = x;
612  if(x>_minMax[1]) _minMax[1] = x;
613  if(y<_minMax[2]) _minMax[2] = y;
614  if(y>_minMax[3]) _minMax[3] = y;
615  }
616  }
617  else
618  {
619  _minMax = QVector<qreal>();
620  }
621  }
622  }
623  delete item;
624  }
625 
626  return index;
627 }
628 
629 void UPlotCurve::removeItem(UPlotItem * item) // ownership is transfered to the caller
630 {
631  for(int i=0; i<_items.size(); ++i)
632  {
633  if(_items.at(i) == item)
634  {
635  if(i!=0)
636  {
637  i-=1;
638  delete _items[i];
639  _items.removeAt(i);
640  }
641  else if(_items.size()>1)
642  {
643  delete _items[i+1];
644  _items.removeAt(i+1);
645  }
646  item->scene()->removeItem(item);
647  _items.removeAt(i);
648  break;
649  }
650  }
651 }
652 
654 {
655 #if PRINT_DEBUG
656  ULOGGER_DEBUG("%s", this->name().toStdString().c_str());
657 #endif
658  qDeleteAll(_rootItem->childItems());
659  _items.clear();
660 }
661 
662 void UPlotCurve::setPen(const QPen & pen)
663 {
664  _pen = pen;
665  for(int i=1; i<_items.size(); i+=2)
666  {
667  ((QGraphicsLineItem*) _items.at(i))->setPen(_pen);
668  }
669 }
670 
671 void UPlotCurve::setBrush(const QBrush & brush)
672 {
673  _brush = brush;
674  ULOGGER_WARN("Not used...");
675 }
676 
677 void UPlotCurve::setItemsColor(const QColor & color)
678 {
679  if(color.isValid())
680  {
681  _itemsColor.setRgb(color.red(), color.green(), color.blue(), _itemsColor.alpha());
682  for(int i=0; i<_items.size(); i+=2)
683  {
684  QPen pen = ((UPlotItem*) _items.at(i))->pen();
685  pen.setColor(_itemsColor);
686  ((UPlotItem*) _items.at(i))->setPen(pen);
687  }
688  }
689 }
690 
691 void UPlotCurve::update(qreal scaleX, qreal scaleY, qreal offsetX, qreal offsetY, qreal xDir, qreal yDir, int maxItemsKept)
692 {
693  //ULOGGER_DEBUG("scaleX=%f, scaleY=%f, offsetX=%f, offsetY=%f, xDir=%d, yDir=%d, _plot->scene()->width()=%f, _plot->scene()->height=%f", scaleX, scaleY, offsetX, offsetY, xDir, yDir,_plot->scene()->width(),_plot->scene()->height());
694  //make sure direction values are 1 or -1
695  xDir<0?xDir=-1:xDir=1;
696  yDir<0?yDir=-1:yDir=1;
697 
698  bool hide = false;
699  int j=0;
700  for(int i=_items.size()-1; i>=0; --i)
701  {
702  if(i%2 == 0)
703  {
704  UPlotItem * item = (UPlotItem *)_items.at(i);
705  if(hide)
706  {
707  if(maxItemsKept == 0 || j <= maxItemsKept)
708  {
709  // if not visible, stop looping... all other items are normally already hidden
710  if(!item->isVisible())
711  {
712  break;
713  }
714  item->setVisible(false);
715  }
716  else
717  {
718  //remove the item with his line
719  i = this->removeItem(i);
720  }
721  }
722  else
723  {
724  QPointF newPos(((xDir*item->data().x()+offsetX)*scaleX-item->rect().width()/2.0f),
725  ((yDir*item->data().y()+offsetY)*scaleY-item->rect().width()/2.0f));
726  if(!item->isVisible())
727  {
728  item->setVisible(true);
729  }
730  item->setPos(newPos);
731  }
732  ++j;
733  }
734  else
735  {
736  if(hide)
737  {
738  _items.at(i)->setVisible(false);
739  }
740  else
741  {
742  UPlotItem * from = (UPlotItem *)_items.at(i-1);
743  UPlotItem * to = (UPlotItem *)_items.at(i+1);
744  QGraphicsLineItem * lineItem = (QGraphicsLineItem *)_items.at(i);
745  lineItem->setLine((xDir*from->data().x()+offsetX)*scaleX,
746  (yDir*from->data().y()+offsetY)*scaleY,
747  (xDir*to->data().x()+offsetX)*scaleX,
748  (yDir*to->data().y()+offsetY)*scaleY);
749  if(!lineItem->isVisible())
750  {
751  lineItem->setVisible(true);
752  }
753  //Don't update not visible items
754  // (Detect also if the curve goes forward or backward)
755  QLineF line = lineItem->line();
756  if((line.x1() <= line.x2() && line.x2() < 0-((line.x2() - line.x1()))) ||
757  (line.x1() > line.x2() && line.x2() > lineItem->scene()->sceneRect().width() + ((line.x1() - line.x2()))))
758  {
759  hide = true;
760  }
761 
762  }
763  }
764  }
765 
766 }
767 
768 void UPlotCurve::draw(QPainter * painter, const QRect & limits)
769 {
770  if(painter)
771  {
772  for(int i=_items.size()-1; i>=0 && _items.at(i)->isVisible(); i-=2)
773  {
774  //plotItem
775  const UPlotItem * item = (const UPlotItem *)_items.at(i);
776  int x = (int)item->x();
777  if(x<0)
778  {
779  break;
780  }
781 
782  // draw line in first
783  if(i-1>=0)
784  {
785  //lineItem
786  const QGraphicsLineItem * lineItem = (const QGraphicsLineItem *)_items.at(i-1);
787  QLine line = lineItem->line().toLine();
788  if(limits.contains(line.p1()) || limits.contains(line.p2()))
789  {
790  QPointF intersection;
791  QLineF::IntersectType type;
792 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 3)
793  type = lineItem->line().intersects(QLineF(limits.topLeft(), limits.bottomLeft()), &intersection);
794 #else
795  type = lineItem->line().intersect(QLineF(limits.topLeft(), limits.bottomLeft()), &intersection);
796 #endif
797  if(type == QLineF::BoundedIntersection)
798  {
799  !limits.contains(line.p1())?line.setP1(intersection.toPoint()):line.setP2(intersection.toPoint());
800  }
801  else
802  {
803 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 3)
804  type = lineItem->line().intersects(QLineF(limits.topLeft(), limits.topRight()), &intersection);
805 #else
806  type = lineItem->line().intersect(QLineF(limits.topLeft(), limits.topRight()), &intersection);
807 #endif
808  if(type == QLineF::BoundedIntersection)
809  {
810  !limits.contains(line.p1())?line.setP1(intersection.toPoint()):line.setP2(intersection.toPoint());
811  }
812  else
813  {
814 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 3)
815  type = lineItem->line().intersects(QLineF(limits.bottomLeft(), limits.bottomRight()), &intersection);
816 #else
817  type = lineItem->line().intersect(QLineF(limits.bottomLeft(), limits.bottomRight()), &intersection);
818 #endif
819  if(type == QLineF::BoundedIntersection)
820  {
821  !limits.contains(line.p1())?line.setP1(intersection.toPoint()):line.setP2(intersection.toPoint());
822  }
823  else
824  {
825 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 3)
826  type = lineItem->line().intersects(QLineF(limits.topRight(), limits.bottomRight()), &intersection);
827 #else
828  type = lineItem->line().intersect(QLineF(limits.topRight(), limits.bottomRight()), &intersection);
829 #endif
830  if(type == QLineF::BoundedIntersection)
831  {
832  !limits.contains(line.p1())?line.setP1(intersection.toPoint()):line.setP2(intersection.toPoint());
833  }
834  }
835  }
836  }
837  painter->save();
838  painter->setPen(this->pen());
839  painter->setBrush(this->brush());
840  painter->drawLine(line);
841  painter->restore();
842  }
843  }
844 
845  /*if(limits.contains(item->pos().toPoint()) && limits.contains((item->pos() + QPointF(item->rect().width(), item->rect().height())).toPoint()))
846  {
847  painter->save();
848  painter->setPen(QPen(_itemsColor));
849  painter->drawEllipse(item->pos()+QPointF(item->rect().width()/2, item->rect().height()/2), (int)item->rect().width()/2, (int)item->rect().height()/2);
850  painter->restore();
851  }*/
852  }
853  }
854 }
855 
857 {
858  return _items.size();
859 }
860 
861 QPointF UPlotCurve::getItemData(int index)
862 {
863  QPointF data;
864  //make sure the index point to a PlotItem {PlotItem, line, PlotItem, line...}
865  if(index>=0 && index < _items.size() && index % 2 == 0 )
866  {
867  data = ((UPlotItem*)_items.at(index))->data();
868  }
869  else
870  {
871  ULOGGER_ERROR("Wrong index, not pointing on a PlotItem");
872  }
873  return data;
874 }
875 
876 void UPlotCurve::setVisible(bool visible)
877 {
878  _visible = visible;
879  for(int i=0; i<_items.size(); ++i)
880  {
881  _items.at(i)->setVisible(visible);
882  }
883 }
884 
885 void UPlotCurve::setXIncrement(qreal increment)
886 {
887  _xIncrement = increment;
888 }
889 
890 void UPlotCurve::setXStart(qreal val)
891 {
892  _xStart = val;
893 }
894 
895 void UPlotCurve::setData(QVector<UPlotItem*> & data)
896 {
897  this->clear();
898  for(int i = 0; i<data.size(); ++i)
899  {
900  this->addValue(data[i]);
901  }
902 }
903 
904 void UPlotCurve::setData(const QVector<qreal> & x, const QVector<qreal> & y)
905 {
906  if(x.size() == y.size())
907  {
908  //match the size of the current data
909  int margin = int((_items.size()+1)/2) - x.size();
910  while(margin < 0)
911  {
912  UPlotItem * newItem = new UPlotItem(0, 0, 2);
913  this->_addValue(newItem);
914  ++margin;
915  }
916  while(margin > 0)
917  {
918  this->removeItem(0);
919  --margin;
920  }
921 
922  // update values
923  int index = 0;
924  QVector<qreal>::const_iterator i=x.begin();
925  QVector<qreal>::const_iterator j=y.begin();
926  for(; i!=x.end() && j!=y.end(); ++i, ++j, index+=2)
927  {
928  ((UPlotItem*)_items[index])->setData(QPointF(*i, *j));
929  }
930 
931  //reset minMax, this will force the plot to update the axes
932  this->updateMinMax();
933  Q_EMIT dataChanged(this);
934  }
935  else if(y.size()>0 && x.size()==0)
936  {
937  this->setData(y);
938  }
939  else
940  {
941  ULOGGER_ERROR("Data vectors have not the same size.");
942  }
943 }
944 
945 void UPlotCurve::setData(const std::vector<qreal> & x, const std::vector<qreal> & y)
946 {
947  if(x.size() == y.size())
948  {
949  //match the size of the current data
950  int margin = int((_items.size()+1)/2) - int(x.size());
951  while(margin < 0)
952  {
953  UPlotItem * newItem = new UPlotItem(0, 0, 2);
954  this->_addValue(newItem);
955  ++margin;
956  }
957  while(margin > 0)
958  {
959  this->removeItem(0);
960  --margin;
961  }
962 
963  // update values
964  int index = 0;
965  std::vector<qreal>::const_iterator i=x.begin();
966  std::vector<qreal>::const_iterator j=y.begin();
967  for(; i!=x.end() && j!=y.end(); ++i, ++j, index+=2)
968  {
969  ((UPlotItem*)_items[index])->setData(QPointF(*i, *j));
970  }
971 
972  //reset minMax, this will force the plot to update the axes
973  this->updateMinMax();
974  Q_EMIT dataChanged(this);
975  }
976  else if(y.size()>0 && x.size()==0)
977  {
978  this->setData(y);
979  }
980  else
981  {
982  ULOGGER_ERROR("Data vectors have not the same size.");
983  }
984 }
985 
986 void UPlotCurve::setData(const QVector<qreal> & y)
987 {
988  this->setData(std::vector<qreal>(y.begin(), y.end()));
989 }
990 
991 void UPlotCurve::setData(const std::vector<qreal> & y)
992 {
993  //match the size of the current data
994  int margin = int((_items.size()+1)/2) - int(y.size());
995  while(margin < 0)
996  {
997  UPlotItem * newItem = new UPlotItem(0, 0, 2);
998  this->_addValue(newItem);
999  ++margin;
1000  }
1001  while(margin > 0)
1002  {
1003  this->removeItem(0);
1004  --margin;
1005  }
1006 
1007  // update values
1008  int index = 0;
1009  qreal x = 0;
1010  std::vector<qreal>::const_iterator j=y.begin();
1011  for(; j!=y.end(); ++j, index+=2)
1012  {
1013  ((UPlotItem*)_items[index])->setData(QPointF(x++, *j));
1014  }
1015 
1016  //reset minMax, this will force the plot to update the axes
1017  this->updateMinMax();
1018  Q_EMIT dataChanged(this);
1019 }
1020 
1021 void UPlotCurve::getData(QVector<qreal> & x, QVector<qreal> & y) const
1022 {
1023  x.clear();
1024  y.clear();
1025  if(_items.size())
1026  {
1027  x.resize((_items.size()-1)/2+1);
1028  y.resize(x.size());
1029  int j=0;
1030  for(int i=0; i<_items.size(); i+=2)
1031  {
1032  x[j] = ((UPlotItem*)_items.at(i))->data().x();
1033  y[j++] = ((UPlotItem*)_items.at(i))->data().y();
1034  }
1035  }
1036 }
1037 
1038 void UPlotCurve::getData(QMap<qreal,qreal> & data) const
1039 {
1040  data.clear();
1041  if(_items.size())
1042  {
1043  for(int i=0; i<_items.size(); i+=2)
1044  {
1045  data.insert(((UPlotItem*)_items.at(i))->data().x(), ((UPlotItem*)_items.at(i))->data().y());
1046  }
1047  }
1048 }
1049 
1050 
1051 
1052 
1053 
1054 UPlotCurveThreshold::UPlotCurveThreshold(const QString & name, qreal thesholdValue, Qt::Orientation orientation, QObject * parent) :
1055  UPlotCurve(name, parent),
1056  _orientation(orientation)
1057 {
1058  _threshold = thesholdValue;
1060  {
1061  this->addValue(0, thesholdValue);
1062  this->addValue(1, thesholdValue);
1063  }
1064  else
1065  {
1066  this->addValue(thesholdValue, 0);
1067  this->addValue(thesholdValue, 1);
1068  }
1069 }
1070 
1072 {
1073 
1074 }
1075 
1077 {
1078 #if PRINT_DEBUG
1079  ULOGGER_DEBUG("%f", threshold);
1080 #endif
1081  if(_items.size() == 3)
1082  {
1083  UPlotItem * item = 0;
1084  _threshold = threshold;
1086  {
1087  item = (UPlotItem*)_items.at(0);
1088  item->setData(QPointF(item->data().x(), threshold));
1089  item = (UPlotItem*)_items.at(2);
1090  item->setData(QPointF(item->data().x(), threshold));
1091  }
1092  else
1093  {
1094  item = (UPlotItem*)_items.at(0);
1095  item->setData(QPointF(threshold, item->data().y()));
1096  item = (UPlotItem*)_items.at(2);
1097  item->setData(QPointF(threshold, item->data().y()));
1098  }
1099  }
1100  else
1101  {
1102  ULOGGER_ERROR("A threshold must has only 3 items (1 PlotItem + 1 QGraphicsLineItem + 1 PlotItem)");
1103  }
1104 }
1105 
1107 {
1108  if(_orientation != orientation)
1109  {
1111  if(_items.size() == 3)
1112  {
1113  UPlotItem * item = 0;
1114  item = (UPlotItem*)_items.at(0);
1115  item->setData(QPointF(item->data().y(), item->data().x()));
1116  item = (UPlotItem*)_items.at(2);
1117  item->setData(QPointF(item->data().y(), item->data().x()));
1118  }
1119  else
1120  {
1121  ULOGGER_ERROR("A threshold must has only 3 items (1 PlotItem + 1 QGraphicsLineItem + 1 PlotItem)");
1122  }
1123  }
1124 }
1125 
1126 void UPlotCurveThreshold::update(qreal scaleX, qreal scaleY, qreal offsetX, qreal offsetY, qreal xDir, qreal yDir, int maxItemsKept)
1127 {
1128  if(_items.size() == 3)
1129  {
1130  if(_plot)
1131  {
1132  UPlotItem * item = 0;
1134  {
1135  //(xDir*item->data().x()+offsetX)*scaleX
1136  item = (UPlotItem*)_items.at(0);
1137  item->setData(QPointF(-(offsetX-item->rect().width()/scaleX)/xDir, item->data().y()));
1138  item = (UPlotItem*)_items.at(2);
1139  item->setData(QPointF( (_plot->sceneRect().width()/scaleX-(offsetX+item->rect().width()/scaleX))/xDir, item->data().y()));
1140  }
1141  else
1142  {
1143  item = (UPlotItem*)_items.at(0);
1144  item->setData(QPointF(item->data().x(), -(offsetY-item->rect().height()/scaleY)/yDir));
1145  item = (UPlotItem*)_items.at(2);
1146  item->setData(QPointF(item->data().x(), (_plot->sceneRect().height()/scaleY-(offsetY+item->rect().height()/scaleY))/yDir));
1147  }
1148  this->updateMinMax();
1149  }
1150  }
1151  else
1152  {
1153  ULOGGER_ERROR("A threshold must has only 3 items (1 PlotItem + 1 QGraphicsLineItem + 1 PlotItem)");
1154  }
1155  UPlotCurve::update(scaleX, scaleY, offsetX, offsetY, xDir, yDir, maxItemsKept);
1156 }
1157 
1158 
1159 
1160 
1161 
1162 
1163 
1164 UPlotAxis::UPlotAxis(Qt::Orientation orientation, qreal min, qreal max, QWidget * parent) :
1165  QWidget(parent),
1166  _orientation(orientation),
1167  _min(0),
1168  _max(0),
1169  _count(0),
1170  _step(0),
1171  _reversed(false),
1172  _gradMaxDigits(4),
1173  _border(0)
1174 {
1175  if(_orientation == Qt::Vertical)
1176  {
1177  _reversed = true; // default bottom->up
1178  }
1179 #ifdef _WIN32
1180  this->setMinimumSize(15, 25);
1181 #else
1182  this->setMinimumSize(15, 25);
1183 #endif
1184  this->setAxis(min, max); // this initialize all attributes
1185 }
1186 
1188 {
1189 #if PRINT_DEBUG
1190  ULOGGER_DEBUG("");
1191 #endif
1192 }
1193 
1194 // Vertical :bottom->up, horizontal :right->left
1195 void UPlotAxis::setReversed(bool reversed)
1196 {
1197  if(_reversed != reversed)
1198  {
1199  qreal min = _min;
1200  _min = _max;
1201  _max = min;
1202  }
1203  _reversed = reversed;
1204 }
1205 
1206 void UPlotAxis::setAxis(qreal & min, qreal & max)
1207 {
1208  int borderMin = 0;
1209  int borderMax = 0;
1210  if(_orientation == Qt::Vertical)
1211  {
1212  borderMin = borderMax = this->fontMetrics().height()/2;
1213  }
1214  else
1215  {
1216 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
1217  borderMin = this->fontMetrics().horizontalAdvance(QString::number(_min,'g',_gradMaxDigits))/2;
1218  borderMax = this->fontMetrics().horizontalAdvance(QString::number(_max,'g',_gradMaxDigits))/2;
1219 #else
1220  borderMin = this->fontMetrics().width(QString::number(_min,'g',_gradMaxDigits))/2;
1221  borderMax = this->fontMetrics().width(QString::number(_max,'g',_gradMaxDigits))/2;
1222 #endif
1223  }
1224  int border = borderMin>borderMax?borderMin:borderMax;
1225  int borderDelta;
1226  int length;
1227  if(_orientation == Qt::Vertical)
1228  {
1229  length = (this->height()-border*2);
1230  }
1231  else
1232  {
1233  length = (this->width()-border*2);
1234  }
1235 
1236  if(length <= 70)
1237  {
1238  _count = 5;
1239  }
1240  else if(length <= 175)
1241  {
1242  _count = 10;
1243  }
1244  else if(length <= 350)
1245  {
1246  _count = 20;
1247  }
1248  else if(length <= 700)
1249  {
1250  _count = 40;
1251  }
1252  else if(length <= 1000)
1253  {
1254  _count = 60;
1255  }
1256  else if(length <= 1300)
1257  {
1258  _count = 80;
1259  }
1260  else
1261  {
1262  _count = 100;
1263  }
1264 
1265  // Rounding min and max
1266  if(min != max)
1267  {
1268  qreal mul = 1;
1269  qreal rangef = max - min;
1270  int countStep = _count/5;
1271  qreal val;
1272  for(int i=0; i<6; ++i)
1273  {
1274  val = (rangef/qreal(countStep)) * mul;
1275  if( val >= 1.0f && val < 10.0f)
1276  {
1277  break;
1278  }
1279  else if(val<1)
1280  {
1281  mul *= 10.0f;
1282  }
1283  else
1284  {
1285  mul /= 10.0f;
1286  }
1287  }
1288  //ULOGGER_DEBUG("min=%f, max=%f", min, max);
1289  int minR = min*mul-0.9;
1290  int maxR = max*mul+0.9;
1291  min = qreal(minR)/mul;
1292  max = qreal(maxR)/mul;
1293  //ULOGGER_DEBUG("mul=%f, minR=%d, maxR=%d,countStep=%d", mul, minR, maxR, countStep);
1294  }
1295 
1296  _min = min;
1297  _max = max;
1298 
1299  if(_reversed)
1300  {
1301  _min = _max;
1302  _max = min;
1303  }
1304 
1305  if(_orientation == Qt::Vertical)
1306  {
1307  _step = length/_count;
1308  borderDelta = length - (_step*_count);
1309  }
1310  else
1311  {
1312  _step = length/_count;
1313  borderDelta = length - (_step*_count);
1314  }
1315 
1316  if(borderDelta%2 != 0)
1317  {
1318  borderDelta+=1;
1319  }
1320 
1321  _border = border + borderDelta/2;
1322 
1323  //Resize estimation
1324  if(_orientation == Qt::Vertical)
1325  {
1326  int minWidth = 0;
1327  for (int i = 0; i <= _count; i+=5)
1328  {
1329  QString n(QString::number(_min + (i/5)*((_max-_min)/(_count/5)),'g',_gradMaxDigits));
1330 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
1331  if(this->fontMetrics().horizontalAdvance(n) > minWidth)
1332  {
1333  minWidth = this->fontMetrics().horizontalAdvance(n);
1334  }
1335 #else
1336  if(this->fontMetrics().width(n) > minWidth)
1337  {
1338  minWidth = this->fontMetrics().width(n);
1339  }
1340 #endif
1341 
1342  }
1343  this->setMinimumWidth(15+minWidth);
1344  }
1345 }
1346 
1347 void UPlotAxis::paintEvent(QPaintEvent * event)
1348 {
1349  QPainter painter(this);
1350  if(_orientation == Qt::Vertical)
1351  {
1352  painter.translate(0, _border);
1353  for (int i = 0; i <= _count; ++i)
1354  {
1355  if(i%5 == 0)
1356  {
1357  painter.drawLine(this->width(), 0, this->width()-10, 0);
1358  QLabel n(QString::number(_min + (i/5)*((_max-_min)/(_count/5)),'g',_gradMaxDigits));
1359  painter.drawText(this->width()-(12+n.sizeHint().width()), n.sizeHint().height()/2-2, n.text());
1360  }
1361  else
1362  {
1363  painter.drawLine(this->width(), 0, this->width()-5, 0);
1364  }
1365  painter.translate(0, _step);
1366  }
1367  }
1368  else
1369  {
1370  painter.translate(_border, 0);
1371  for (int i = 0; i <= _count; ++i)
1372  {
1373  if(i%5 == 0)
1374  {
1375  painter.drawLine(0, 0, 0, 10);
1376  QLabel n(QString::number(_min + (i/5)*((_max-_min)/(_count/5)),'g',_gradMaxDigits));
1377  painter.drawText(-(n.sizeHint().width()/2)+1, 22, n.text());
1378  }
1379  else
1380  {
1381  painter.drawLine(0, 0, 0, 5);
1382  }
1383  painter.translate(_step, 0);
1384  }
1385  }
1386 }
1387 
1388 
1389 
1390 
1391 UPlotLegendItem::UPlotLegendItem(UPlotCurve * curve, QWidget * parent) :
1392  QPushButton(parent),
1393  _curve(curve)
1394 {
1395  QString nameSpaced = curve->name();
1396  nameSpaced.replace('_', ' ');
1397  this->setText(nameSpaced);
1398 
1399  this->setIcon(QIcon(this->createSymbol(curve->pen(), curve->brush())));
1400  this->setIconSize(QSize(25,20));
1401 
1402  _aChangeText = new QAction(tr("Change text..."), this);
1403  _aResetText = new QAction(tr("Reset text..."), this);
1404  _aChangeColor = new QAction(tr("Change color..."), this);
1405  _aCopyToClipboard = new QAction(tr("Copy curve data to clipboard"), this);
1406  _aShowStdDevMeanMax = new QAction(tr("Show %1, %2, max").arg(QChar(0xbc, 0x03)).arg(QChar(0xc3, 0x03)), this);
1407  _aShowStdDevMeanMax->setCheckable(true);
1408  _aMoveUp = new QAction(tr("Move up"), this);
1409  _aMoveDown = new QAction(tr("Move down"), this);
1410  _aRemoveCurve = new QAction(tr("Remove this curve"), this);
1411  _menu = new QMenu(tr("Curve"), this);
1412  _menu->addAction(_aChangeText);
1413  _menu->addAction(_aResetText);
1414  _menu->addAction(_aChangeColor);
1415  _menu->addAction(_aCopyToClipboard);
1416  _menu->addAction(_aShowStdDevMeanMax);
1417  _menu->addSeparator();
1418  _menu->addAction(_aMoveUp);
1419  _menu->addAction(_aMoveDown);
1420  _menu->addSeparator();
1421  _menu->addAction(_aRemoveCurve);
1422 }
1423 
1425 {
1426 
1427 }
1428 void UPlotLegendItem::contextMenuEvent(QContextMenuEvent * event)
1429 {
1430  QAction * action = _menu->exec(event->globalPos());
1431  if(action == _aChangeText)
1432  {
1433  bool ok;
1434  QString text = QInputDialog::getText(this, _aChangeText->text(), tr("Name :"), QLineEdit::Normal, this->text(), &ok);
1435  if(ok && !text.isEmpty())
1436  {
1437  this->setText(text);
1438  }
1439  }
1440  else if(action == _aResetText)
1441  {
1442  if(_curve)
1443  {
1444  this->setText(_curve->name());
1445  }
1446  }
1447  else if(action == _aChangeColor)
1448  {
1449  if(_curve)
1450  {
1451  QPen pen = _curve->pen();
1452  QColor color = QColorDialog::getColor(pen.color(), this);
1453  if(color.isValid())
1454  {
1455  pen.setColor(color);
1456  _curve->setPen(pen);
1457  this->setIcon(QIcon(this->createSymbol(_curve->pen(), _curve->brush())));
1458  }
1459  }
1460  }
1461  else if (action == _aCopyToClipboard)
1462  {
1463  if(_curve)
1464  {
1465  QVector<qreal> x;
1466  QVector<qreal> y;
1467  _curve->getData(x, y);
1468  QString text;
1469  text.append("x");
1470  text.append('\t');
1471  text.append(_curve->name());
1472  text.append('\n');
1473  for(int i=0; i<x.size(); ++i)
1474  {
1475  text.append(QString::number(x[i]));
1476  text.append('\t');
1477  text.append(QString::number(y[i]));
1478  if(i+1<x.size())
1479  {
1480  text.append('\n');
1481  }
1482  }
1483  QClipboard * clipboard = QApplication::clipboard();
1484  clipboard->setText(text);
1485  }
1486  }
1487  else if(action == _aShowStdDevMeanMax)
1488  {
1489  showStdDevMeanMax(_aShowStdDevMeanMax->isChecked());
1490  }
1491  else if(action == _aRemoveCurve)
1492  {
1493  Q_EMIT legendItemRemoved(_curve);
1494  }
1495  else if(action == _aMoveUp)
1496  {
1497  Q_EMIT moveUpRequest(this);
1498  }
1499  else if(action == _aMoveDown)
1500  {
1501  Q_EMIT moveDownRequest(this);
1502  }
1503 }
1504 
1506 {
1507  _aShowStdDevMeanMax->setChecked(shown);
1508  if(shown)
1509  {
1510  connect(_curve, SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateStdDevMeanMax()));
1512  }
1513  else
1514  {
1515  disconnect(_curve, SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateStdDevMeanMax()));
1516  QString nameSpaced = _curve->name();
1517  nameSpaced.replace('_', ' ');
1518  this->setText(nameSpaced);
1519  }
1520 }
1521 
1522 QPixmap UPlotLegendItem::createSymbol(const QPen & pen, const QBrush & brush)
1523 {
1524  QPixmap pixmap(50, 50);
1525  pixmap.fill(Qt::transparent);
1526  QPainter painter(&pixmap);
1527  QPen p = pen;
1528  p.setWidthF(4.0);
1529  painter.setPen(p);
1530  painter.drawLine(0.0, 25.0, 50.0, 25.0);
1531  return pixmap;
1532 }
1533 
1535 {
1536  QVector<qreal> x, y;
1537  _curve->getData(x, y);
1538  qreal mean = uMean(y.data(), y.size());
1539  qreal stdDev = std::sqrt(uVariance(y.data(), y.size(), mean));
1540  qreal max = uMax(y.data(), y.size());
1541  QString nameSpaced = _curve->name();
1542  nameSpaced.replace('_', ' ');
1543  nameSpaced += QString("\n(%1=%2, %3=%4, max=%5, n=%6)").arg(QChar(0xbc, 0x03)).arg(QString::number(mean, 'f', 3)).arg(QChar(0xc3, 0x03)).arg(QString::number(stdDev, 'f', 3)).arg(QString::number(max, 'f', 3)).arg(y.size());
1544  this->setText(nameSpaced);
1545 }
1546 
1547 
1548 
1549 
1550 
1551 
1552 UPlotLegend::UPlotLegend(QWidget * parent) :
1553  QWidget(parent),
1554  _flat(true)
1555 {
1556  //menu
1557  _aUseFlatButtons = new QAction(tr("Use flat buttons"), this);
1558  _aUseFlatButtons->setCheckable(true);
1559  _aUseFlatButtons->setChecked(_flat);
1560  _aCopyAllCurvesToClipboard = new QAction(tr("Copy all curve data to clipboard"), this);
1561  _aShowAllStdDevMeanMax = new QAction(tr("Show all %1, %2, max").arg(QChar(0xbc, 0x03)).arg(QChar(0xc3, 0x03)), this);
1562  _aShowAllStdDevMeanMax->setCheckable(true);
1563  _aShowAllStdDevMeanMax->setChecked(false);
1564  _menu = new QMenu(tr("Legend"), this);
1565  _menu->addAction(_aUseFlatButtons);
1566  _menu->addAction(_aShowAllStdDevMeanMax);
1567  _menu->addAction(_aCopyAllCurvesToClipboard);
1568 
1569  _scrollArea = new QScrollArea(this);
1570  _scrollArea->setWidgetResizable( true );
1571  _scrollArea->setFrameShape(QFrame::NoFrame);
1572 
1573  this->setLayout(new QVBoxLayout());
1574  this->layout()->setContentsMargins(0,0,0,0);
1575  this->layout()->addWidget(_scrollArea);
1576 
1577  QWidget * _scrollAreaWidgetContent = new QWidget();
1578  _scrollArea->setWidget( _scrollAreaWidgetContent );
1579 
1580  _contentLayout = new QVBoxLayout();
1581  _scrollAreaWidgetContent->setLayout(_contentLayout);
1582  _contentLayout->setContentsMargins(0,0,0,0);
1583  ((QVBoxLayout*)_contentLayout)->addStretch(0);
1584  _contentLayout->setSpacing(0);
1585 }
1586 
1588 {
1589 #if PRINT_DEBUG
1590  ULOGGER_DEBUG("");
1591 #endif
1592 }
1593 
1595 {
1596  if(_flat != on)
1597  {
1598  _flat = on;
1599  QList<UPlotLegendItem*> items = this->findChildren<UPlotLegendItem*>();
1600  for(int i=0; i<items.size(); ++i)
1601  {
1602  items.at(i)->setFlat(_flat);
1603  items.at(i)->setChecked(!items.at(i)->isChecked());
1604  }
1605  _aUseFlatButtons->setChecked(_flat);
1606  }
1607 }
1608 
1610 {
1611  if(curve)
1612  {
1613  UPlotLegendItem * legendItem = new UPlotLegendItem(curve, this);
1614  legendItem->setAutoDefault(false);
1615  legendItem->setFlat(_flat);
1616  legendItem->setCheckable(true);
1617  legendItem->setChecked(false);
1618  connect(legendItem, SIGNAL(toggled(bool)), this, SLOT(redirectToggled(bool)));
1619  connect(legendItem, SIGNAL(legendItemRemoved(const UPlotCurve *)), this, SLOT(removeLegendItem(const UPlotCurve *)));
1620  connect(legendItem, SIGNAL(moveUpRequest(UPlotLegendItem *)), this, SLOT(moveUp(UPlotLegendItem *)));
1621  connect(legendItem, SIGNAL(moveDownRequest(UPlotLegendItem *)), this, SLOT(moveDown(UPlotLegendItem *)));
1622 
1623  // layout
1624  QHBoxLayout * hLayout = new QHBoxLayout();
1625  hLayout->addWidget(legendItem);
1626  hLayout->addStretch(0);
1627  hLayout->setContentsMargins(0,0,0,0);
1628 
1629  // add to the legend
1630  ((QVBoxLayout*)_contentLayout)->insertLayout(_contentLayout->count()-1, hLayout);
1631 
1632  _scrollArea->setMinimumWidth(std::min(480, _scrollArea->widget()->sizeHint().width()+QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent)));
1633  }
1634 }
1635 
1636 bool UPlotLegend::remove(const UPlotCurve * curve)
1637 {
1638  QList<UPlotLegendItem *> items = this->findChildren<UPlotLegendItem*>();
1639  for(int i=0; i<items.size(); ++i)
1640  {
1641  if(items.at(i)->curve() == curve)
1642  {
1643  delete items.at(i);
1644  _scrollArea->setMinimumWidth(std::min(480, _scrollArea->widget()->sizeHint().width()+QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent)));
1645  return true;
1646  }
1647  }
1648  return false;
1649 }
1650 
1652 {
1653  if(this->remove(curve))
1654  {
1655  Q_EMIT legendItemRemoved(curve);
1656  }
1657 }
1658 
1660 {
1661  int index = -1;
1662  QLayoutItem * layoutItem = 0;
1663  for(int i=0; i<_contentLayout->count(); ++i)
1664  {
1665  if(_contentLayout->itemAt(i)->layout() &&
1666  _contentLayout->itemAt(i)->layout()->indexOf(item) != -1)
1667  {
1668  layoutItem = _contentLayout->itemAt(i);
1669  index = i;
1670  break;
1671  }
1672  }
1673  if(index > 0 && layoutItem)
1674  {
1675  _contentLayout->removeItem(layoutItem);
1676  QHBoxLayout * hLayout = new QHBoxLayout();
1677  hLayout->addWidget(layoutItem->layout()->itemAt(0)->widget());
1678  hLayout->addStretch(0);
1679  hLayout->setContentsMargins(0,0,0,0);
1680  ((QVBoxLayout*)_contentLayout)->insertLayout(index-1, hLayout);
1681  delete layoutItem;
1682  Q_EMIT legendItemMoved(item->curve(), index-1);
1683  }
1684 }
1685 
1687 {
1688  int index = -1;
1689  QLayoutItem * layoutItem = 0;
1690  for(int i=0; i<_contentLayout->count(); ++i)
1691  {
1692  if(_contentLayout->itemAt(i)->layout() &&
1693  _contentLayout->itemAt(i)->layout()->indexOf(item) != -1)
1694  {
1695  layoutItem = _contentLayout->itemAt(i);
1696  index = i;
1697  break;
1698  }
1699  }
1700  if(index < _contentLayout->count()-2 && layoutItem)
1701  {
1702  _contentLayout->removeItem(layoutItem);
1703  QHBoxLayout * hLayout = new QHBoxLayout();
1704  hLayout->addWidget(layoutItem->layout()->itemAt(0)->widget());
1705  hLayout->addStretch(0);
1706  hLayout->setContentsMargins(0,0,0,0);
1707  ((QVBoxLayout*)_contentLayout)->insertLayout(index+1, hLayout);
1708  delete layoutItem;
1709  Q_EMIT legendItemMoved(item->curve(), index+1);
1710  }
1711 }
1712 
1714 {
1715  QList<UPlotLegendItem *> items = this->findChildren<UPlotLegendItem*>();
1716  if(items.size())
1717  {
1718  // create common x-axis
1719  QMap<qreal, qreal> xAxisMap;
1720  for(int i=0; i<items.size(); ++i)
1721  {
1722  QMap<qreal, qreal> data;
1723  items.at(i)->curve()->getData(data);
1724  for(QMap<qreal, qreal>::iterator iter=data.begin(); iter!=data.end(); ++iter)
1725  {
1726  xAxisMap.insert(iter.key(), iter.value());
1727  }
1728  }
1729  QList<qreal> xAxis = xAxisMap.keys();
1730 
1731  QVector<QVector<qreal> > axes;
1732  for(int i=0; i<items.size(); ++i)
1733  {
1734  QMap<qreal, qreal> data;
1735  items.at(i)->curve()->getData(data);
1736 
1737  QVector<qreal> y(xAxis.size(), std::numeric_limits<qreal>::quiet_NaN());
1738  // just to make sure that we have the same number of data on each curve, set NAN for unknowns
1739  int j=0;
1740  for(QList<qreal>::iterator iter=xAxis.begin(); iter!=xAxis.end(); ++iter)
1741  {
1742  if(data.contains(*iter))
1743  {
1744  y[j] = data.value(*iter);
1745  }
1746  ++j;
1747  }
1748  axes.push_back(y);
1749  }
1750  if(!xAxis.empty())
1751  {
1752  axes.push_front(xAxis.toVector());
1753  QString text;
1754  text.append('x');
1755  text.append('\t');
1756  for(int i=0; i<items.size(); ++i)
1757  {
1758  text.append(items.at(i)->curve()->name());
1759  if(i+1<axes.size())
1760  {
1761  text.append('\t');
1762  }
1763  }
1764  text.append('\n');
1765  for(int i=0; i<axes[0].size(); ++i)
1766  {
1767  for(int j=0; j<axes.size(); ++j)
1768  {
1769  if(uIsNan(axes[j][i]))
1770  {
1771  text.append("NaN"); // NaN is interpreted by default as NaN in MatLab/Octave
1772  }
1773  else
1774  {
1775  text.append(QString::number(axes[j][i], 'f'));
1776  }
1777  if(j+1<axes.size())
1778  {
1779  text.append('\t');
1780  }
1781  }
1782  if(i+1<axes[0].size())
1783  {
1784  text.append("\n");
1785  }
1786  }
1787  return text;
1788  }
1789  }
1790  return "";
1791 }
1792 
1793 void UPlotLegend::contextMenuEvent(QContextMenuEvent * event)
1794 {
1795  QAction * action = _menu->exec(event->globalPos());
1796  if(action == _aUseFlatButtons)
1797  {
1798  this->setFlat(_aUseFlatButtons->isChecked());
1799  }
1800  else if(action == _aCopyAllCurvesToClipboard)
1801  {
1802  QString data = getAllCurveDataAsText();
1803  if(!data.isEmpty())
1804  {
1805  QClipboard * clipboard = QApplication::clipboard();
1806  clipboard->setText(data);
1807  }
1808  }
1809  else if(action == _aShowAllStdDevMeanMax)
1810  {
1811  QList<UPlotLegendItem *> items = this->findChildren<UPlotLegendItem*>();
1812  for(int i=0; i<items.size(); ++i)
1813  {
1814  items.at(i)->showStdDevMeanMax(_aShowAllStdDevMeanMax->isChecked());
1815  }
1816  }
1817 }
1818 
1820 {
1821  if(sender())
1822  {
1823  UPlotLegendItem * item = qobject_cast<UPlotLegendItem*>(sender());
1824  if(item)
1825  {
1826  Q_EMIT legendItemToggled(item->curve(), _flat?!toggled:toggled);
1827  }
1828  }
1829 }
1830 
1831 
1832 
1833 
1834 
1835 
1836 
1837 UOrientableLabel::UOrientableLabel(const QString & text, Qt::Orientation orientation, QWidget * parent) :
1838  QLabel(text, parent),
1839  _orientation(orientation)
1840 {
1841 }
1842 
1844 {
1845 }
1846 
1848 {
1849  QSize size = QLabel::sizeHint();
1850  if (_orientation == Qt::Vertical)
1851  size.transpose();
1852  return size;
1853 
1854 }
1855 
1857 {
1858  QSize size = QLabel::minimumSizeHint();
1859  if (_orientation == Qt::Vertical)
1860  size.transpose();
1861  return size;
1862 }
1863 
1865 {
1867  switch(orientation)
1868  {
1869  case Qt::Horizontal:
1870  setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
1871  break;
1872 
1873  case Qt::Vertical:
1874  setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
1875  break;
1876  }
1877 }
1878 
1879 void UOrientableLabel::paintEvent(QPaintEvent* event)
1880 {
1881  QPainter p(this);
1882  QRect r = rect();
1883  switch (_orientation)
1884  {
1885  case Qt::Horizontal:
1886  break;
1887  case Qt::Vertical:
1888  p.rotate(-90);
1889  p.translate(-height(), 0);
1890  QSize size = r.size();
1891  size.transpose();
1892  r.setSize(size);
1893  break;
1894  }
1895  p.drawText(r, this->alignment() | (this->wordWrap()?Qt::TextWordWrap:0), this->text());
1896 }
1897 
1898 
1899 
1900 
1901 
1902 
1903 
1904 
1905 
1906 
1907 
1908 
1909 
1910 UPlot::UPlot(QWidget *parent) :
1911  QWidget(parent),
1912  _legend(0),
1913  _view(0),
1914  _sceneRoot(0),
1915  _graphicsViewHolder(0),
1916  _verticalAxis(0),
1917  _horizontalAxis(0),
1918  _penStyleCount(0),
1919  _maxVisibleItems(-1),
1920  _title(0),
1921  _xLabel(0),
1922  _yLabel(0),
1923  _refreshRate(0),
1924  _workingDirectory(QDir::homePath()),
1925  _lowestRefreshRate(99),
1926  _autoScreenCaptureFormat("png"),
1927  _bgColor(Qt::white),
1928  _menu(0),
1929  _aShowLegend(0),
1930  _aShowGrid(0),
1931  _aKeepAllData(0),
1932  _aLimit0(0),
1933  _aLimit10(0),
1934  _aLimit50(0),
1935  _aLimit100(0),
1936  _aLimit500(0),
1937  _aLimit1000(0),
1938  _aLimitCustom(0),
1939  _aAddVerticalLine(0),
1940  _aAddHorizontalLine(0),
1941  _aChangeTitle(0),
1942  _aChangeXLabel(0),
1943  _aChangeYLabel(0),
1944  _aChangeBackgroundColor(0),
1945  _aYLabelVertical(0),
1946  _aShowRefreshRate(0),
1947  _aMouseTracking(0),
1948  _aSaveFigure(0),
1949  _aAutoScreenCapture(0),
1950  _aClearData(0),
1951  _aGraphicsView(0)
1952 {
1953  this->setupUi();
1954  this->createActions();
1955  this->createMenus();
1956 
1957  // This will update actions
1958  this->showLegend(true);
1959  this->setGraphicsView(false);
1960  this->setMaxVisibleItems(0);
1961  this->showGrid(false);
1962  this->showRefreshRate(false);
1963  this->keepAllData(true);
1964 
1965  for(int i=0; i<4; ++i)
1966  {
1967  _axisMaximums[i] = 0;
1968  _axisMaximumsSet[i] = false;
1969  if(i<2)
1970  {
1971  _fixedAxis[i] = false;
1972  }
1973  }
1974 
1975  _mouseCurrentPos = _mousePressedPos; // for zooming
1976 
1977  _refreshIntervalTime.start();
1978  _refreshStartTime.start();
1979 }
1980 
1982 {
1983  _aAutoScreenCapture->setChecked(false);
1984 #if PRINT_DEBUG
1985  ULOGGER_DEBUG("%s", this->title().toStdString().c_str());
1986 #endif
1987  this->removeCurves();
1988 }
1989 
1991 {
1992  _legend = new UPlotLegend(this);
1993  _view = new QGraphicsView(this);
1994  _view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1995  _view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1996  _view->setScene(new QGraphicsScene(0,0,0,0,this));
1997  _view->setStyleSheet( "QGraphicsView { border-style: none; }" );
1998  _sceneRoot = _view->scene()->addText("");
1999  _sceneRoot->setTransform(QTransform::fromTranslate(0, 0), true);
2000  _graphicsViewHolder = new QWidget(this);
2001  _graphicsViewHolder->setMinimumSize(100,100);
2002  _graphicsViewHolder->setMouseTracking(true);
2003  _verticalAxis = new UPlotAxis(Qt::Vertical, 0, 1, this);
2004  _horizontalAxis = new UPlotAxis(Qt::Horizontal, 0, 1, this);
2005  _title = new QLabel("");
2006  _xLabel = new QLabel("");
2007  _refreshRate = new QLabel("");
2008  _yLabel = new UOrientableLabel("");
2010  _title->setAlignment(Qt::AlignCenter);
2011  _xLabel->setAlignment(Qt::AlignCenter);
2012  _yLabel->setAlignment(Qt::AlignCenter);
2013  _refreshRate->setAlignment(Qt::AlignCenter);
2014  _title->setWordWrap(true);
2015  _xLabel->setWordWrap(true);
2016  _yLabel->setWordWrap(true);
2017  _title->setVisible(false);
2018  _xLabel->setVisible(false);
2019  _yLabel->setVisible(false);
2020  _refreshRate->setVisible(false);
2021 
2022  //layouts
2023  QVBoxLayout * vLayout = new QVBoxLayout(_graphicsViewHolder);
2024  vLayout->setContentsMargins(0,0,0,0);
2025  vLayout->addWidget(_view);
2026 
2027  QGridLayout * grid = new QGridLayout(this);
2028  grid->setContentsMargins(0,0,0,0);
2029  grid->addWidget(_title, 0, 2);
2030  grid->addWidget(_yLabel, 1, 0);
2031  grid->addWidget(_verticalAxis, 1, 1);
2032  grid->addWidget(_refreshRate, 2, 1);
2033  grid->addWidget(_graphicsViewHolder, 1, 2);
2034  grid->setColumnStretch(2, 1);
2035  grid->setRowStretch(1, 1);
2036  grid->addWidget(_horizontalAxis, 2, 2);
2037  grid->addWidget(_xLabel, 3, 2);
2038  grid->addWidget(_legend, 1, 3);
2039 
2040  connect(_legend, SIGNAL(legendItemToggled(const UPlotCurve *, bool)), this, SLOT(showCurve(const UPlotCurve *, bool)));
2041  connect(_legend, SIGNAL(legendItemRemoved(const UPlotCurve *)), this, SLOT(removeCurve(const UPlotCurve *)));
2042  connect(_legend, SIGNAL(legendItemMoved(const UPlotCurve *, int)), this, SLOT(moveCurve(const UPlotCurve *, int)));
2043 }
2044 
2046 {
2047  _aShowLegend = new QAction(tr("Show legend"), this);
2048  _aShowLegend->setCheckable(true);
2049  _aShowGrid = new QAction(tr("Show grid"), this);
2050  _aShowGrid->setCheckable(true);
2051  _aShowRefreshRate = new QAction(tr("Show refresh rate"), this);
2052  _aShowRefreshRate->setCheckable(true);
2053  _aMouseTracking = new QAction(tr("Mouse tracking"), this);
2054  _aMouseTracking->setCheckable(true);
2055  _aGraphicsView = new QAction(tr("Graphics view"), this);
2056  _aGraphicsView->setCheckable(true);
2057  _aKeepAllData = new QAction(tr("Keep all data"), this);
2058  _aKeepAllData->setCheckable(true);
2059  _aLimit0 = new QAction(tr("No maximum items shown"), this);
2060  _aLimit10 = new QAction(tr("10"), this);
2061  _aLimit50 = new QAction(tr("50"), this);
2062  _aLimit100 = new QAction(tr("100"), this);
2063  _aLimit500 = new QAction(tr("500"), this);
2064  _aLimit1000 = new QAction(tr("1000"), this);
2065  _aLimitCustom = new QAction(tr(""), this);
2066  _aLimit0->setCheckable(true);
2067  _aLimit10->setCheckable(true);
2068  _aLimit50->setCheckable(true);
2069  _aLimit100->setCheckable(true);
2070  _aLimit500->setCheckable(true);
2071  _aLimit1000->setCheckable(true);
2072  _aLimitCustom->setCheckable(true);
2073  _aLimitCustom->setVisible(false);
2074  _aAddVerticalLine = new QAction(tr("Vertical line..."), this);
2075  _aAddHorizontalLine = new QAction(tr("Horizontal line..."), this);
2076  _aChangeTitle = new QAction(tr("Change title"), this);
2077  _aChangeXLabel = new QAction(tr("Change X label..."), this);
2078  _aChangeYLabel = new QAction(tr("Change Y label..."), this);
2079  _aChangeBackgroundColor = new QAction(tr("Change bg color..."), this);
2080  _aYLabelVertical = new QAction(tr("Vertical orientation"), this);
2081  _aYLabelVertical->setCheckable(true);
2082  _aYLabelVertical->setChecked(true);
2083  _aSaveFigure = new QAction(tr("Save figure..."), this);
2084  _aAutoScreenCapture = new QAction(tr("Auto screen capture..."), this);
2085  _aAutoScreenCapture->setCheckable(true);
2086  _aClearData = new QAction(tr("Clear data"), this);
2087 
2088  QActionGroup * grpLimit = new QActionGroup(this);
2089  grpLimit->addAction(_aLimit0);
2090  grpLimit->addAction(_aLimit10);
2091  grpLimit->addAction(_aLimit50);
2092  grpLimit->addAction(_aLimit100);
2093  grpLimit->addAction(_aLimit500);
2094  grpLimit->addAction(_aLimit1000);
2095  grpLimit->addAction(_aLimitCustom);
2096  _aLimit0->setChecked(true);
2097 }
2098 
2100 {
2101  _menu = new QMenu(tr("Plot"), this);
2102  _menu->addAction(_aShowLegend);
2103  _menu->addAction(_aShowGrid);
2104  _menu->addAction(_aShowRefreshRate);
2105  _menu->addAction(_aMouseTracking);
2106  _menu->addAction(_aGraphicsView);
2107  _menu->addAction(_aKeepAllData);
2108  _menu->addSeparator()->setStatusTip(tr("Maximum items shown"));
2109  _menu->addAction(_aLimit0);
2110  _menu->addAction(_aLimit10);
2111  _menu->addAction(_aLimit50);
2112  _menu->addAction(_aLimit100);
2113  _menu->addAction(_aLimit500);
2114  _menu->addAction(_aLimit1000);
2115  _menu->addAction(_aLimitCustom);
2116  _menu->addSeparator();
2117  QMenu * addLineMenu = _menu->addMenu(tr("Add line"));
2118  addLineMenu->addAction(_aAddHorizontalLine);
2119  addLineMenu->addAction(_aAddVerticalLine);
2120  _menu->addSeparator();
2121  _menu->addAction(_aChangeTitle);
2122  _menu->addAction(_aChangeXLabel);
2123  QMenu * yLabelMenu = _menu->addMenu(tr("Y label"));
2124  yLabelMenu->addAction(_aChangeYLabel);
2125  yLabelMenu->addAction(_aYLabelVertical);
2126  _menu->addAction(_aChangeBackgroundColor);
2127  _menu->addAction(_aSaveFigure);
2128  _menu->addAction(_aAutoScreenCapture);
2129  _menu->addSeparator();
2130  _menu->addAction(_aClearData);
2131 
2132 }
2133 
2134 UPlotCurve * UPlot::addCurve(const QString & curveName, const QColor & color)
2135 {
2136  // add curve
2137  UPlotCurve * curve = new UPlotCurve(curveName, this);
2138  if(color.isValid())
2139  {
2140  curve->setPen(color);
2141  }
2142  else
2143  {
2144  curve->setPen(this->getRandomPenColored());
2145  }
2146  this->addCurve(curve);
2147  return curve;
2148 }
2149 
2150 bool UPlot::addCurve(UPlotCurve * curve, bool ownershipTransferred)
2151 {
2152  if(curve)
2153  {
2154 #if PRINT_DEBUG
2155  ULOGGER_DEBUG("Adding curve \"%s\" to plot \"%s\"...", curve->name().toStdString().c_str(), this->title().toStdString().c_str());
2156 #endif
2157  // only last curve can trigger an update, so disable previous connections
2158  if(!qobject_cast<UPlotCurveThreshold*>(curve))
2159  {
2160  for(int i=_curves.size()-1; i>=0; --i)
2161  {
2162  if(!qobject_cast<UPlotCurveThreshold*>(_curves.at(i)))
2163  {
2164  disconnect(_curves.at(i), SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateAxis()));
2165  break;
2166  }
2167  }
2168  }
2169 
2170  // add curve
2171  _curves.append(curve);
2172  curve->attach(this);
2173  curve->setItemsColor(QColor(255-_bgColor.red(), 255-_bgColor.green(), 255-_bgColor.red(), _bgColor.alpha()));
2174  if(ownershipTransferred)
2175  {
2176  curve->setParent(this);
2177  }
2178  this->updateAxis(curve);
2179  curve->setXStart(_axisMaximums[1]);
2180 
2181  connect(curve, SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateAxis()));
2182 
2183  _legend->addItem(curve);
2184 
2185 #if PRINT_DEBUG
2186  ULOGGER_DEBUG("Curve \"%s\" added to plot \"%s\"", curve->name().toStdString().c_str(), this->title().toStdString().c_str());
2187 #endif
2188 
2189  return true;
2190  }
2191  else
2192  {
2193  ULOGGER_ERROR("The curve is null!");
2194  }
2195  return false;
2196 }
2197 
2198 QStringList UPlot::curveNames() const
2199 {
2200  QStringList names;
2201  for(QList<UPlotCurve*>::const_iterator iter = _curves.constBegin(); iter!=_curves.constEnd(); ++iter)
2202  {
2203  if(*iter)
2204  {
2205  names.append((*iter)->name());
2206  }
2207  }
2208  return names;
2209 }
2210 
2211 bool UPlot::isThreshold(const QString & curveName) const
2212 {
2213  for(QList<UPlotCurve*>::const_iterator iter = _curves.constBegin(); iter!=_curves.constEnd(); ++iter)
2214  {
2215  if(*iter && (*iter)->name().compare(curveName) == 0)
2216  {
2217  return qobject_cast<UPlotCurveThreshold*>(*iter) != 0;
2218  }
2219  }
2220  return false;
2221 }
2222 
2223 double UPlot::getThresholdValue(const QString & curveName) const
2224 {
2225  for(QList<UPlotCurve*>::const_iterator iter = _curves.constBegin(); iter!=_curves.constEnd(); ++iter)
2226  {
2227  if(*iter && (*iter)->name().compare(curveName) == 0)
2228  {
2229  UPlotCurveThreshold* curve = qobject_cast<UPlotCurveThreshold*>(*iter);
2230  if(curve)
2231  {
2232  return curve->getThreshold();
2233  }
2234  }
2235  }
2236  UERROR("Curve \"%s\" not found as theshold!", curveName.toStdString().c_str());
2237  return 0;
2238 }
2239 
2240 bool UPlot::contains(const QString & curveName) const
2241 {
2242  for(QList<UPlotCurve*>::const_iterator iter = _curves.constBegin(); iter!=_curves.constEnd(); ++iter)
2243  {
2244  if(*iter && (*iter)->name().compare(curveName) == 0)
2245  {
2246  return true;
2247  }
2248  }
2249  return false;
2250 }
2251 
2253 {
2254  int penStyle = 0;
2255  bool colorNotUsed = false;
2256  for(int i=0; i<12; ++i)
2257  {
2258  QColor tmp((Qt::GlobalColor)((penStyle+i) % 12 + 7 ));
2259  bool colorAlreadyUsed = false;
2260  for(QList<UPlotCurve*>::const_iterator iter = _curves.constBegin(); iter!=_curves.constEnd() && !colorAlreadyUsed; ++iter)
2261  {
2262  colorAlreadyUsed = (*iter)->pen().color() == tmp;
2263  }
2264  if(!colorAlreadyUsed)
2265  {
2266  colorNotUsed = true;
2267  penStyle+=i;
2268  break;
2269  }
2270  }
2271  if(colorNotUsed)
2272  {
2273  _penStyleCount = penStyle;
2274  }
2275 
2276  return QPen((Qt::GlobalColor)(_penStyleCount++ % 12 + 7 ));
2277 }
2278 
2279 void UPlot::replot(QPainter * painter)
2280 {
2281  if(_maxVisibleItems>0)
2282  {
2283  UPlotCurve * c = 0;
2284  int maxItem = 0;
2285  // find the curve with the most items
2286  for(QList<UPlotCurve *>::iterator i=_curves.begin(); i!=_curves.end(); ++i)
2287  {
2288  if((*i)->isVisible() && ((UPlotCurve *)(*i))->itemsSize() > maxItem)
2289  {
2290  c = *i;
2291  maxItem = c->itemsSize();
2292  }
2293  }
2294  if(c && (maxItem-1)/2+1 > _maxVisibleItems && _axisMaximums[0] < c->getItemData((c->itemsSize()-1) -_maxVisibleItems*2).x())
2295  {
2296  _axisMaximums[0] = c->getItemData((c->itemsSize()-1) -_maxVisibleItems*2).x();
2297  }
2298  }
2299 
2300  qreal axis[4] = {0};
2301  for(int i=0; i<4; ++i)
2302  {
2303  axis[i] = _axisMaximums[i];
2304  }
2305 
2306  _verticalAxis->setAxis(axis[2], axis[3]);
2307  _horizontalAxis->setAxis(axis[0], axis[1]);
2308  if(_aGraphicsView->isChecked() && !painter)
2309  {
2310  _verticalAxis->update();
2311  _horizontalAxis->update();
2312  }
2313 
2314  //ULOGGER_DEBUG("x1=%f, x2=%f, y1=%f, y2=%f", _axisMaximums[0], _axisMaximums[1], _axisMaximums[2], _axisMaximums[3]);
2315 
2316  QRectF newRect(0,0, _graphicsViewHolder->size().width(), _graphicsViewHolder->size().height());
2317  _view->scene()->setSceneRect(newRect);
2318  qreal borderHor = (qreal)_horizontalAxis->border();
2319  qreal borderVer = (qreal)_verticalAxis->border();
2320 
2321  //grid
2322  qDeleteAll(hGridLines);
2323  hGridLines.clear();
2324  qDeleteAll(vGridLines);
2325  vGridLines.clear();
2326  if(_aShowGrid->isChecked())
2327  {
2328  // TODO make a PlotGrid class ?
2329  qreal w = newRect.width()-(borderHor*2);
2330  qreal h = newRect.height()-(borderVer*2);
2331  qreal stepH = w / qreal(_horizontalAxis->count());
2332  qreal stepV = h / qreal(_verticalAxis->count());
2333  QPen dashPen(Qt::DashLine);
2334  dashPen.setColor(QColor(255-_bgColor.red(), 255-_bgColor.green(), 255-_bgColor.blue(), 100));
2335  QPen pen(dashPen.color());
2336  for(qreal i=0.0f; i*stepV <= h+stepV; i+=5.0f)
2337  {
2338  //horizontal lines
2339  if(!_aGraphicsView->isChecked())
2340  {
2341  if(painter)
2342  {
2343  painter->save();
2344  painter->setPen(pen);
2345  painter->drawLine(0, stepV*i+borderVer+0.5f, borderHor, stepV*i+borderVer+0.5f);
2346 
2347  painter->setPen(dashPen);
2348  painter->drawLine(borderHor, stepV*i+borderVer+0.5f, w+borderHor, stepV*i+borderVer+0.5f);
2349 
2350  painter->setPen(pen);
2351  painter->drawLine(w+borderHor, stepV*i+borderVer+0.5f, w+borderHor*2, stepV*i+borderVer+0.5f);
2352  painter->restore();
2353  }
2354  }
2355  else
2356  {
2357  hGridLines.append(new QGraphicsLineItem(0, stepV*i+borderVer, borderHor, stepV*i+borderVer, _sceneRoot));
2358  hGridLines.last()->setPen(pen);
2359  hGridLines.append(new QGraphicsLineItem(borderHor, stepV*i+borderVer, w+borderHor, stepV*i+borderVer, _sceneRoot));
2360  hGridLines.last()->setPen(dashPen);
2361  hGridLines.append(new QGraphicsLineItem(w+borderHor, stepV*i+borderVer, w+borderHor*2, stepV*i+borderVer, _sceneRoot));
2362  hGridLines.last()->setPen(pen);
2363  }
2364  }
2365  for(qreal i=0; i*stepH < w+stepH; i+=5.0f)
2366  {
2367  //vertical lines
2368  if(!_aGraphicsView->isChecked())
2369  {
2370  if(painter)
2371  {
2372  painter->save();
2373  painter->setPen(pen);
2374  painter->drawLine(stepH*i+borderHor+0.5f, 0, stepH*i+borderHor+0.5f, borderVer);
2375 
2376  painter->setPen(dashPen);
2377  painter->drawLine(stepH*i+borderHor+0.5f, borderVer, stepH*i+borderHor+0.5f, h+borderVer);
2378 
2379  painter->setPen(pen);
2380  painter->drawLine(stepH*i+borderHor+0.5f, h+borderVer, stepH*i+borderHor+0.5f, h+borderVer*2);
2381  painter->restore();
2382  }
2383  }
2384  else
2385  {
2386  vGridLines.append(new QGraphicsLineItem(stepH*i+borderHor, 0, stepH*i+borderHor, borderVer, _sceneRoot));
2387  vGridLines.last()->setPen(pen);
2388  vGridLines.append(new QGraphicsLineItem(stepH*i+borderHor, borderVer, stepH*i+borderHor, h+borderVer, _sceneRoot));
2389  vGridLines.last()->setPen(dashPen);
2390  vGridLines.append(new QGraphicsLineItem(stepH*i+borderHor, h+borderVer, stepH*i+borderHor, h+borderVer*2, _sceneRoot));
2391  vGridLines.last()->setPen(pen);
2392  }
2393  }
2394  }
2395 
2396  // curves
2397  qreal scaleX = 1;
2398  qreal scaleY = 1;
2399  qreal den = 0;
2400  den = axis[1] - axis[0];
2401  if(den != 0)
2402  {
2403  scaleX = (newRect.width()-(borderHor*2)) / den;
2404  }
2405  den = axis[3] - axis[2];
2406  if(den != 0)
2407  {
2408  scaleY = (newRect.height()-(borderVer*2)) / den;
2409  }
2410  for(QList<UPlotCurve *>::iterator i=_curves.begin(); i!=_curves.end(); ++i)
2411  {
2412  if((*i)->isVisible())
2413  {
2414  qreal xDir = 1.0f;
2415  qreal yDir = -1.0f;
2416  (*i)->update(scaleX,
2417  scaleY,
2418  xDir<0?axis[1]+borderHor/scaleX:-(axis[0]-borderHor/scaleX),
2419  yDir<0?axis[3]+borderVer/scaleY:-(axis[2]-borderVer/scaleY),
2420  xDir,
2421  yDir,
2422  _aKeepAllData->isChecked()?0:_maxVisibleItems);
2423  if(painter)
2424  {
2425  (*i)->draw(painter, QRect(0,0,_graphicsViewHolder->rect().width(), _graphicsViewHolder->rect().height()));
2426  }
2427  }
2428  }
2429 
2430  // Update refresh rate
2431  if(_aShowRefreshRate->isChecked())
2432  {
2433  int refreshRate = qRound(1000.0f/qreal(_refreshIntervalTime.restart()));
2434  if(refreshRate > 0 && refreshRate < _lowestRefreshRate)
2435  {
2436  _lowestRefreshRate = refreshRate;
2437  }
2438  // Refresh the label only after each 1000 ms
2439  if(_refreshStartTime.elapsed() > 1000)
2440  {
2441  _refreshRate->setText(QString::number(_lowestRefreshRate));
2442  _lowestRefreshRate = 99;
2443  _refreshStartTime.start();
2444  }
2445  }
2446 }
2447 
2448 void UPlot::setFixedXAxis(qreal x1, qreal x2)
2449 {
2450  _fixedAxis[0] = true;
2451  _axisMaximums[0] = x1;
2452  _axisMaximums[1] = x2;
2453 }
2454 
2455 void UPlot::setFixedYAxis(qreal y1, qreal y2)
2456 {
2457  _fixedAxis[1] = true;
2458  _axisMaximums[2] = y1;
2459  _axisMaximums[3] = y2;
2460 }
2461 
2462 void UPlot::updateAxis(const UPlotCurve * curve)
2463 {
2464  if(curve && curve->isVisible() && curve->itemsSize() && curve->isMinMaxValid())
2465  {
2466  const QVector<qreal> & minMax = curve->getMinMax();
2467  //ULOGGER_DEBUG("x1=%f, x2=%f, y1=%f, y2=%f", minMax[0], minMax[1], minMax[2], minMax[3]);
2468  if(minMax.size() != 4)
2469  {
2470  ULOGGER_ERROR("minMax size != 4 ?!?");
2471  return;
2472  }
2473  this->updateAxis(minMax[0], minMax[1], minMax[2], minMax[3]);
2474  _aGraphicsView->isChecked()?this->replot(0):this->update();
2475  }
2476 }
2477 
2478 bool UPlot::updateAxis(qreal x1, qreal x2, qreal y1, qreal y2)
2479 {
2480  bool modified = false;
2481  modified = updateAxis(x1,y1);
2482  if(!modified)
2483  {
2484  modified = updateAxis(x2,y2);
2485  }
2486  else
2487  {
2488  updateAxis(x2,y2);
2489  }
2490  return modified;
2491 }
2492 
2493 bool UPlot::updateAxis(qreal x, qreal y)
2494 {
2495  //ULOGGER_DEBUG("x=%f, y=%f", x,y);
2496  bool modified = false;
2497  if(!_fixedAxis[0] && (!_axisMaximumsSet[0] || x < _axisMaximums[0]))
2498  {
2499  _axisMaximums[0] = x;
2500  _axisMaximumsSet[0] = true;
2501  modified = true;
2502  }
2503 
2504  if(!_fixedAxis[0] && (!_axisMaximumsSet[1] || x > _axisMaximums[1]))
2505  {
2506  _axisMaximums[1] = x;
2507  _axisMaximumsSet[1] = true;
2508  modified = true;
2509  }
2510 
2511  if(!_fixedAxis[1] && (!_axisMaximumsSet[2] || y < _axisMaximums[2]))
2512  {
2513  _axisMaximums[2] = y;
2514  _axisMaximumsSet[2] = true;
2515  modified = true;
2516  }
2517 
2518  if(!_fixedAxis[1] && (!_axisMaximumsSet[3] || y > _axisMaximums[3]))
2519  {
2520  _axisMaximums[3] = y;
2521  _axisMaximumsSet[3] = true;
2522  modified = true;
2523  }
2524 
2525  return modified;
2526 }
2527 
2529 {
2530  //Reset the axis
2531  for(int i=0; i<4; ++i)
2532  {
2533  if((!_fixedAxis[0] && i<2) || (!_fixedAxis[1] && i>=2))
2534  {
2535  _axisMaximums[i] = 0;
2536  _axisMaximumsSet[i] = false;
2537  }
2538  }
2539 
2540  for(int i=0; i<_curves.size(); ++i)
2541  {
2542  if(_curves.at(i)->isVisible() && _curves.at(i)->isMinMaxValid())
2543  {
2544  const QVector<qreal> & minMax = _curves.at(i)->getMinMax();
2545  this->updateAxis(minMax[0], minMax[1], minMax[2], minMax[3]);
2546  }
2547  }
2548 
2549  _aGraphicsView->isChecked()?this->replot(0):this->update();
2550 
2551  this->captureScreen();
2552 }
2553 
2554 void UPlot::paintEvent(QPaintEvent * event)
2555 {
2556 #if PRINT_DEBUG
2557  UDEBUG("");
2558 #endif
2559  if(!_aGraphicsView->isChecked())
2560  {
2561  QPainter painter(this);
2562  painter.translate(_graphicsViewHolder->pos());
2563  painter.save();
2564  painter.setBrush(_bgColor);
2565  painter.setPen(QPen(Qt::NoPen));
2566  painter.drawRect(_graphicsViewHolder->rect());
2567  painter.restore();
2568 
2569  this->replot(&painter);
2570 
2572  {
2573  painter.save();
2574  int left, top, right, bottom;
2579  if(left <= 0)
2580  {
2581  left = 1;
2582  }
2583  if(right >= _graphicsViewHolder->width())
2584  {
2585  right = _graphicsViewHolder->width()-1;
2586  }
2587  if(top <= 0)
2588  {
2589  top = 1;
2590  }
2591  if(bottom >= _graphicsViewHolder->height())
2592  {
2593  bottom = _graphicsViewHolder->height()-1;
2594  }
2595  painter.setPen(Qt::NoPen);
2596  painter.setBrush(QBrush(QColor(255-_bgColor.red(),255-_bgColor.green(),255-_bgColor.blue(),100)));
2597  painter.drawRect(0, 0, _graphicsViewHolder->width(), top);
2598  painter.drawRect(0, top, left, bottom-top);
2599  painter.drawRect(right, top, _graphicsViewHolder->width()-right, bottom-top);
2600  painter.drawRect(0, bottom, _graphicsViewHolder->width(), _graphicsViewHolder->height()-bottom);
2601  painter.restore();
2602  }
2603  }
2604  else
2605  {
2606  QWidget::paintEvent(event);
2607  }
2608 }
2609 
2610 void UPlot::resizeEvent(QResizeEvent * event)
2611 {
2612  if(_aGraphicsView->isChecked())
2613  {
2614  this->replot(0);
2615  }
2616  QWidget::resizeEvent(event);
2617 }
2618 
2619 void UPlot::mousePressEvent(QMouseEvent * event)
2620 {
2621  _mousePressedPos = event->pos();
2623  QWidget::mousePressEvent(event);
2624 }
2625 
2626 void UPlot::mouseMoveEvent(QMouseEvent * event)
2627 {
2628  if(!_aGraphicsView->isChecked())
2629  {
2630  if(!(QApplication::mouseButtons() & Qt::LeftButton))
2631  {
2633  }
2634 
2635  qreal x,y;
2636  if(mousePosToValue(event->pos(), x ,y))
2637  {
2638  if(QApplication::mouseButtons() & Qt::LeftButton)
2639  {
2640  _mouseCurrentPos = event->pos();
2641  this->update();
2642  }
2643 
2644  int xPos = event->pos().x() - _graphicsViewHolder->pos().x();
2645  int yPos = event->pos().y() - _graphicsViewHolder->pos().y();
2646  if((QApplication::mouseButtons() & Qt::LeftButton) ||
2647  (_aMouseTracking->isChecked() && xPos>=0 && yPos>=0 && xPos<_graphicsViewHolder->width() && yPos<_graphicsViewHolder->height()))
2648  {
2649 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
2650  QToolTip::showText(event->globalPosition().toPoint(), QString("%1,%2").arg(x).arg(y));
2651 #else
2652  QToolTip::showText(event->globalPos(), QString("%1,%2").arg(x).arg(y));
2653 #endif
2654  }
2655  else
2656  {
2657  QToolTip::hideText();
2658  }
2659  }
2660  else
2661  {
2662  QToolTip::hideText();
2663  }
2664  }
2665  QWidget::mouseMoveEvent(event);
2666 }
2667 
2668 void UPlot::mouseReleaseEvent(QMouseEvent * event)
2669 {
2671  {
2672  int left,top,bottom,right;
2673 
2678 
2679  if(right - left > 5 || bottom - top > 5)
2680  {
2681  qreal axis[4];
2682  if(mousePosToValue(QPoint(left, top), axis[0], axis[3]) && mousePosToValue(QPoint(right, bottom), axis[1], axis[2]))
2683  {
2684 #if PRINT_DEBUG
2685  UDEBUG("resize! new axis = [%f, %f, %f, %f]", axis[0], axis[1], axis[2], axis[3]);
2686 #endif
2687  //update axis (only if not fixed)
2688  for(int i=0; i<4; ++i)
2689  {
2690  if((!_fixedAxis[0] && i<2) || (!_fixedAxis[1] && i>=2))
2691  {
2692  _axisMaximums[i] = axis[i];
2693  }
2694  }
2695  _aGraphicsView->isChecked()?this->replot(0):this->update();
2696  }
2697  }
2699  }
2700  QWidget::mouseReleaseEvent(event);
2701 }
2702 
2703 void UPlot::mouseDoubleClickEvent(QMouseEvent * event)
2704 {
2705  this->updateAxis();
2706  QWidget::mouseDoubleClickEvent(event);
2707 }
2708 
2709 bool UPlot::mousePosToValue(const QPoint & pos, qreal & x, qreal & y)
2710 {
2711  int xPos = pos.x() - _graphicsViewHolder->pos().x() - _horizontalAxis->border();
2712  int yPos = pos.y() - _graphicsViewHolder->pos().y() - _verticalAxis->border();
2713  int maxX = _graphicsViewHolder->width() - _horizontalAxis->border()*2;
2714  int maxY = _graphicsViewHolder->height() - _verticalAxis->border()*2;
2715  if(maxX == 0 || maxY == 0)
2716  {
2717  return false;
2718  }
2719 
2720  if(xPos < 0)
2721  {
2722  xPos = 0;
2723  }
2724  else if(xPos > maxX)
2725  {
2726  xPos = maxX;
2727  }
2728 
2729  if(yPos < 0)
2730  {
2731  yPos = 0;
2732  }
2733  else if(yPos > maxY)
2734  {
2735  yPos = maxY;
2736  }
2737 
2738  //UDEBUG("IN");
2739  //UDEBUG("x1=%f, x2=%f, y1=%f, y2=%f", _axisMaximums[0], _axisMaximums[1], _axisMaximums[2], _axisMaximums[3]);
2740  //UDEBUG("border hor=%f ver=%f", (qreal)_horizontalAxis->border(), (qreal)_verticalAxis->border());
2741  //UDEBUG("rect = %d,%d %d,%d", _graphicsViewHolder->pos().x(), _graphicsViewHolder->pos().y(), _graphicsViewHolder->width(), _graphicsViewHolder->height());
2742  //UDEBUG("%d,%d", event->pos().x(), event->pos().y());
2743  //UDEBUG("x/y %d,%d", x, y);
2744  //UDEBUG("max %d,%d", maxX, maxY);
2745 
2746  //UDEBUG("map %f,%f", x, y);
2747  x = _axisMaximums[0] + qreal(xPos)*(_axisMaximums[1] - _axisMaximums[0]) / qreal(maxX);
2748  y = _axisMaximums[2] + qreal(maxY - yPos)*(_axisMaximums[3] - _axisMaximums[2]) / qreal(maxY);
2749  return true;
2750 }
2751 
2752 void UPlot::contextMenuEvent(QContextMenuEvent * event)
2753 {
2754  QAction * action = _menu->exec(event->globalPos());
2755 
2756  if(!action)
2757  {
2758  return;
2759  }
2760  else if(action == _aShowLegend)
2761  {
2762  this->showLegend(_aShowLegend->isChecked());
2763  }
2764  else if(action == _aShowGrid)
2765  {
2766  this->showGrid(_aShowGrid->isChecked());
2767  }
2768  else if(action == _aShowRefreshRate)
2769  {
2770  this->showRefreshRate(_aShowRefreshRate->isChecked());
2771  }
2772  else if(action == _aMouseTracking)
2773  {
2774  this->trackMouse(_aMouseTracking->isChecked());
2775  }
2776  else if(action == _aGraphicsView)
2777  {
2778  this->setGraphicsView(_aGraphicsView->isChecked());
2779  }
2780  else if(action == _aKeepAllData)
2781  {
2782  this->keepAllData(_aKeepAllData->isChecked());
2783  }
2784  else if(action == _aLimit0 ||
2785  action == _aLimit10 ||
2786  action == _aLimit50 ||
2787  action == _aLimit100 ||
2788  action == _aLimit500 ||
2789  action == _aLimit1000 ||
2790  action == _aLimitCustom)
2791  {
2792  this->setMaxVisibleItems(action->text().toInt());
2793  }
2795  {
2796  bool ok;
2797  QString text = QInputDialog::getText(this, action->text(), tr("New line name :"), QLineEdit::Normal, "", &ok);
2798  while(ok && text.isEmpty())
2799  {
2800  QMessageBox::warning(this, action->text(), tr("The name is not valid or it is already used in this plot."));
2801  text = QInputDialog::getText(this, action->text(), tr("New line name :"), QLineEdit::Normal, "", &ok);
2802  }
2803  if(ok)
2804  {
2805  double min = _axisMaximums[2];
2806  double max = _axisMaximums[3];
2807  QString axis = "Y";
2808  if(action == _aAddVerticalLine)
2809  {
2810  min = _axisMaximums[0];
2811  max = _axisMaximums[1];
2812  axis = "X";
2813  }
2814  double value = QInputDialog::getDouble(this,
2815  action->text(),
2816  tr("%1 value (min=%2, max=%3):").arg(axis).arg(min).arg(max),
2817  (min+max)/2,
2818  -2147483647,
2819  2147483647,
2820  4,
2821  &ok);
2822  if(ok)
2823  {
2825  {
2826  this->addThreshold(text, value, Qt::Horizontal);
2827  }
2828  else
2829  {
2830  this->addThreshold(text, value, Qt::Vertical);
2831  }
2832  }
2833  }
2834  }
2835  else if(action == _aChangeTitle)
2836  {
2837  bool ok;
2838  QString text = _title->text();
2839  if(text.isEmpty())
2840  {
2841  text = this->objectName();
2842  }
2843  text = QInputDialog::getText(this, _aChangeTitle->text(), tr("Title :"), QLineEdit::Normal, text, &ok);
2844  if(ok)
2845  {
2846  this->setTitle(text);
2847  }
2848  }
2849  else if(action == _aChangeXLabel)
2850  {
2851  bool ok;
2852  QString text = QInputDialog::getText(this, _aChangeXLabel->text(), tr("X axis label :"), QLineEdit::Normal, _xLabel->text(), &ok);
2853  if(ok)
2854  {
2855  this->setXLabel(text);
2856  }
2857  }
2858  else if(action == _aChangeYLabel)
2859  {
2860  bool ok;
2861  QString text = QInputDialog::getText(this, _aChangeYLabel->text(), tr("Y axis label :"), QLineEdit::Normal, _yLabel->text(), &ok);
2862  if(ok)
2863  {
2864  this->setYLabel(text, _yLabel->orientation());
2865  }
2866  }
2867  else if(action == _aYLabelVertical)
2868  {
2869  this->setYLabel(_yLabel->text(), _aYLabelVertical->isChecked()?Qt::Vertical:Qt::Horizontal);
2870  }
2871  else if(action == _aChangeBackgroundColor)
2872  {
2873  QColor color = QColorDialog::getColor(_bgColor, this);
2874  if(color.isValid())
2875  {
2876  this->setBackgroundColor(color);
2877  }
2878  }
2879  else if(action == _aSaveFigure)
2880  {
2881 
2882  QString text;
2883 #ifdef QT_SVG_LIB
2884  text = QFileDialog::getSaveFileName(this, tr("Save figure to ..."), (QDir::homePath() + "/") + this->title() + ".png", "*.png *.xpm *.jpg *.pdf *.svg");
2885 #else
2886  text = QFileDialog::getSaveFileName(this, tr("Save figure to ..."), (QDir::homePath() + "/") + this->title() + ".png", "*.png *.xpm *.jpg *.pdf");
2887 #endif
2888  if(!text.isEmpty())
2889  {
2890  bool flatModified = false;
2891  if(!_legend->isFlat())
2892  {
2893  _legend->setFlat(true);
2894  flatModified = true;
2895  }
2896 
2897  QPalette p(palette());
2898  // Set background color to white
2899  QColor c = p.color(QPalette::Window);
2900  p.setColor(QPalette::Window, Qt::white);
2901  setPalette(p);
2902 
2903 #ifdef QT_SVG_LIB
2904  if(QFileInfo(text).suffix().compare("svg") == 0)
2905  {
2906  QSvgGenerator generator;
2907  generator.setFileName(text);
2908  generator.setSize(this->size());
2909  QPainter painter;
2910  painter.begin(&generator);
2911  this->render(&painter);
2912  painter.end();
2913  }
2914  else
2915  {
2916 #endif
2917  if(QFileInfo(text).suffix().compare("pdf") == 0)
2918  {
2919  QPrinter printer;
2920  printer.setOutputFormat(QPrinter::PdfFormat);
2921  printer.setOutputFileName(text);
2922  this->render(&printer);
2923  }
2924  else
2925  {
2926  QPixmap figure = this->grab();
2927  figure.save(text);
2928  }
2929 #ifdef QT_SVG_LIB
2930  }
2931 #endif
2932  // revert background color
2933  p.setColor(QPalette::Window, c);
2934  setPalette(p);
2935 
2936  if(flatModified)
2937  {
2938  _legend->setFlat(false);
2939  }
2940  }
2941  }
2942  else if(action == _aAutoScreenCapture)
2943  {
2944  if(_aAutoScreenCapture->isChecked())
2945  {
2946  this->selectScreenCaptureFormat();
2947  }
2948  }
2949  else if(action == _aClearData)
2950  {
2951  this->clearData();
2952  }
2953  else
2954  {
2955  ULOGGER_WARN("Unknown action");
2956  }
2957 }
2958 
2959 void UPlot::setWorkingDirectory(const QString & workingDirectory)
2960 {
2961  if(QDir(_workingDirectory).exists())
2962  {
2963  _workingDirectory = workingDirectory;
2964  }
2965  else
2966  {
2967  ULOGGER_ERROR("The directory \"%s\" doesn't exist", workingDirectory.toStdString().c_str());
2968  }
2969 }
2970 
2972 {
2973  if(!_aAutoScreenCapture->isChecked())
2974  {
2975  return;
2976  }
2977  QString targetDir = _workingDirectory + "/ScreensCaptured";
2978  QDir dir;
2979  if(!dir.exists(targetDir))
2980  {
2981  dir.mkdir(targetDir);
2982  }
2983  targetDir += "/";
2984  targetDir += this->title().replace(" ", "_");
2985  if(!dir.exists(targetDir))
2986  {
2987  dir.mkdir(targetDir);
2988  }
2989  targetDir += "/";
2990  QString name = (QDateTime::currentDateTime().toString("yyMMddhhmmsszzz") + ".") + _autoScreenCaptureFormat;
2991  QPixmap figure = this->grab();
2992  figure.save(targetDir + name);
2993 }
2994 
2996 {
2997  QStringList items;
2998  items << QString("png") << QString("jpg");
2999  bool ok;
3000  QString item = QInputDialog::getItem(this, tr("Select format"), tr("Format:"), items, 0, false, &ok);
3001  if(ok && !item.isEmpty())
3002  {
3003  _autoScreenCaptureFormat = item;
3004  }
3005  this->captureScreen();
3006 }
3007 
3009 {
3010  for(int i=0; i<_curves.size(); ++i)
3011  {
3012  // Don't clear threshold curves
3013  if(qobject_cast<UPlotCurveThreshold*>(_curves.at(i)) == 0)
3014  {
3015  _curves.at(i)->clear();
3016  }
3017  }
3018  _aGraphicsView->isChecked()?this->replot(0):this->update();
3019 }
3020 
3021 void UPlot::frameData(bool xAxis, bool yAxis)
3022 {
3023  if(!xAxis && !yAxis)
3024  {
3025  return;
3026  }
3027  qreal minX = std::numeric_limits<qreal>::max();
3028  qreal minY = std::numeric_limits<qreal>::max();
3029  for(int i=0; i<_curves.size(); ++i)
3030  {
3031  if(qobject_cast<UPlotCurveThreshold*>(_curves.at(i)) == 0)
3032  {
3033  const QVector<qreal> & minMax = _curves.at(i)->getMinMax();
3034  if(minMax.size() == 4)
3035  {
3036  if(minMax[0] < minX)
3037  {
3038  minX = minMax[0];
3039  }
3040  if(minMax[2] < minY)
3041  {
3042  minY = minMax[2];
3043  }
3044  }
3045  }
3046  }
3047  if(minX != std::numeric_limits<qreal>::max())
3048  {
3049  for(int i=0; i<_curves.size(); ++i)
3050  {
3051  if(qobject_cast<UPlotCurveThreshold*>(_curves.at(i)) == 0)
3052  {
3053  QVector<qreal> x;
3054  QVector<qreal> y;
3055  _curves.at(i)->getData(x,y);
3056  for(int j=0; j<x.size(); ++j)
3057  {
3058  if(xAxis)
3059  {
3060  x[j]-=minX;
3061  }
3062  if(yAxis)
3063  {
3064  y[j]-=minY;
3065  }
3066  }
3067  _curves.at(i)->setData(x,y);
3068  }
3069  }
3070  }
3071  _aGraphicsView->isChecked()?this->replot(0):this->update();
3072 }
3073 
3074 // for convenience...
3075 UPlotCurveThreshold * UPlot::addThreshold(const QString & name, qreal value, Qt::Orientation orientation)
3076 {
3078  QPen pen = curve->pen();
3079  pen.setStyle((Qt::PenStyle)(_penStyleCount++ % 4 + 2));
3080  curve->setPen(pen);
3081  if(!this->addCurve(curve))
3082  {
3083  if(curve)
3084  {
3085  delete curve;
3086  }
3087  }
3088  else
3089  {
3090  _aGraphicsView->isChecked()?this->replot(0):this->update();
3091  }
3092  return curve;
3093 }
3094 
3095 void UPlot::setTitle(const QString & text)
3096 {
3097  _title->setText(text);
3098  _title->setVisible(!text.isEmpty());
3099  this->update();
3100  if(_aGraphicsView->isChecked())
3101  {
3102  QTimer::singleShot(10, this, SLOT(updateAxis()));
3103  }
3104 }
3105 
3106 void UPlot::setXLabel(const QString & text)
3107 {
3108  _xLabel->setText(text);
3109  _xLabel->setVisible(!text.isEmpty());
3110  this->update();
3111  if(_aGraphicsView->isChecked())
3112  {
3113  QTimer::singleShot(10, this, SLOT(updateAxis()));
3114  }
3115 }
3116 
3117 void UPlot::setYLabel(const QString & text, Qt::Orientation orientation)
3118 {
3119  _yLabel->setText(text);
3121  _yLabel->setVisible(!text.isEmpty());
3123  this->update();
3124  if(_aGraphicsView->isChecked())
3125  {
3126  QTimer::singleShot(10, this, SLOT(updateAxis()));
3127  }
3128 }
3129 
3130 void UPlot::setBackgroundColor(const QColor & color)
3131 {
3132  if(color.isValid())
3133  {
3134  _bgColor = color;
3135  _view->scene()->setBackgroundBrush(QBrush(_bgColor));
3136  for(QList<UPlotCurve*>::iterator iter=_curves.begin(); iter!=_curves.end(); ++iter)
3137  {
3138  (*iter)->setItemsColor(QColor(255-_bgColor.red(), 255-_bgColor.green(), 255-_bgColor.blue(), _bgColor.alpha()));
3139  }
3140  }
3141 }
3142 
3143 void UPlot::addItem(QGraphicsItem * item)
3144 {
3145  item->setParentItem(_sceneRoot);
3146  item->setZValue(1.0f);
3147 }
3148 
3149 void UPlot::showLegend(bool shown)
3150 {
3151  _legend->setVisible(shown);
3152  _aShowLegend->setChecked(shown);
3153  this->update();
3154  if(_aGraphicsView->isChecked())
3155  {
3156  QTimer::singleShot(10, this, SLOT(updateAxis()));
3157  }
3158 }
3159 
3160 void UPlot::showGrid(bool shown)
3161 {
3162  _aShowGrid->setChecked(shown);
3163  _aGraphicsView->isChecked()?this->replot(0):this->update();
3164 }
3165 
3166 void UPlot::showRefreshRate(bool shown)
3167 {
3168  _aShowRefreshRate->setChecked(shown);
3169  _refreshRate->setVisible(shown);
3170  this->update();
3171  if(_aGraphicsView->isChecked())
3172  {
3173  QTimer::singleShot(10, this, SLOT(updateAxis()));
3174  }
3175 }
3176 
3177 void UPlot::trackMouse(bool tracking)
3178 {
3179  _aMouseTracking->setChecked(tracking);
3180  this->setMouseTracking(tracking);
3181 }
3182 
3184 {
3185  _aGraphicsView->setChecked(on);
3186  _view->setVisible(on);
3187  _aGraphicsView->isChecked()?this->replot(0):this->update();
3188  _aMouseTracking->setEnabled(!on);
3189 }
3190 
3191 void UPlot::keepAllData(bool kept)
3192 {
3193  _aKeepAllData->setChecked(kept);
3194 }
3195 
3196 void UPlot::setMaxVisibleItems(int maxVisibleItems)
3197 {
3198  if(maxVisibleItems <= 0)
3199  {
3200  _aLimit0->setChecked(true);
3201  }
3202  else if(maxVisibleItems == 10)
3203  {
3204  _aLimit10->setChecked(true);
3205  }
3206  else if(maxVisibleItems == 50)
3207  {
3208  _aLimit50->setChecked(true);
3209  }
3210  else if(maxVisibleItems == 100)
3211  {
3212  _aLimit100->setChecked(true);
3213  }
3214  else if(maxVisibleItems == 500)
3215  {
3216  _aLimit500->setChecked(true);
3217  }
3218  else if(maxVisibleItems == 1000)
3219  {
3220  _aLimit1000->setChecked(true);
3221  }
3222  else
3223  {
3224  _aLimitCustom->setVisible(true);
3225  _aLimitCustom->setChecked(true);
3226  _aLimitCustom->setText(QString::number(maxVisibleItems));
3227  }
3228  _maxVisibleItems = maxVisibleItems;
3229  updateAxis();
3230 }
3231 
3232 QRectF UPlot::sceneRect() const
3233 {
3234  return _view->sceneRect();
3235 }
3236 
3238 {
3239  QList<UPlotCurve*> tmp = _curves;
3240  for(QList<UPlotCurve*>::iterator iter=tmp.begin(); iter!=tmp.end(); ++iter)
3241  {
3242  this->removeCurve(*iter);
3243  }
3244  _curves.clear();
3245 }
3246 
3247 void UPlot::removeCurve(const UPlotCurve * curve)
3248 {
3249  QList<UPlotCurve *>::iterator iter = std::find(_curves.begin(), _curves.end(), curve);
3250 #if PRINT_DEBUG
3251  ULOGGER_DEBUG("Plot=\"%s\" removing curve=\"%s\"", this->objectName().toStdString().c_str(), curve?curve->name().toStdString().c_str():"");
3252 #endif
3253  if(iter!=_curves.end())
3254  {
3255  UPlotCurve * c = *iter;
3256  c->detach(this);
3257  _curves.erase(iter);
3258  _legend->remove(c);
3259  if(!qobject_cast<UPlotCurveThreshold*>(c))
3260  {
3261  // transfer update connection to next curve
3262  for(int i=_curves.size()-1; i>=0; --i)
3263  {
3264  if(!qobject_cast<UPlotCurveThreshold*>(_curves.at(i)))
3265  {
3266  connect(_curves.at(i), SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateAxis()));
3267  break;
3268  }
3269  }
3270  }
3271 
3272  if(c->parent() == this)
3273  {
3274  delete c;
3275  }
3276  // Update axis
3277  updateAxis();
3278  }
3279 }
3280 
3281 void UPlot::showCurve(const UPlotCurve * curve, bool shown)
3282 {
3283  QList<UPlotCurve *>::iterator iter = std::find(_curves.begin(), _curves.end(), curve);
3284  if(iter!=_curves.end())
3285  {
3286  UPlotCurve * value = *iter;
3287  if(value->isVisible() != shown)
3288  {
3289  value->setVisible(shown);
3290  this->updateAxis();
3291  }
3292  }
3293 }
3294 
3295 void UPlot::moveCurve(const UPlotCurve * curve, int index)
3296 {
3297  // this will change the print order
3298  int currentIndex = -1;
3299  UPlotCurve * c = 0;
3300  for(int i=0; i<_curves.size(); ++i)
3301  {
3302  if(_curves.at(i) == curve)
3303  {
3304  c = _curves.at(i);
3305  currentIndex = i;
3306  break;
3307  }
3308  }
3309 
3310  if(c && currentIndex != index)
3311  {
3312  _curves.removeAt(currentIndex);
3313  QList<QGraphicsItem *> children = _sceneRoot->childItems();
3314  _curves.insert(index, c);
3315  if(currentIndex > index)
3316  {
3317  children[currentIndex]->stackBefore(children[index]);
3318  }
3319  else
3320  {
3321  if(currentIndex<children.size()-2)
3322  {
3323  if(index < children.size()-1)
3324  {
3325  children[index]->stackBefore(children[currentIndex]);
3326  }
3327  else
3328  {
3329  children[currentIndex]->stackBefore(children[index]);
3330  }
3331  }
3332  if(currentIndex == children.size()-2 && currentIndex < index)
3333  {
3334  children[index]->stackBefore(children[currentIndex]);
3335  }
3336  }
3337  this->update();
3338  }
3339 }
3340 
3342 {
3343  if(_legend)
3344  {
3345  return _legend->getAllCurveDataAsText();
3346  }
3347  return "";
3348 }
UPlotLegend::_flat
bool _flat
Definition: UPlot.h:423
w
RowVector3d w
glm::min
GLM_FUNC_DECL genType min(genType const &x, genType const &y)
int
int
UPlotItem::_data
QPointF _data
Definition: UPlot.h:81
UPlot::addItem
void addItem(QGraphicsItem *item)
Definition: UPlot.cpp:3143
compare
bool compare
UPlot::replot
void replot(QPainter *painter)
Definition: UPlot.cpp:2279
UPlotCurve::_addValue
void _addValue(UPlotItem *data)
Definition: UPlot.cpp:377
UPlot::_curves
QList< UPlotCurve * > _curves
Definition: UPlot.h:604
UPlotAxis::paintEvent
virtual void paintEvent(QPaintEvent *event)
Definition: UPlot.cpp:1347
UPlotItem::setNextItem
void setNextItem(UPlotItem *nextItem)
Definition: UPlot.cpp:107
UOrientableLabel::_orientation
Qt::Orientation _orientation
Definition: UPlot.h:459
UPlotLegend
Definition: UPlot.h:389
UPlotItem::UPlotItem
UPlotItem(qreal dataX, qreal dataY, qreal width=2)
Definition: UPlot.cpp:57
update
def update(text)
UOrientableLabel::setOrientation
void setOrientation(Qt::Orientation orientation)
Definition: UPlot.cpp:1864
UPlotCurve::_minMax
QVector< qreal > _minMax
Definition: UPlot.h:254
name
UPlotItem
Definition: UPlot.h:47
uMean
T uMean(const T *v, unsigned int size)
Definition: UMath.h:399
UPlotAxis::border
int border() const
Definition: UPlot.h:316
UPlot::getAllCurveDataAsText
QString getAllCurveDataAsText() const
Definition: UPlot.cpp:3341
glm::length
GLM_FUNC_DECL genType::value_type length(genType const &x)
UPlot::_aKeepAllData
QAction * _aKeepAllData
Definition: UPlot.h:621
UPlotLegendItem::_aMoveUp
QAction * _aMoveUp
Definition: UPlot.h:382
UPlotLegendItem
Definition: UPlot.h:348
x1
x1
UPlot::contains
bool contains(const QString &curveName) const
Definition: UPlot.cpp:2240
arg::arg
constexpr arg(const char *name=nullptr)
UPlot::_aClearData
QAction * _aClearData
Definition: UPlot.h:640
UPlotLegendItem::curve
const UPlotCurve * curve() const
Definition: UPlot.h:358
UPlotCurveThreshold::setOrientation
void setOrientation(Qt::Orientation orientation)
Definition: UPlot.cpp:1106
UPlot::_sceneRoot
QGraphicsItem * _sceneRoot
Definition: UPlot.h:593
UPlotCurve::_xStart
qreal _xStart
Definition: UPlot.h:251
UPlotCurve::pen
const QPen & pen() const
Definition: UPlot.h:115
UPlotItem::_textBackground
QGraphicsRectItem * _textBackground
Definition: UPlot.h:85
UPlotItem::nextItem
UPlotItem * nextItem() const
Definition: UPlot.h:65
UPlot::_bgColor
QColor _bgColor
Definition: UPlot.h:616
UPlot::_axisMaximums
qreal _axisMaximums[4]
Definition: UPlot.h:595
UPlot::_xLabel
QLabel * _xLabel
Definition: UPlot.h:606
Horizontal
Horizontal
glm::axis
GLM_FUNC_DECL detail::tvec3< T, P > axis(detail::tquat< T, P > const &x)
UPlotCurve::_visible
bool _visible
Definition: UPlot.h:252
UPlot::showGrid
void showGrid(bool shown)
Definition: UPlot.cpp:3160
UPlotLegend::legendItemToggled
void legendItemToggled(const UPlotCurve *curve, bool toggled)
c
Scalar Scalar * c
h
const double h
UPlot::frameData
void frameData(bool xAxis=true, bool yAxis=false)
Definition: UPlot.cpp:3021
UPlot::setFixedXAxis
void setFixedXAxis(qreal x1, qreal x2)
Definition: UPlot.cpp:2448
UPlotLegend::~UPlotLegend
virtual ~UPlotLegend()
Definition: UPlot.cpp:1587
UPlotLegendItem::~UPlotLegendItem
virtual ~UPlotLegendItem()
Definition: UPlot.cpp:1424
UPlotLegendItem::_aMoveDown
QAction * _aMoveDown
Definition: UPlot.h:383
size
Index size
this
this
UPlot::_fixedAxis
bool _fixedAxis[2]
Definition: UPlot.h:597
UPlotLegendItem::_aResetText
QAction * _aResetText
Definition: UPlot.h:377
UPlot::createMenus
void createMenus()
Definition: UPlot.cpp:2099
UPlotCurve::setData
void setData(QVector< UPlotItem * > &data)
Definition: UPlot.cpp:895
UOrientableLabel::minimumSizeHint
QSize minimumSizeHint() const
Definition: UPlot.cpp:1856
UPlot::setupUi
void setupUi()
Definition: UPlot.cpp:1990
UPlot::_aChangeYLabel
QAction * _aChangeYLabel
Definition: UPlot.h:633
UPlot::_refreshRate
QLabel * _refreshRate
Definition: UPlot.h:608
UPlotLegend::redirectToggled
void redirectToggled(bool)
Definition: UPlot.cpp:1819
UPlotLegendItem::showStdDevMeanMax
void showStdDevMeanMax(bool shown)
Definition: UPlot.cpp:1505
count
Index count
UPlot::_verticalAxis
UPlotAxis * _verticalAxis
Definition: UPlot.h:598
UPlotCurve::attach
void attach(UPlot *plot)
Definition: UPlot.cpp:311
UPlot::_aGraphicsView
QAction * _aGraphicsView
Definition: UPlot.h:641
type
UPlotCurve::getMinMax
const QVector< qreal > & getMinMax() const
Definition: UPlot.h:235
mul
double mul(const double &a, const double &b)
UPlot::_graphicsViewHolder
QWidget * _graphicsViewHolder
Definition: UPlot.h:594
UOrientableLabel::UOrientableLabel
UOrientableLabel(const QString &text, Qt::Orientation orientation=Qt::Horizontal, QWidget *parent=0)
Definition: UPlot.cpp:1837
y
Matrix3f y
UPlotCurve::name
QString name() const
Definition: UPlot.h:136
UPlotLegend::getAllCurveDataAsText
QString getAllCurveDataAsText() const
Definition: UPlot.cpp:1713
UPlot::_aAddVerticalLine
QAction * _aAddVerticalLine
Definition: UPlot.h:629
UPlot::_aChangeBackgroundColor
QAction * _aChangeBackgroundColor
Definition: UPlot.h:634
true
#define true
Definition: ConvertUTF.c:57
UPlotCurve::UPlotCurve
UPlotCurve(const QString &name, QObject *parent=0)
Definition: UPlot.cpp:257
uVariance
T uVariance(const T *v, unsigned int size, T meanV)
Definition: UMath.h:489
UPlotItem::keyReleaseEvent
virtual void keyReleaseEvent(QKeyEvent *keyEvent)
Definition: UPlot.cpp:221
UPlotItem::hoverEnterEvent
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event)
Definition: UPlot.cpp:194
UPlot::removeCurves
void removeCurves()
Definition: UPlot.cpp:3237
UPlotCurve::draw
void draw(QPainter *painter, const QRect &limits)
Definition: UPlot.cpp:768
UPlotCurve::removeItem
int removeItem(int index)
Definition: UPlot.cpp:577
UPlotAxis::UPlotAxis
UPlotAxis(Qt::Orientation orientation=Qt::Horizontal, qreal min=0, qreal max=1, QWidget *parent=0)
Definition: UPlot.cpp:1164
UPlotLegend::contextMenuEvent
virtual void contextMenuEvent(QContextMenuEvent *event)
Definition: UPlot.cpp:1793
UPlotCurve::isVisible
bool isVisible() const
Definition: UPlot.h:142
ULOGGER_DEBUG
#define ULOGGER_DEBUG(...)
Definition: ULogger.h:53
UPlot::mousePressEvent
virtual void mousePressEvent(QMouseEvent *event)
Definition: UPlot.cpp:2619
UPlotAxis::setReversed
void setReversed(bool reversed)
Definition: UPlot.cpp:1195
UPlot::_aLimit100
QAction * _aLimit100
Definition: UPlot.h:625
UPlot::showRefreshRate
void showRefreshRate(bool shown)
Definition: UPlot.cpp:3166
UOrientableLabel::paintEvent
virtual void paintEvent(QPaintEvent *event)
Definition: UPlot.cpp:1879
UPlotLegend::isFlat
bool isFlat() const
Definition: UPlot.h:401
UMath.h
Basic mathematics functions.
UPlotCurve::dataChanged
void dataChanged(const UPlotCurve *)
UPlot::_aMouseTracking
QAction * _aMouseTracking
Definition: UPlot.h:637
UPlotLegendItem::createSymbol
QPixmap createSymbol(const QPen &pen, const QBrush &brush)
Definition: UPlot.cpp:1522
UPlotCurve::setItemsColor
void setItemsColor(const QColor &color)
Definition: UPlot.cpp:677
UPlotItem::_nextItem
UPlotItem * _nextItem
Definition: UPlot.h:83
UPlotCurveThreshold::setThreshold
void setThreshold(qreal threshold)
Definition: UPlot.cpp:1076
UPlotLegendItem::updateStdDevMeanMax
void updateStdDevMeanMax()
Definition: UPlot.cpp:1534
UPlot::_horizontalAxis
UPlotAxis * _horizontalAxis
Definition: UPlot.h:599
UPlotItem::setData
void setData(const QPointF &data)
Definition: UPlot.cpp:102
UPlot::_aShowRefreshRate
QAction * _aShowRefreshRate
Definition: UPlot.h:636
UPlot::UPlot
UPlot(QWidget *parent=0)
Definition: UPlot.cpp:1910
n
int n
UPlot::trackMouse
void trackMouse(bool tracking)
Definition: UPlot.cpp:3177
UPlotCurve::getItemData
QPointF getItemData(int index)
Definition: UPlot.cpp:861
countStep
static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv)
Definition: sqlite3.c:91144
UPlotLegendItem::UPlotLegendItem
UPlotLegendItem(UPlotCurve *curve, QWidget *parent=0)
Definition: UPlot.cpp:1391
uIsNan
bool uIsNan(const T &value)
Definition: UMath.h:40
UPlot::curveNames
QStringList curveNames() const
Definition: UPlot.cpp:2198
UPlot::_aShowGrid
QAction * _aShowGrid
Definition: UPlot.h:620
UPlot::mouseReleaseEvent
virtual void mouseReleaseEvent(QMouseEvent *event)
Definition: UPlot.cpp:2668
UPlot::UPlotCurve
friend class UPlotCurve
Definition: UPlot.h:577
UPlotAxis::count
int count() const
Definition: UPlot.h:324
UPlot::_aLimitCustom
QAction * _aLimitCustom
Definition: UPlot.h:628
data
int data[]
UPlotCurve::setBrush
void setBrush(const QBrush &brush)
Definition: UPlot.cpp:671
UPlotCurveThreshold::update
virtual void update(qreal scaleX, qreal scaleY, qreal offsetX, qreal offsetY, qreal xDir, qreal yDir, int maxItemsKept)
Definition: UPlot.cpp:1126
UPlotCurve::update
virtual void update(qreal scaleX, qreal scaleY, qreal offsetX, qreal offsetY, qreal xDir, qreal yDir, int maxItemsKept)
Definition: UPlot.cpp:691
UPlotCurveThreshold
Definition: UPlot.h:263
j
std::ptrdiff_t j
UPlotLegend::_aCopyAllCurvesToClipboard
QAction * _aCopyAllCurvesToClipboard
Definition: UPlot.h:426
UPlot::_yLabel
UOrientableLabel * _yLabel
Definition: UPlot.h:607
UPlotLegend::legendItemMoved
void legendItemMoved(const UPlotCurve *curve, int)
UPlotCurveThreshold::UPlotCurveThreshold
UPlotCurveThreshold(const QString &name, qreal thesholdValue, Qt::Orientation orientation=Qt::Horizontal, QObject *parent=0)
Definition: UPlot.cpp:1054
UPlotAxis::_count
int _count
Definition: UPlot.h:337
UPlotCurveThreshold::_threshold
qreal _threshold
Definition: UPlot.h:292
UPlot::getRandomPenColored
QPen getRandomPenColored()
Definition: UPlot.cpp:2252
UPlot::moveCurve
void moveCurve(const UPlotCurve *, int index)
Definition: UPlot.cpp:3295
glm::sqrt
GLM_FUNC_DECL vecType< T, P > sqrt(vecType< T, P > const &x)
UPlotLegend::remove
bool remove(const UPlotCurve *curve)
Definition: UPlot.cpp:1636
UPlot::mouseDoubleClickEvent
virtual void mouseDoubleClickEvent(QMouseEvent *event)
Definition: UPlot.cpp:2703
UPlotItem::data
const QPointF & data() const
Definition: UPlot.h:67
UPlotCurve::_items
QList< QGraphicsItem * > _items
Definition: UPlot.h:240
UPlot::clearData
void clearData()
Definition: UPlot.cpp:3008
UOrientableLabel
Definition: UPlot.h:436
UPlotLegend::UPlotLegend
UPlotLegend(QWidget *parent=0)
Definition: UPlot.cpp:1552
UPlotAxis::_step
int _step
Definition: UPlot.h:338
UPlot::_aAddHorizontalLine
QAction * _aAddHorizontalLine
Definition: UPlot.h:630
UPlot::setFixedYAxis
void setFixedYAxis(qreal y1, qreal y2)
Definition: UPlot.cpp:2455
UPlotCurve::_plot
UPlot * _plot
Definition: UPlot.h:241
UPlotCurveThreshold::_orientation
Qt::Orientation _orientation
Definition: UPlot.h:291
arg
UPlotAxis::_reversed
bool _reversed
Definition: UPlot.h:339
UPlotCurve::_brush
QBrush _brush
Definition: UPlot.h:249
UPlot::resizeEvent
virtual void resizeEvent(QResizeEvent *event)
Definition: UPlot.cpp:2610
glm::max
GLM_FUNC_DECL genType max(genType const &x, genType const &y)
UPlot::_workingDirectory
QString _workingDirectory
Definition: UPlot.h:609
UPlotLegendItem::contextMenuEvent
virtual void contextMenuEvent(QContextMenuEvent *event)
Definition: UPlot.cpp:1428
UPlotLegendItem::legendItemRemoved
void legendItemRemoved(const UPlotCurve *)
x2
x2
UPlotAxis::_orientation
Qt::Orientation _orientation
Definition: UPlot.h:334
UPlot::_mouseCurrentPos
QPoint _mouseCurrentPos
Definition: UPlot.h:615
UPlot::addCurve
UPlotCurve * addCurve(const QString &curveName, const QColor &color=QColor())
Definition: UPlot.cpp:2134
UPlotCurve::itemsSize
int itemsSize() const
Definition: UPlot.cpp:856
UPlot::_mousePressedPos
QPoint _mousePressedPos
Definition: UPlot.h:614
glm::orientation
GLM_FUNC_DECL detail::tmat4x4< T, P > orientation(detail::tvec3< T, P > const &Normal, detail::tvec3< T, P > const &Up)
UPlot::_aLimit10
QAction * _aLimit10
Definition: UPlot.h:623
UPlotCurve::~UPlotCurve
virtual ~UPlotCurve()
Definition: UPlot.cpp:298
UPlot::setXLabel
void setXLabel(const QString &text)
Definition: UPlot.cpp:3106
UPlotCurve::setXStart
void setXStart(qreal val)
Definition: UPlot.cpp:890
x
x
iterator::value
object value
p
Point3_ p(2)
UPlotLegendItem::_aRemoveCurve
QAction * _aRemoveCurve
Definition: UPlot.h:381
UPlotLegend::_aShowAllStdDevMeanMax
QAction * _aShowAllStdDevMeanMax
Definition: UPlot.h:427
UPlotLegend::removeLegendItem
void removeLegendItem(const UPlotCurve *curve)
Definition: UPlot.cpp:1651
UPlotLegend::addItem
void addItem(UPlotCurve *curve)
Definition: UPlot.cpp:1609
UPlotCurve::brush
const QBrush & brush() const
Definition: UPlot.h:119
UPlot::mouseMoveEvent
virtual void mouseMoveEvent(QMouseEvent *event)
Definition: UPlot.cpp:2626
Vertical
Vertical
UPlot::paintEvent
virtual void paintEvent(QPaintEvent *event)
Definition: UPlot.cpp:2554
action
action
UPlot::_legend
UPlotLegend * _legend
Definition: UPlot.h:591
UPlotLegend::_menu
QMenu * _menu
Definition: UPlot.h:424
UPlot::_view
QGraphicsView * _view
Definition: UPlot.h:592
intersection
Definition: dummy.cpp:142
UPlot::~UPlot
virtual ~UPlot()
Definition: UPlot.cpp:1981
UPlot::createActions
void createActions()
Definition: UPlot.cpp:2045
UWARN
#define UWARN(...)
UPlotCurve::addValue
void addValue(UPlotItem *data)
Definition: UPlot.cpp:423
UPlotLegend::legendItemRemoved
void legendItemRemoved(const UPlotCurve *curve)
UPlotCurve::_pen
QPen _pen
Definition: UPlot.h:248
f
Point2(* f)(const Point3 &, OptionalJacobian< 2, 3 >)
UPlotCurve::setXIncrement
void setXIncrement(qreal increment)
Definition: UPlot.cpp:885
names
dictionary names
y1
CEPHES_EXTERN_EXPORT double y1(double x)
UPlot::_maxVisibleItems
int _maxVisibleItems
Definition: UPlot.h:601
UPlotCurve::detach
void detach(UPlot *plot)
Definition: UPlot.cpp:325
UPlotLegend::_scrollArea
QScrollArea * _scrollArea
Definition: UPlot.h:429
UPlot::_aChangeTitle
QAction * _aChangeTitle
Definition: UPlot.h:631
UPlot::updateAxis
void updateAxis()
Definition: UPlot.cpp:2528
UPlot::_aLimit1000
QAction * _aLimit1000
Definition: UPlot.h:627
UPlotAxis
Definition: UPlot.h:298
ULogger.h
ULogger class and convenient macros.
UPlot.h
UPlot::removeCurve
void removeCurve(const UPlotCurve *curve)
Definition: UPlot.cpp:3247
UPlot::setBackgroundColor
void setBackgroundColor(const QColor &color)
Definition: UPlot.cpp:3130
UPlot::setGraphicsView
void setGraphicsView(bool on)
Definition: UPlot.cpp:3183
UPlot::setTitle
void setTitle(const QString &text)
Definition: UPlot.cpp:3095
UPlotLegendItem::_curve
UPlotCurve * _curve
Definition: UPlot.h:374
UPlot::_refreshIntervalTime
QElapsedTimer _refreshIntervalTime
Definition: UPlot.h:610
UPlotLegend::_aUseFlatButtons
QAction * _aUseFlatButtons
Definition: UPlot.h:425
UPlotLegendItem::_aChangeColor
QAction * _aChangeColor
Definition: UPlot.h:378
UPlotCurve
Definition: UPlot.h:93
UPlot::_aYLabelVertical
QAction * _aYLabelVertical
Definition: UPlot.h:635
UPlotItem::focusOutEvent
virtual void focusOutEvent(QFocusEvent *event)
Definition: UPlot.cpp:215
UPlotCurve::setVisible
void setVisible(bool visible)
Definition: UPlot.cpp:876
UPlotItem::focusInEvent
virtual void focusInEvent(QFocusEvent *event)
Definition: UPlot.cpp:209
mean
Point3 mean(const CONTAINER &points)
UPlot::_title
QLabel * _title
Definition: UPlot.h:605
UPlot::mousePosToValue
bool mousePosToValue(const QPoint &pos, qreal &x, qreal &y)
Definition: UPlot.cpp:2709
UPlotLegend::setFlat
void setFlat(bool on)
Definition: UPlot.cpp:1594
UPlotItem::_previousItem
UPlotItem * _previousItem
Definition: UPlot.h:82
UPlotItem::setPreviousItem
void setPreviousItem(UPlotItem *previousItem)
Definition: UPlot.cpp:119
iter
iterator iter(handle obj)
ULOGGER_ERROR
#define ULOGGER_ERROR(...)
Definition: ULogger.h:56
UPlotCurveThreshold::getThreshold
qreal getThreshold() const
Definition: UPlot.h:273
UPlotAxis::_min
qreal _min
Definition: UPlot.h:335
UPlot::setMaxVisibleItems
void setMaxVisibleItems(int maxVisibleItems)
Definition: UPlot.cpp:3196
UPlot::vGridLines
QList< QGraphicsLineItem * > vGridLines
Definition: UPlot.h:603
UPlot::isThreshold
bool isThreshold(const QString &curveName) const
Definition: UPlot.cpp:2211
UPlotItem::showDescription
virtual void showDescription(bool shown)
Definition: UPlot.cpp:131
UPlot::showCurve
void showCurve(const UPlotCurve *curve, bool shown)
Definition: UPlot.cpp:3281
c_str
const char * c_str(Args &&...args)
UPlot::setYLabel
void setYLabel(const QString &text, Qt::Orientation orientation=Qt::Vertical)
Definition: UPlot.cpp:3117
UPlotCurveThreshold::~UPlotCurveThreshold
virtual ~UPlotCurveThreshold()
Definition: UPlot.cpp:1071
UPlot::_aChangeXLabel
QAction * _aChangeXLabel
Definition: UPlot.h:632
UOrientableLabel::orientation
Qt::Orientation orientation() const
Definition: UPlot.h:449
v
Array< int, Dynamic, 1 > v
UDEBUG
#define UDEBUG(...)
UPlotItem::hoverLeaveEvent
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
Definition: UPlot.cpp:200
UPlot::selectScreenCaptureFormat
void selectScreenCaptureFormat()
Definition: UPlot.cpp:2995
UPlotItem::~UPlotItem
virtual ~UPlotItem()
Definition: UPlot.cpp:85
UPlot::hGridLines
QList< QGraphicsLineItem * > hGridLines
Definition: UPlot.h:602
UPlot::_axisMaximumsSet
bool _axisMaximumsSet[4]
Definition: UPlot.h:596
UOrientableLabel::~UOrientableLabel
virtual ~UOrientableLabel()
Definition: UPlot.cpp:1843
UPlotCurve::isMinMaxValid
virtual bool isMinMaxValid() const
Definition: UPlot.h:238
UPlotLegendItem::moveUpRequest
void moveUpRequest(UPlotLegendItem *)
UPlotLegend::moveDown
void moveDown(UPlotLegendItem *item)
Definition: UPlot.cpp:1686
UPlot::_menu
QMenu * _menu
Definition: UPlot.h:618
UPlot::_aLimit50
QAction * _aLimit50
Definition: UPlot.h:624
UPlot::title
QString title() const
Definition: UPlot.h:524
UPlot::_aLimit0
QAction * _aLimit0
Definition: UPlot.h:622
UPlotLegend::_contentLayout
QLayout * _contentLayout
Definition: UPlot.h:428
UPlot::showLegend
void showLegend(bool shown)
Definition: UPlot.cpp:3149
UPlot::_aSaveFigure
QAction * _aSaveFigure
Definition: UPlot.h:638
UPlotAxis::~UPlotAxis
virtual ~UPlotAxis()
Definition: UPlot.cpp:1187
UPlotLegend::moveUp
void moveUp(UPlotLegendItem *item)
Definition: UPlot.cpp:1659
UPlotCurve::_itemsColor
QColor _itemsColor
Definition: UPlot.h:256
UPlotCurve::_rootItem
QGraphicsRectItem * _rootItem
Definition: UPlot.h:255
UPlotCurve::updateMinMax
void updateMinMax()
Definition: UPlot.cpp:340
UPlot::_autoScreenCaptureFormat
QString _autoScreenCaptureFormat
Definition: UPlot.h:613
UPlotCurve::getData
void getData(QVector< qreal > &x, QVector< qreal > &y) const
Definition: UPlot.cpp:1021
UPlotCurve::_xIncrement
qreal _xIncrement
Definition: UPlot.h:250
uMax
T uMax(const T *v, unsigned int size, unsigned int &index)
Definition: UMath.h:92
UPlotLegendItem::_menu
QMenu * _menu
Definition: UPlot.h:375
UPlotLegendItem::moveDownRequest
void moveDownRequest(UPlotLegendItem *)
false
#define false
Definition: ConvertUTF.c:56
UPlot::keepAllData
void keepAllData(bool kept)
Definition: UPlot.cpp:3191
UPlot::getThresholdValue
double getThresholdValue(const QString &curveName) const
Definition: UPlot.cpp:2223
UPlot::_aAutoScreenCapture
QAction * _aAutoScreenCapture
Definition: UPlot.h:639
UPlot
Definition: UPlot.h:492
UPlot::_refreshStartTime
QElapsedTimer _refreshStartTime
Definition: UPlot.h:612
UPlotCurve::setPen
void setPen(const QPen &pen)
Definition: UPlot.cpp:662
UPlotLegendItem::_aCopyToClipboard
QAction * _aCopyToClipboard
Definition: UPlot.h:379
pos
UPlot::addThreshold
UPlotCurveThreshold * addThreshold(const QString &name, qreal value, Qt::Orientation orientation=Qt::Horizontal)
Definition: UPlot.cpp:3075
UPlotAxis::setAxis
void setAxis(qreal &min, qreal &max)
Definition: UPlot.cpp:1206
UPlot::_penStyleCount
int _penStyleCount
Definition: UPlot.h:600
UPlotItem::init
void init(qreal dataX, qreal dataY)
Definition: UPlot.cpp:77
UPlotItem::_text
QGraphicsTextItem * _text
Definition: UPlot.h:84
UOrientableLabel::sizeHint
QSize sizeHint() const
Definition: UPlot.cpp:1847
UPlotAxis::_border
int _border
Definition: UPlot.h:341
UPlot::captureScreen
void captureScreen()
Definition: UPlot.cpp:2971
UPlotItem::previousItem
UPlotItem * previousItem() const
Definition: UPlot.h:66
UPlotLegendItem::_aChangeText
QAction * _aChangeText
Definition: UPlot.h:376
UERROR
#define UERROR(...)
UPlot::sceneRect
QRectF sceneRect() const
Definition: UPlot.cpp:3232
UPlot::setWorkingDirectory
void setWorkingDirectory(const QString &workingDirectory)
Definition: UPlot.cpp:2959
UPlotCurve::clear
virtual void clear()
Definition: UPlot.cpp:653
value
value
i
int i
ULOGGER_WARN
#define ULOGGER_WARN(...)
Definition: ULogger.h:55
text
text
UPlot::contextMenuEvent
virtual void contextMenuEvent(QContextMenuEvent *event)
Definition: UPlot.cpp:2752
UPlot::_lowestRefreshRate
int _lowestRefreshRate
Definition: UPlot.h:611
UPlot::_aShowLegend
QAction * _aShowLegend
Definition: UPlot.h:619
UPlotLegendItem::_aShowStdDevMeanMax
QAction * _aShowStdDevMeanMax
Definition: UPlot.h:380
UPlot::_aLimit500
QAction * _aLimit500
Definition: UPlot.h:626
UPlotAxis::_gradMaxDigits
int _gradMaxDigits
Definition: UPlot.h:340
UPlotCurve::addValues
void addValues(QVector< UPlotItem * > &data)
Definition: UPlot.cpp:478
UPlotAxis::_max
qreal _max
Definition: UPlot.h:336


rtabmap
Author(s): Mathieu Labbe
autogenerated on Thu Jul 25 2024 02:50:23