From 0ee0bd882ee0dac6d8e822cb151fdd5e531100df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Fri, 19 Aug 2016 19:48:44 +0200 Subject: [PATCH] Some more graph handling improvements --- gpxsee.pro | 3 +- lang/gpxsee_cs.ts | 60 +++++++-------- src/elevationgraph.cpp | 2 + src/graphitem.cpp | 10 +++ src/graphitem.h | 3 +- src/graphview.cpp | 157 ++++++++++++++++++--------------------- src/graphview.h | 6 +- src/heartrategraph.cpp | 19 +++-- src/heartrategraph.h | 2 + src/slideritem.cpp | 2 +- src/speedgraph.cpp | 19 +++-- src/speedgraph.h | 2 + src/temperaturegraph.cpp | 23 +++--- src/temperaturegraph.h | 2 + 14 files changed, 164 insertions(+), 146 deletions(-) create mode 100644 src/graphitem.cpp diff --git a/gpxsee.pro b/gpxsee.pro index b2476191..a737e0f2 100644 --- a/gpxsee.pro +++ b/gpxsee.pro @@ -87,7 +87,8 @@ SOURCES += src/main.cpp \ src/trackitem.cpp \ src/tooltip.cpp \ src/route.cpp \ - src/routeitem.cpp + src/routeitem.cpp \ + src/graphitem.cpp RESOURCES += gpxsee.qrc TRANSLATIONS = lang/gpxsee_cs.ts macx { diff --git a/lang/gpxsee_cs.ts b/lang/gpxsee_cs.ts index d75b11a6..6d26b630 100644 --- a/lang/gpxsee_cs.ts +++ b/lang/gpxsee_cs.ts @@ -536,48 +536,48 @@ HeartRateGraph - + Distance Vzdálenost - + Heart rate Tep - + km km - + 1/min 1/min - + Average Průměr - + Maximum Maximum - + m m - + ft ft - + mi mi @@ -633,53 +633,53 @@ SpeedGraph - + Distance Vzdálenost - + Speed Rychlost - + m m - + km - + ft ft - + km/h km/h - + Average Průměr - + Maximum Maximum - + mi mi - + mi/h mi/h @@ -687,58 +687,58 @@ TemperatureGraph - + Distance Vzdálenost - + Temperature Teplota - + Average Průměr - + Minimum Minimum - + Maximum Maximum - + m m - + km km - + ft ft - + mi mi - + C C - + F F diff --git a/src/elevationgraph.cpp b/src/elevationgraph.cpp index 053cc3c7..fdc78260 100644 --- a/src/elevationgraph.cpp +++ b/src/elevationgraph.cpp @@ -184,6 +184,7 @@ void ElevationGraph::showTracks(bool show) setInfo(); showGraph(show, Track); + setXUnits(); redraw(); } @@ -194,6 +195,7 @@ void ElevationGraph::showRoutes(bool show) setInfo(); showGraph(show, Route); + setXUnits(); redraw(); } diff --git a/src/graphitem.cpp b/src/graphitem.cpp new file mode 100644 index 00000000..e9c8d625 --- /dev/null +++ b/src/graphitem.cpp @@ -0,0 +1,10 @@ +#include +#include +#include "graphitem.h" + +void GraphItem::setColor(const QColor &color) +{ + QBrush brush(color, Qt::SolidPattern); + QPen pen(brush, 0); + setPen(pen); +} diff --git a/src/graphitem.h b/src/graphitem.h index 25248b3d..39447a81 100644 --- a/src/graphitem.h +++ b/src/graphitem.h @@ -9,8 +9,9 @@ public: GraphItem(const QPainterPath &path, QGraphicsItem * parent = 0) : QGraphicsPathItem(path, parent) {_id = 0;} - int id() {return _id;} + int id() const {return _id;} void setId(int id) {_id = id;} + void setColor(const QColor &color); private: int _id; diff --git a/src/graphview.cpp b/src/graphview.cpp index 644dd069..9eb4e976 100644 --- a/src/graphview.cpp +++ b/src/graphview.cpp @@ -39,6 +39,11 @@ GraphView::GraphView(QWidget *parent) _sliderInfo->setZValue(2.0); _info = new InfoItem(); + _scene->addItem(_xAxis); + _scene->addItem(_yAxis); + _scene->addItem(_slider); + _scene->addItem(_info); + connect(_slider, SIGNAL(positionChanged(const QPointF&)), this, SLOT(emitSliderPositionChanged(const QPointF&))); connect(_scene, SIGNAL(mouseClicked(const QPointF&)), this, @@ -54,30 +59,6 @@ GraphView::GraphView(QWidget *parent) _sliderPos = 0; } -GraphView::~GraphView() -{ - if (_xAxis->scene() != _scene) - delete _xAxis; - if (_yAxis->scene() != _scene) - delete _yAxis; - if (_slider->scene() != _scene) - delete _slider; - if (_info->scene() != _scene) - delete _info; -} - -void GraphView::updateBounds(const QPointF &point) -{ - if (point.x() < _bounds.left()) - _bounds.setLeft(point.x()); - if (point.x() > _bounds.right()) - _bounds.setRight(point.x()); - if (point.y() > _bounds.bottom()) - _bounds.setBottom(point.y()); - if (point.y() < _bounds.top()) - _bounds.setTop(point.y()); -} - void GraphView::createXLabel() { _xAxis->setLabel(QString("%1 [%2]").arg(_xLabel).arg(_xUnits)); @@ -121,44 +102,68 @@ void GraphView::loadData(const QVector &data, int id) if (data.size() < 2) return; - if (!_graphs.size()) - _bounds.moveTo(data.at(0)); - - updateBounds(data.at(0)); path.moveTo(data.at(0).x(), -data.at(0).y()); for (int i = 1; i < data.size(); i++) { const QPointF &p = data.at(i); path.lineTo(p.x(), -p.y()); - updateBounds(p); } pi = new GraphItem(path); - QBrush brush(_palette.color(), Qt::SolidPattern); - QPen pen(brush, 0); - pi->setPen(pen); pi->setId(id); - if (_hide.contains(id)) - pi->hide(); - _scene->addItem(pi); + pi->setColor(_palette.color()); + _graphs.append(pi); + + if (!_hide.contains(id)) { + _visible.append(pi); + _scene->addItem(pi); + updateBounds(path); + } } void GraphView::showGraph(bool show, int id) { - for (int i = 0; i < _graphs.count(); i++) - if (_graphs.at(i)->id() == id) - _graphs.at(i)->setVisible(show); - if (show) _hide.remove(id); else _hide.insert(id); + + _visible.clear(); + _bounds = QRectF(); + for (int i = 0; i < _graphs.count(); i++) { + GraphItem* gi = _graphs.at(i); + if (_hide.contains(gi->id())) { + if (gi->scene() == _scene) + _scene->removeItem(gi); + } else { + if (gi->scene() != _scene) + _scene->addItem(gi); + _visible.append(gi); + updateBounds(gi->path()); + } + } } void GraphView::redraw() { - if (!_graphs.isEmpty()) - redraw(viewport()->size() - QSizeF(MARGIN, MARGIN)); + redraw(viewport()->size() - QSizeF(MARGIN, MARGIN)); +} + +void GraphView::updateBounds(const QPainterPath &path) +{ + QRectF br = path.boundingRect(); + br.moveTopLeft(QPointF(br.left(), -br.top() - br.height())); + _bounds |= br; +} + +QRectF GraphView::graphsBoundingRect() const +{ + QRectF rect; + + for (int i = 0; i < _visible.count(); i++) + rect |= _visible.at(i)->boundingRect(); + + return rect; } void GraphView::redraw(const QSizeF &size) @@ -170,18 +175,6 @@ void GraphView::redraw(const QSizeF &size) qreal xs, ys; - if (_xAxis->scene() == _scene) - _scene->removeItem(_xAxis); - if (_yAxis->scene() == _scene) - _scene->removeItem(_yAxis); - if (_slider->scene() == _scene) - _scene->removeItem(_slider); - if (_info->scene() == _scene) - _scene->removeItem(_info); - - for (int i = 0; i < _graphs.size(); i++) - _graphs.at(i)->resetTransform(); - rx = RangeF(_bounds.left() * _xScale, _bounds.right() * _xScale); ry = RangeF(_bounds.top() * _yScale + _yOffset, _bounds.bottom() * _yScale + _yOffset); @@ -193,7 +186,7 @@ void GraphView::redraw(const QSizeF &size) mx = _xAxis->margin(); my = _yAxis->margin(); - r = _scene->itemsBoundingRect(); + r = graphsBoundingRect(); if (r.height() < _minYRange) r.adjust(0, -(_minYRange/2 - r.height()/2), 0, _minYRange/2 - r.height()/2); @@ -203,10 +196,12 @@ void GraphView::redraw(const QSizeF &size) - _info->boundingRect().height()) / r.height(); transform.scale(xs, ys); - for (int i = 0; i < _graphs.size(); i++) - _graphs.at(i)->setTransform(transform); + for (int i = 0; i < _visible.size(); i++) + _visible.at(i)->setTransform(transform); - r = _scene->itemsBoundingRect(); + QPointF p(r.left() * xs, r.top() * ys); + QSizeF s(r.width() * xs, r.height() * ys); + r = QRectF(p, s); if (r.height() < _minYRange * ys) r.adjust(0, -(_minYRange/2 * ys - r.height()/2), 0, (_minYRange/2) * ys - r.height()/2); @@ -215,25 +210,21 @@ void GraphView::redraw(const QSizeF &size) _yAxis->setSize(r.height()); _xAxis->setPos(r.bottomLeft()); _yAxis->setPos(r.bottomLeft()); - _scene->addItem(_xAxis); - _scene->addItem(_yAxis); _slider->setArea(r); updateSliderPosition(); - _scene->addItem(_slider); - r = _scene->itemsBoundingRect(); + r |= _xAxis->sceneBoundingRect(); + r |= _yAxis->sceneBoundingRect(); _info->setPos(r.topLeft() + QPointF(r.width()/2 - _info->boundingRect().width()/2, -_info->boundingRect().height())); - _scene->addItem(_info); _scene->setSceneRect(_scene->itemsBoundingRect()); } void GraphView::resizeEvent(QResizeEvent *) { - if (!_graphs.empty()) - redraw(); + redraw(); } void GraphView::plot(QPainter *painter, const QRectF &target) @@ -254,19 +245,14 @@ void GraphView::plot(QPainter *painter, const QRectF &target) void GraphView::clear() { - if (_xAxis->scene() == _scene) - _scene->removeItem(_xAxis); - if (_yAxis->scene() == _scene) - _scene->removeItem(_yAxis); - if (_slider->scene() == _scene) - _scene->removeItem(_slider); - if (_info->scene() == _scene) - _scene->removeItem(_info); - _slider->clear(); _info->clear(); - _scene->clear(); + + for (int i = 0; i < _graphs.count(); i++) + delete _graphs[i]; + _graphs.clear(); + _visible.clear(); _palette.reset(); _bounds = QRectF(); @@ -308,26 +294,28 @@ static qreal yAtX(const QPainterPath &path, qreal x) void GraphView::updateSliderPosition() { - Q_ASSERT(_bounds.width() > 0); + if (_bounds.width() <= 0) + return; if (_sliderPos <= _bounds.right() && _sliderPos >= _bounds.left()) { _slider->setPos((_sliderPos / _bounds.width()) * _slider->area().width(), _slider->area().bottom()); - _slider->setVisible(true); - } else + _slider->setVisible(!_visible.isEmpty()); + } else { + _slider->setPos(_slider->area().left(), _slider->area().bottom()); _slider->setVisible(false); + } updateSliderInfo(); } void GraphView::updateSliderInfo() { - _sliderInfo->setVisible(_graphs.size() == 1); - + _sliderInfo->setVisible(_visible.count() == 1); if (!_sliderInfo->isVisible()) return; - const QPainterPath &path = _graphs.at(0)->path(); + const QPainterPath &path = _visible.first()->path(); QRectF br = path.boundingRect(); if (br.height() < _minYRange) br.adjust(0, -(_minYRange/2 - br.height()/2), 0, @@ -348,17 +336,18 @@ void GraphView::updateSliderInfo() void GraphView::emitSliderPositionChanged(const QPointF &pos) { - Q_ASSERT(_slider->area().width() > 0); + if (_slider->area().width() <= 0) + return; _sliderPos = (pos.x() / _slider->area().width()) * _bounds.width(); - updateSliderPosition(); + emit sliderPositionChanged(_sliderPos); } void GraphView::setSliderPosition(qreal pos) { - if (_graphs.isEmpty()) + if (_visible.isEmpty()) return; _sliderPos = pos; @@ -368,7 +357,7 @@ void GraphView::setSliderPosition(qreal pos) void GraphView::newSliderPosition(const QPointF &pos) { if (_slider->area().contains(pos)) - emitSliderPositionChanged(pos); + _slider->setPos(pos); } void GraphView::addInfo(const QString &key, const QString &value) diff --git a/src/graphview.h b/src/graphview.h index c24f2ecf..7f561b75 100644 --- a/src/graphview.h +++ b/src/graphview.h @@ -33,7 +33,6 @@ class GraphView : public QGraphicsView public: GraphView(QWidget *parent = 0); - ~GraphView(); void loadData(const QVector &data, int id = 0); int count() const {return _graphs.count();} @@ -84,9 +83,10 @@ private slots: private: void createXLabel(); void createYLabel(); - void updateBounds(const QPointF &point); void updateSliderPosition(); void updateSliderInfo(); + void updateBounds(const QPainterPath &path); + QRectF graphsBoundingRect() const; qreal _xScale, _yScale; qreal _yOffset; @@ -104,8 +104,8 @@ private: InfoItem *_info; QList _graphs; + QList _visible; QSet _hide; - bool _hideAll; QRectF _bounds; Palette _palette; }; diff --git a/src/heartrategraph.cpp b/src/heartrategraph.cpp index 6e4a78da..f0a1202f 100644 --- a/src/heartrategraph.cpp +++ b/src/heartrategraph.cpp @@ -5,6 +5,7 @@ HeartRateGraph::HeartRateGraph(QWidget *parent) : GraphTab(parent) { _units = Metric; + _showTracks = true; GraphView::setYUnits(tr("1/min")); setXLabel(tr("Distance")); @@ -15,10 +16,13 @@ HeartRateGraph::HeartRateGraph(QWidget *parent) : GraphTab(parent) void HeartRateGraph::setInfo() { - GraphView::addInfo(tr("Average"), QString::number(avg() * yScale(), 'f', 0) - + UNIT_SPACE + yUnits()); - GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale(), 'f', 0) - + UNIT_SPACE + yUnits()); + if (_showTracks) { + GraphView::addInfo(tr("Average"), QString::number(avg() * yScale(), 'f', + 0) + UNIT_SPACE + yUnits()); + GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale(), 'f', + 0) + UNIT_SPACE + yUnits()); + } else + clearInfo(); } void HeartRateGraph::loadGPX(const GPX &gpx) @@ -103,12 +107,11 @@ void HeartRateGraph::setUnits(enum Units units) void HeartRateGraph::showTracks(bool show) { - if (show) - setInfo(); - else - clearInfo(); + _showTracks = show; + setInfo(); showGraph(show); + setXUnits(); redraw(); } diff --git a/src/heartrategraph.h b/src/heartrategraph.h index 7e9f63f0..b193677e 100644 --- a/src/heartrategraph.h +++ b/src/heartrategraph.h @@ -26,7 +26,9 @@ private: void setInfo(); QList _avg; + enum Units _units; + bool _showTracks; }; #endif // HEARTRATEGRAPH_H diff --git a/src/slideritem.cpp b/src/slideritem.cpp index 421b0718..bfb18b8e 100644 --- a/src/slideritem.cpp +++ b/src/slideritem.cpp @@ -24,7 +24,7 @@ void SliderItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option painter->setPen(Qt::red); painter->drawLine(0, 0, 0, -_area.height()); - //painter->drawRect(boundingRect()); +// painter->drawRect(boundingRect()); } QVariant SliderItem::itemChange(GraphicsItemChange change, const QVariant &value) diff --git a/src/speedgraph.cpp b/src/speedgraph.cpp index 137d0efa..bb6b339d 100644 --- a/src/speedgraph.cpp +++ b/src/speedgraph.cpp @@ -6,6 +6,7 @@ SpeedGraph::SpeedGraph(QWidget *parent) : GraphTab(parent) { _units = Metric; + _showTracks = true; setYUnits(); setXLabel(tr("Distance")); @@ -16,10 +17,13 @@ SpeedGraph::SpeedGraph(QWidget *parent) : GraphTab(parent) void SpeedGraph::setInfo() { - GraphView::addInfo(tr("Average"), QString::number(avg() * yScale(), 'f', 1) - + UNIT_SPACE + yUnits()); - GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale(), 'f', 1) - + UNIT_SPACE + yUnits()); + if (_showTracks) { + GraphView::addInfo(tr("Average"), QString::number(avg() * yScale(), 'f', + 1) + UNIT_SPACE + yUnits()); + GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale(), 'f', + 1) + UNIT_SPACE + yUnits()); + } else + clearInfo(); } void SpeedGraph::loadGPX(const GPX &gpx) @@ -111,12 +115,11 @@ void SpeedGraph::setUnits(enum Units units) void SpeedGraph::showTracks(bool show) { - if (show) - setInfo(); - else - clearInfo(); + _showTracks = show; + setInfo(); showGraph(show); + setXUnits(); redraw(); } diff --git a/src/speedgraph.h b/src/speedgraph.h index 48a47bfe..b483e7dc 100644 --- a/src/speedgraph.h +++ b/src/speedgraph.h @@ -28,7 +28,9 @@ private: void setInfo(); QList _avg; + enum Units _units; + bool _showTracks; }; #endif // SPEEDGRAPH_H diff --git a/src/temperaturegraph.cpp b/src/temperaturegraph.cpp index 46d6211f..a8ea3ef0 100644 --- a/src/temperaturegraph.cpp +++ b/src/temperaturegraph.cpp @@ -5,6 +5,7 @@ TemperatureGraph::TemperatureGraph(QWidget *parent) : GraphTab(parent) { _units = Metric; + _showTracks = true; setYUnits(); setXLabel(tr("Distance")); @@ -15,12 +16,15 @@ TemperatureGraph::TemperatureGraph(QWidget *parent) : GraphTab(parent) void TemperatureGraph::setInfo() { - GraphView::addInfo(tr("Average"), QString::number(avg() * yScale() - + yOffset(), 'f', 1) + UNIT_SPACE + yUnits()); - GraphView::addInfo(tr("Minimum"), QString::number(min() * yScale() - + yOffset(), 'f', 1) + UNIT_SPACE + yUnits()); - GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale() - + yOffset(), 'f', 1) + UNIT_SPACE + yUnits()); + if (_showTracks) { + GraphView::addInfo(tr("Average"), QString::number(avg() * yScale() + + yOffset(), 'f', 1) + UNIT_SPACE + yUnits()); + GraphView::addInfo(tr("Minimum"), QString::number(min() * yScale() + + yOffset(), 'f', 1) + UNIT_SPACE + yUnits()); + GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale() + + yOffset(), 'f', 1) + UNIT_SPACE + yUnits()); + } else + clearInfo(); } void TemperatureGraph::loadGPX(const GPX &gpx) @@ -119,12 +123,11 @@ void TemperatureGraph::setUnits(enum Units units) void TemperatureGraph::showTracks(bool show) { - if (show) - setInfo(); - else - clearInfo(); + _showTracks = show; + setInfo(); showGraph(show); + setXUnits(); redraw(); } diff --git a/src/temperaturegraph.h b/src/temperaturegraph.h index e63b7e8b..27a61891 100644 --- a/src/temperaturegraph.h +++ b/src/temperaturegraph.h @@ -28,7 +28,9 @@ private: void setInfo(); QList _avg; + enum Units _units; + bool _showTracks; }; #endif // TEMPERATUREGRAPH_H