From 93670d302693f4082dd3ddb8887f7bc79706ea0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Mon, 21 Mar 2016 22:37:55 +0100 Subject: [PATCH] Added heart rate graph Improved graphs loading performance Fixed various corner case behaviour bugs --- gpxsee.pro | 6 +- lang/gpxsee_cs.ts | 232 ++++++++++++++++++++++++----------------- src/elevationgraph.cpp | 38 +++---- src/graphview.cpp | 15 ++- src/graphview.h | 2 + src/gui.cpp | 22 +++- src/gui.h | 6 ++ src/heartrategraph.cpp | 87 ++++++++++++++++ src/heartrategraph.h | 30 ++++++ src/parser.cpp | 9 +- src/speedgraph.cpp | 38 +++---- src/track.cpp | 52 ++++++--- src/track.h | 7 +- src/trackpoint.h | 8 +- src/trackview.cpp | 24 +++-- src/trackview.h | 2 +- 16 files changed, 409 insertions(+), 169 deletions(-) create mode 100644 src/heartrategraph.cpp create mode 100644 src/heartrategraph.h diff --git a/gpxsee.pro b/gpxsee.pro index a594cc3e..df040db6 100644 --- a/gpxsee.pro +++ b/gpxsee.pro @@ -33,7 +33,8 @@ HEADERS += src/config.h \ src/graphview.h \ src/trackpoint.h \ src/waypointitem.h \ - src/palette.h + src/palette.h \ + src/heartrategraph.h SOURCES += src/main.cpp \ src/gui.cpp \ src/gpx.cpp \ @@ -57,7 +58,8 @@ SOURCES += src/main.cpp \ src/track.cpp \ src/graphview.cpp \ src/waypointitem.cpp \ - src/palette.cpp + src/palette.cpp \ + src/heartrategraph.cpp RESOURCES += gpxsee.qrc TRANSLATIONS = lang/gpxsee_cs.ts macx:ICON = icons/gpxsee.icns diff --git a/lang/gpxsee_cs.ts b/lang/gpxsee_cs.ts index 67166b53..19739463 100644 --- a/lang/gpxsee_cs.ts +++ b/lang/gpxsee_cs.ts @@ -15,43 +15,43 @@ - + km km - + m m - + Ascent Stoupání - + Descent Klesání - + Minimum Minimum - + mi mi - + ft ft - + Maximum Maximum @@ -59,352 +59,396 @@ GUI - + About Qt O Qt - + GPXSee is distributed under the terms of the GNU General Public License version 3. For more info about GPXSee visit the project homepage at Program GPXSee je distribuován pod podmínkami licence GNU General Public License verze 3. Pro více informací navštivte stránky programu na adrese - + Open file Otevřít soubor - + Save as Uložit jako - + Open POI file Otevřít POI soubor - + Open Otevřít - + Quit Ukončit - - - + + + Keyboard controls Ovládací klávesy - + Save Uložit - + Close Zavřít - + Reload Znovu načíst - + Show Zobrazit - - + + File Soubor - - - + + + Data sources Zdroje dat - + Load POI file Nahrát POI soubor - + Close POI files Zavřit soubory POI - + Show POIs Zobrazit POI - + Show map Zobrazit mapu - + Show graphs Zobrazovat grafy - + Show toolbars Zobrazovat nástrojové lišty - + Metric Metrické - + Imperial Imperiální - + Next Následující - + Previous Předchozí - + Last Poslední - + First První - + Map Mapa - + POI POI - + POI files POI soubory - + Settings Nastavení - + Units Jednotky - + Help Nápověda - + Elevation Výška - + Speed Rychlost - + + Heart rate + Tep + + + Next file Následující soubor - + Previous file Předchozí soubor - + First file První soubor - + Last file Poslední soubor - + Append modifier Modifikátor nahradit/přidat - + Map (tiles) source URLs are read on program startup from the following file: URL mapových zdrojů (dlaždic) jsou načteny při startu programu z následujícího souboru: - + The file format is one map entry per line, consisting of the map name and tiles URL delimited by a TAB character. The tile X and Y coordinates are replaced with $x and $y in the URL and the zoom level is replaced with $z. An example map file could look like: Formát souboru je jeden mapový záznam na řádku, kde mapový záznam sestává ze jména mapy a URL dlaždic navzájem oddělených tabulátorem. Souřadnice dlaždice jsou v URL nahrazeny řetězci $x a $y, úroven přiblížení (zoom) pak řetězcem $z. Příklad: - + To make GPXSee load a POI file automatically on startup, add the file to the following directory: POI soubory, které se mají automaticky nahrát při startu programu jsou načítány z následujícího adresáře: - + GPX files (*.gpx);;All files (*) soubory GPX (*.gpx);;všechny soubory (*) - - + + Line: %1 Řádka: %1 - + GPX files (*.gpx);;CSV files (*.csv);;All files (*) soubory GPX (*.gpx);;soubory CSV (*.csv);;všechny soubory (*) - - + + mi mi - - - - + + + + ft ft - - + + Maximum Maximum - - + + Minimum Minimum - - + + About GPXSee O aplikaci GPXSee - + Navigation Navigace - + GPX viewer and analyzer Prohlížeč a analyzátor GPX - + Map sources Mapové zdroje - + POIs POI body - - + + Distance Vzdálenost - - + + Time Čas - - + + Ascent Stoupání - - - - + + + + m m - - + + Descent Klesání - + %1 tracks Počet tras: %1 - - + + km km - - + + Error Chyba - + Error loading GPX file: %1 Soubor GPX nelze otevřít: %1 - + Error loading POI file: %1 Soubor POI nelze otevřít: %1 + + HeartRateGraph + + + Distance + Vzdálenost + + + + Heart rate + Tep + + + + + km + km + + + + 1/min + 1/min + + + + Average + Průměr + + + + Maximum + Maximum + + + + mi + mi + + QObject diff --git a/src/elevationgraph.cpp b/src/elevationgraph.cpp index 34a69d0b..69360a65 100644 --- a/src/elevationgraph.cpp +++ b/src/elevationgraph.cpp @@ -11,12 +11,12 @@ ElevationGraph::ElevationGraph(QWidget *parent) : GraphView(parent) _max = -FLT_MAX; _min = FLT_MAX; - GraphView::setXLabel(tr("Distance")); - GraphView::setYLabel(tr("Elevation")); - GraphView::setXUnits(tr("km")); - GraphView::setYUnits(tr("m")); - GraphView::setXScale(M2KM); - GraphView::setMinRange(50.0); + setXLabel(tr("Distance")); + setYLabel(tr("Elevation")); + setXUnits(tr("km")); + setYUnits(tr("m")); + setXScale(M2KM); + setMinRange(50.0); } void ElevationGraph::addInfo() @@ -38,14 +38,16 @@ void ElevationGraph::loadGPX(const GPX &gpx) qreal min, max, ascent = 0, descent = 0; gpx.track(i).elevationGraph(data); - if (data.isEmpty()) + if (data.count() < 2) { + skipColor(); continue; + } min = max = data.at(0).y(); - for (int i = 1; i < data.size(); i++) { - qreal cur = data.at(i).y(); - qreal prev = data.at(i-1).y(); + for (int j = 1; j < data.size(); j++) { + qreal cur = data.at(j).y(); + qreal prev = data.at(j-1).y(); if (cur > prev) ascent += cur - prev; @@ -81,15 +83,15 @@ void ElevationGraph::clear() void ElevationGraph::setUnits(enum Units units) { if (units == Metric) { - GraphView::setXUnits(tr("km")); - GraphView::setYUnits(tr("m")); - GraphView::setXScale(M2KM); - GraphView::setYScale(1); + setXUnits(tr("km")); + setYUnits(tr("m")); + setXScale(M2KM); + setYScale(1); } else { - GraphView::setXUnits(tr("mi")); - GraphView::setYUnits(tr("ft")); - GraphView::setXScale(M2MI); - GraphView::setYScale(M2FT); + setXUnits(tr("mi")); + setYUnits(tr("ft")); + setXScale(M2MI); + setYScale(M2FT); } clearInfo(); diff --git a/src/graphview.cpp b/src/graphview.cpp index fa4064e2..eaaeb20d 100644 --- a/src/graphview.cpp +++ b/src/graphview.cpp @@ -294,7 +294,7 @@ void GraphView::emitSliderPositionChanged(const QPointF &pos) return; qreal val = pos.x() / _slider->area().width(); - emit sliderPositionChanged(val); + emit sliderPositionChanged(val * (_xMax - _xMin)); const QPainterPath &path = _graphs.at(0)->path(); QRectF br = path.boundingRect(); @@ -309,18 +309,27 @@ void GraphView::emitSliderPositionChanged(const QPointF &pos) qreal GraphView::sliderPosition() const { - return _slider->pos().x() / _slider->area().width(); + if (!_slider->isVisible()) + return -1; + else + return (_slider->pos().x() / _slider->area().width()) * (_xMax - _xMin); } void GraphView::setSliderPosition(qreal pos) { - _slider->setPos(pos * _slider->area().width(), 0); + if (pos > (_xMax - _xMin)) + _slider->setVisible(false); + else { + _slider->setPos((pos / (_xMax - _xMin)) * _slider->area().width(), 0); + _slider->setVisible(true); + } } void GraphView::newSliderPosition(const QPointF &pos) { if (_slider->area().contains(pos)) { _slider->setPos(pos); + _slider->setVisible(true); emitSliderPositionChanged(pos); } } diff --git a/src/graphview.h b/src/graphview.h index 8373b7da..3768b8be 100644 --- a/src/graphview.h +++ b/src/graphview.h @@ -55,6 +55,8 @@ public: void addInfo(const QString &key, const QString &value); void clearInfo(); + void skipColor() {_palette.color();} + signals: void sliderPositionChanged(qreal); diff --git a/src/gui.cpp b/src/gui.cpp index 2132af31..98f9bef5 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -22,6 +22,7 @@ #include "maplist.h" #include "elevationgraph.h" #include "speedgraph.h" +#include "heartrategraph.h" #include "trackview.h" #include "infoitem.h" #include "filebrowser.h" @@ -56,6 +57,8 @@ GUI::GUI(QWidget *parent) : QMainWindow(parent) SLOT(movePositionMarker(qreal))); connect(_speedGraph, SIGNAL(sliderPositionChanged(qreal)), _track, SLOT(movePositionMarker(qreal))); + connect(_heartRateGraph, SIGNAL(sliderPositionChanged(qreal)), _track, + SLOT(movePositionMarker(qreal))); _browser = new FileBrowser(this); _browser->setFilter(QStringList("*.gpx")); @@ -75,6 +78,9 @@ GUI::GUI(QWidget *parent) : QMainWindow(parent) _time = 0; _trackCount = 0; + _lastGraph = static_cast(_trackGraphs->currentWidget()); + _lastSliderPos = _lastGraph->sliderPosition(); + resize(600, 800); } @@ -349,10 +355,12 @@ void GUI::createTrackGraphs() { _elevationGraph = new ElevationGraph; _speedGraph = new SpeedGraph; + _heartRateGraph = new HeartRateGraph; _trackGraphs = new QTabWidget; _trackGraphs->addTab(_elevationGraph, tr("Elevation")); _trackGraphs->addTab(_speedGraph, tr("Speed")); + _trackGraphs->addTab(_heartRateGraph, tr("Heart rate")); connect(_trackGraphs, SIGNAL(currentChanged(int)), this, SLOT(graphChanged(int))); @@ -478,6 +486,7 @@ bool GUI::loadFile(const QString &fileName) if (gpx.loadFile(fileName)) { _elevationGraph->loadGPX(gpx); _speedGraph->loadGPX(gpx); + _heartRateGraph->loadGPX(gpx); _track->loadGPX(gpx); if (_showPOIAction->isChecked()) _track->loadPOI(_poi); @@ -611,6 +620,7 @@ void GUI::reloadFile() _elevationGraph->clear(); _speedGraph->clear(); + _heartRateGraph->clear(); _track->clear(); for (int i = 0; i < _files.size(); i++) { @@ -635,6 +645,7 @@ void GUI::closeFile() _elevationGraph->clear(); _speedGraph->clear(); + _heartRateGraph->clear(); _track->clear(); _files.clear(); @@ -721,10 +732,11 @@ void GUI::poiFileChecked(int index) void GUI::graphChanged(int index) { - if (_trackGraphs->widget(index) == _elevationGraph) - _elevationGraph->setSliderPosition(_speedGraph->sliderPosition()); - else if (_trackGraphs->widget(index) == _speedGraph) - _speedGraph->setSliderPosition(_elevationGraph->sliderPosition()); + GraphView *tv = static_cast(_trackGraphs->widget(index)); + if (_lastGraph->sliderPosition() >= 0) + _lastSliderPos = _lastGraph->sliderPosition(); + tv->setSliderPosition(_lastSliderPos); + _lastGraph = tv; } void GUI::updateNavigationActions() @@ -751,6 +763,7 @@ void GUI::setMetricUnits() _track->setUnits(Metric); _elevationGraph->setUnits(Metric); _speedGraph->setUnits(Metric); + _heartRateGraph->setUnits(Metric); updateStatusBarInfo(); } @@ -759,6 +772,7 @@ void GUI::setImperialUnits() _track->setUnits(Imperial); _elevationGraph->setUnits(Imperial); _speedGraph->setUnits(Imperial); + _heartRateGraph->setUnits(Imperial); updateStatusBarInfo(); } diff --git a/src/gui.h b/src/gui.h index 06132556..f224da76 100644 --- a/src/gui.h +++ b/src/gui.h @@ -14,8 +14,10 @@ class QAction; class QLabel; class QSignalMapper; class FileBrowser; +class GraphView; class ElevationGraph; class SpeedGraph; +class HeartRateGraph; class TrackView; class Map; @@ -124,6 +126,7 @@ private: ElevationGraph *_elevationGraph; SpeedGraph *_speedGraph; + HeartRateGraph *_heartRateGraph; TrackView *_track; POI _poi; @@ -137,6 +140,9 @@ private: qreal _distance; qreal _time; int _trackCount; + + GraphView *_lastGraph; + qreal _lastSliderPos; }; #endif // GUI_H diff --git a/src/heartrategraph.cpp b/src/heartrategraph.cpp new file mode 100644 index 00000000..b3043e10 --- /dev/null +++ b/src/heartrategraph.cpp @@ -0,0 +1,87 @@ +#include "gpx.h" +#include "heartrategraph.h" + + +HeartRateGraph::HeartRateGraph(QWidget *parent) : GraphView(parent) +{ + _max = 0; + + setXLabel(tr("Distance")); + setYLabel(tr("Heart rate")); + setXUnits(tr("km")); + setYUnits(tr("1/min")); + setXScale(M2KM); + setPrecision(0); +} + +void HeartRateGraph::addInfo() +{ + 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); +} + +void HeartRateGraph::loadGPX(const GPX &gpx) +{ + for (int i = 0; i < gpx.trackCount(); i++) { + QVector data; + qreal max = 0, sum = 0, w = 0; + + gpx.track(i).heartRateGraph(data); + if (data.count() < 2) { + skipColor(); + continue; + } + + for (int j = 1; j < data.size(); j++) { + sum += data.at(j).y() * (data.at(j).x() - data.at(j-1).x()); + w += data.at(j).x() - data.at(j-1).x(); + } + _avg.append(QPointF(gpx.track(i).distance(), sum/w)); + + for (int j = 0; j < data.size(); j++) + max = qMax(max, data.at(j).y()); + _max = qMax(_max, max); + + addInfo(); + loadData(data); + } +} + +qreal HeartRateGraph::avg() const +{ + qreal sum = 0, w = 0; + QList::const_iterator it; + + for (it = _avg.begin(); it != _avg.end(); it++) { + sum += it->y() * it->x(); + w += it->x(); + } + + return (sum / w); +} + +void HeartRateGraph::clear() +{ + _max = 0; + _avg.clear(); + + GraphView::clear(); +} + +void HeartRateGraph::setUnits(enum Units units) +{ + if (units == Metric) { + setXUnits(tr("km")); + setXScale(M2KM); + } else { + setXUnits(tr("mi")); + setXScale(M2MI); + } + + clearInfo(); + addInfo(); + + redraw(); +} diff --git a/src/heartrategraph.h b/src/heartrategraph.h new file mode 100644 index 00000000..372c78a5 --- /dev/null +++ b/src/heartrategraph.h @@ -0,0 +1,30 @@ +#ifndef HEARTRATEGRAPH_H +#define HEARTRATEGRAPH_H + +#include "graphview.h" +#include "units.h" + +class GPX; + +class HeartRateGraph : public GraphView +{ + Q_OBJECT + +public: + HeartRateGraph(QWidget *parent = 0); + + void loadGPX(const GPX &gpx); + void clear(); + void setUnits(enum Units units); + + qreal avg() const; + qreal max() const {return _max;} + +private: + void addInfo(); + + qreal _max; + QList _avg; +}; + +#endif // HEARTRATEGRAPH_H diff --git a/src/parser.cpp b/src/parser.cpp index 805a32af..963f0051 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -5,16 +5,18 @@ void Parser::handleExtensionData(QStringRef element, const QString &value) { if (element == "speed") _track->last().speed = value.toDouble(); + else if (element == "hr" || element == "heartrate") + _track->last().heartRate = value.toDouble(); } void Parser::handleTrekPointData(QStringRef element, const QString &value) { if (element == "ele") _track->last().elevation = value.toLatin1().toDouble(); - if (element == "time") + else if (element == "time") _track->last().timestamp = QDateTime::fromString(value.toLatin1(), Qt::ISODate); - if (element == "geoidheight") + else if (element == "geoidheight") _track->last().geoidheight = value.toLatin1().toDouble(); } @@ -40,7 +42,8 @@ void Parser::handleWayPointAttributes(const QXmlStreamAttributes &attr) void Parser::extensions() { while (_reader.readNextStartElement()) { - if (_reader.name() == "speed") + if (_reader.name() == "speed" || _reader.name() == "hr" + || _reader.name() == "heartrate") handleExtensionData(_reader.name(), _reader.readElementText()); else _reader.skipCurrentElement(); diff --git a/src/speedgraph.cpp b/src/speedgraph.cpp index e7c1723e..e4465df0 100644 --- a/src/speedgraph.cpp +++ b/src/speedgraph.cpp @@ -7,13 +7,13 @@ SpeedGraph::SpeedGraph(QWidget *parent) : GraphView(parent) { _max = 0; - GraphView::setXLabel(tr("Distance")); - GraphView::setYLabel(tr("Speed")); - GraphView::setXUnits(tr("km")); - GraphView::setYUnits(tr("km/h")); - GraphView::setXScale(M2KM); - GraphView::setYScale(MS2KMH); - GraphView::setPrecision(1); + setXLabel(tr("Distance")); + setYLabel(tr("Speed")); + setXUnits(tr("km")); + setYUnits(tr("km/h")); + setXScale(M2KM); + setYScale(MS2KMH); + setPrecision(1); } void SpeedGraph::addInfo() @@ -31,14 +31,16 @@ void SpeedGraph::loadGPX(const GPX &gpx) qreal max = 0; gpx.track(i).speedGraph(data); - if (data.isEmpty()) + if (data.count() < 2) { + skipColor(); continue; + } _avg.append(QPointF(gpx.track(i).distance(), gpx.track(i).distance() / gpx.track(i).time())); - for (int i = 0; i < data.size(); i++) - max = qMax(max, data.at(i).y()); + for (int j = 0; j < data.size(); j++) + max = qMax(max, data.at(j).y()); _max = qMax(_max, max); addInfo(); @@ -70,15 +72,15 @@ void SpeedGraph::clear() void SpeedGraph::setUnits(enum Units units) { if (units == Metric) { - GraphView::setXUnits(tr("km")); - GraphView::setYUnits(tr("km/h")); - GraphView::setXScale(M2KM); - GraphView::setYScale(MS2KMH); + setXUnits(tr("km")); + setYUnits(tr("km/h")); + setXScale(M2KM); + setYScale(MS2KMH); } else { - GraphView::setXUnits(tr("mi")); - GraphView::setYUnits(tr("mi/h")); - GraphView::setXScale(M2MI); - GraphView::setYScale(MS2MIH); + setXUnits(tr("mi")); + setYUnits(tr("mi/h")); + setXScale(M2MI); + setYScale(MS2MIH); } clearInfo(); diff --git a/src/track.cpp b/src/track.cpp index 806cea01..b798f542 100644 --- a/src/track.cpp +++ b/src/track.cpp @@ -6,6 +6,8 @@ #define WINDOW_EF 3 #define WINDOW_SE 11 #define WINDOW_SF 11 +#define WINDOW_HE 7 +#define WINDOW_HF 5 static bool lt(const QPointF &p1, const QPointF &p2) { @@ -78,6 +80,18 @@ static QVector filter(const QVector &v, int window) return ret; } +Track::Track(const QVector &data) : _data(data) +{ + _distance = 0; + + for (int i = 1; i < _data.count(); i++) + _dd.append(llDistance(_data.at(i).coordinates, + _data.at(i-1).coordinates)); + + for (int i = 0; i < _dd.size(); i++) + _distance += _dd.at(i); +} + void Track::elevationGraph(QVector &graph) const { qreal dist = 0; @@ -86,12 +100,12 @@ void Track::elevationGraph(QVector &graph) const if (!_data.size()) return; - if (isnan(_data.at(0).elevation)) + if (std::isnan(_data.at(0).elevation)) return; raw.append(QPointF(0, _data.at(0).elevation)); for (int i = 1; i < _data.size(); i++) { - dist += llDistance(_data.at(i).coordinates, _data.at(i-1).coordinates); - if (isnan(_data.at(i).elevation)) + dist += _dd.at(i-1); + if (std::isnan(_data.at(i).elevation)) return; raw.append(QPointF(dist, _data.at(i).elevation - _data.at(i).geoidheight)); @@ -110,11 +124,11 @@ void Track::speedGraph(QVector &graph) const raw.append(QPointF(0, 0)); for (int i = 1; i < _data.size(); i++) { - ds = llDistance(_data.at(i).coordinates, _data.at(i-1).coordinates); + ds = _dd.at(i-1); dt = _data.at(i-1).timestamp.msecsTo(_data.at(i).timestamp) / 1000.0; dist += ds; - if (isnan(_data.at(i).speed)) { + if (std::isnan(_data.at(i).speed)) { if (dt == 0) continue; v = ds / dt; @@ -127,22 +141,30 @@ void Track::speedGraph(QVector &graph) const graph = filter(eliminate(raw, WINDOW_SE), WINDOW_SF); } +void Track::heartRateGraph(QVector &graph) const +{ + qreal dist = 0; + QVector raw; + + if (std::isnan(_data.at(0).heartRate)) + return; + raw.append(QPointF(0, _data.at(0).heartRate)); + for (int i = 1; i < _data.count(); i++) { + if (std::isnan(_data.at(i).heartRate)) + return; + dist += _dd.at(i-1); + raw.append(QPointF(dist, _data.at(i).heartRate)); + } + + graph = filter(eliminate(raw, WINDOW_HE), WINDOW_HF); +} + void Track::track(QVector &track) const { for (int i = 0; i < _data.size(); i++) track.append(_data.at(i).coordinates); } -qreal Track::distance() const -{ - qreal dist = 0; - - for (int i = 1; i < _data.size(); i++) - dist += llDistance(_data.at(i).coordinates, _data.at(i-1).coordinates); - - return dist; -} - qreal Track::time() const { if (_data.size() < 2) diff --git a/src/track.h b/src/track.h index c1074183..401a9eeb 100644 --- a/src/track.h +++ b/src/track.h @@ -8,17 +8,20 @@ class Track { public: - Track(const QVector &data) : _data(data) {} + Track(const QVector &data); void elevationGraph(QVector &graph) const; void speedGraph(QVector &graph) const; + void heartRateGraph(QVector &graph) const; void track(QVector &track) const; - qreal distance() const; + qreal distance() const {return _distance;} qreal time() const; QDateTime date() const; private: const QVector &_data; + QVector _dd; + qreal _distance; }; #endif // TRACK_H diff --git a/src/trackpoint.h b/src/trackpoint.h index 773e3e21..05793fc3 100644 --- a/src/trackpoint.h +++ b/src/trackpoint.h @@ -12,8 +12,14 @@ struct Trackpoint qreal elevation; qreal geoidheight; qreal speed; + qreal heartRate; - Trackpoint() {elevation = NAN; geoidheight = 0; speed = NAN;} + Trackpoint() { + elevation = NAN; + geoidheight = 0; + speed = NAN; + heartRate = NAN; + } }; #endif // TRACKPOINT_H diff --git a/src/trackview.cpp b/src/trackview.cpp index 7c64b636..c51e55d1 100644 --- a/src/trackview.cpp +++ b/src/trackview.cpp @@ -34,7 +34,8 @@ TrackView::TrackView(QWidget *parent) _zoom = ZOOM_MAX; _scale = mapScale(_zoom); _map = 0; - _maxLen = 0; + _maxPath = 0; + _maxDistance = 0; } TrackView::~TrackView() @@ -61,8 +62,7 @@ void TrackView::addTrack(const QVector &track) path.lineTo(ll2mercator(QPointF(p.x(), -p.y()))); } - _maxLen = qMax(path.length(), _maxLen); - + _maxPath = qMax(path.length(), _maxPath); pi = new QGraphicsPathItem(path); _paths.append(pi); @@ -108,6 +108,7 @@ void TrackView::loadGPX(const GPX &gpx) QVector track; gpx.track(i).track(track); addTrack(track); + _maxDistance = qMax(gpx.track(i).distance(), _maxDistance); } addWaypoints(gpx.waypoints()); @@ -403,7 +404,8 @@ void TrackView::clear() _tracks.clear(); _waypoints.clear(); - _maxLen = 0; + _maxPath = 0; + _maxDistance = 0; _zoom = ZOOM_MAX; _scale = mapScale(_zoom); @@ -412,11 +414,17 @@ void TrackView::clear() void TrackView::movePositionMarker(qreal val) { + qreal mp = val / _maxDistance; + for (int i = 0; i < _paths.size(); i++) { - qreal f = _maxLen / _paths.at(i)->path().length(); - QPointF pos = _paths.at(i)->path().pointAtPercent(qMin(val * f, - 1.0)); - _markers.at(i)->setPos(pos); + qreal f = _maxPath / _paths.at(i)->path().length(); + if (mp * f > 1.0) + _markers.at(i)->setVisible(false); + else { + QPointF pos = _paths.at(i)->path().pointAtPercent(mp * f); + _markers.at(i)->setPos(pos); + _markers.at(i)->setVisible(true); + } } } diff --git a/src/trackview.h b/src/trackview.h index 7d55faf9..b22a325e 100644 --- a/src/trackview.h +++ b/src/trackview.h @@ -75,7 +75,7 @@ private: ScaleItem *_mapScale; Palette _palette; - qreal _maxLen; + qreal _maxPath, _maxDistance; qreal _scale; int _zoom;