diff --git a/src/elevationgraph.cpp b/src/elevationgraph.cpp index 06df870b..e5b3dd09 100644 --- a/src/elevationgraph.cpp +++ b/src/elevationgraph.cpp @@ -71,15 +71,15 @@ void ElevationGraph::loadGraph(const Graph &graph, Type type, PathItem *path) qreal ascent = 0, descent = 0; qreal min, max; - if (graph.y.count() < 2) { + if (graph.size() < 2) { skipColor(); return; } - max = min = graph.y.at(0); - for (int j = 1; j < graph.y.size(); j++) { - qreal cur = graph.y.at(j); - qreal prev = graph.y.at(j-1); + max = min = graph.at(0).y(); + for (int j = 1; j < graph.size(); j++) { + qreal cur = graph.at(j).y(); + qreal prev = graph.at(j-1).y(); if (cur > prev) ascent += cur - prev; diff --git a/src/elevationgraph.h b/src/elevationgraph.h index b3a75585..442ef2b1 100644 --- a/src/elevationgraph.h +++ b/src/elevationgraph.h @@ -4,7 +4,6 @@ #include "graphtab.h" class GPX; -class Graph; class PathItem; class ElevationGraph : public GraphTab diff --git a/src/graph.h b/src/graph.h index ba0205bf..3344f779 100644 --- a/src/graph.h +++ b/src/graph.h @@ -2,15 +2,30 @@ #define GRAPH_H #include +#include -class Graph +enum GraphType {Distance, Time}; + +class GraphPoint { public: - enum Type {Distance, Time}; + GraphPoint(qreal s = NAN, qreal t = NAN, qreal y = NAN) + : _s(s), _t(t), _y(y) {} - QVector distance; - QVector time; - QVector y; + qreal s() const {return _s;} + qreal t() const {return _t;} + qreal y() const {return _y;} + + void setS(qreal s) {_s = s;} + void setT(qreal t) {_t = t;} + void setY(qreal y) {_y = y;} + +private: + qreal _s; + qreal _t; + qreal _y; }; +typedef QVector Graph; + #endif // GRAPH_H diff --git a/src/graphitem.cpp b/src/graphitem.cpp index b6ddc6f5..a56b14dd 100644 --- a/src/graphitem.cpp +++ b/src/graphitem.cpp @@ -33,21 +33,30 @@ static qreal yAtX(const QPainterPath &path, qreal x) return l.pointAt((x - l.p1().x()) / (l.p2().x() - l.p1().x())).y(); } +static bool hasTime(const Graph &graph) +{ + for (int i = 0; i < graph.count(); i++) + if (std::isnan(graph.at(i).t())) + return false; + + return true; +} + GraphItem::GraphItem(const Graph &graph, QGraphicsItem *parent) : QGraphicsObject(parent) { _id = 0; _pen = QPen(QBrush(Qt::SolidPattern), 0); - _type = Graph::Distance; + _type = Distance; - _distancePath.moveTo(graph.distance.first(), -graph.y.first()); - for (int i = 1; i < graph.y.size(); i++) - _distancePath.lineTo(graph.distance.at(i), -graph.y.at(i)); + _distancePath.moveTo(graph.first().s(), -graph.first().y()); + for (int i = 1; i < graph.size(); i++) + _distancePath.lineTo(graph.at(i).s(), -graph.at(i).y()); - if (!graph.time.isEmpty()) { - _timePath.moveTo(graph.time.first(), -graph.y.first()); - for (int i = 1; i < graph.y.size(); i++) - _timePath.lineTo(graph.time.at(i), -graph.y.at(i)); + if (hasTime(graph)) { + _timePath.moveTo(graph.first().t(), -graph.first().y()); + for (int i = 1; i < graph.size(); i++) + _timePath.lineTo(graph.at(i).t(), -graph.at(i).y()); } } @@ -58,7 +67,7 @@ void GraphItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q_UNUSED(widget); painter->setPen(_pen); - painter->drawPath((_type == Graph::Distance) ? _distancePath : _timePath); + painter->drawPath((_type == Distance) ? _distancePath : _timePath); } void GraphItem::setColor(const QColor &color) @@ -69,7 +78,7 @@ void GraphItem::setColor(const QColor &color) qreal GraphItem::yAtX(qreal x) { - return ::yAtX((_type == Graph::Distance) ? _distancePath : _timePath, x); + return ::yAtX((_type == Distance) ? _distancePath : _timePath, x); } qreal GraphItem::distanceAtTime(qreal time) @@ -103,7 +112,7 @@ qreal GraphItem::distanceAtTime(qreal time) void GraphItem::emitSliderPositionChanged(qreal pos) { - if (_type == Graph::Time) { + if (_type == Time) { if (!_timePath.isEmpty()) { if (pos <= _timePath.elementAt(_timePath.elementCount() - 1).x) emit sliderPositionChanged(distanceAtTime(pos)); diff --git a/src/graphitem.h b/src/graphitem.h index fc8d1ee2..21eb59b6 100644 --- a/src/graphitem.h +++ b/src/graphitem.h @@ -13,12 +13,12 @@ public: GraphItem(const Graph &graph, QGraphicsItem *parent = 0); QRectF boundingRect() const - {return (_type == Graph::Distance) ? _distancePath.boundingRect() + {return (_type == Distance) ? _distancePath.boundingRect() : _timePath.boundingRect();} void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); - void setGraphType(Graph::Type type) {_type = type;} + void setGraphType(GraphType type) {_type = type;} int id() const {return _id;} void setId(int id) {_id = id;} void setColor(const QColor &color); @@ -36,7 +36,7 @@ private: int _id; QPen _pen; QPainterPath _distancePath, _timePath; - Graph::Type _type; + GraphType _type; }; #endif // GRAPHITEM_H diff --git a/src/graphview.cpp b/src/graphview.cpp index bb3dfed0..36035dda 100644 --- a/src/graphview.cpp +++ b/src/graphview.cpp @@ -59,7 +59,7 @@ GraphView::GraphView(QWidget *parent) _sliderPos = 0; _units = Metric; - _graphType = Graph::Distance; + _graphType = Distance; setGraphType(_graphType); setUnits(_units); @@ -105,7 +105,7 @@ void GraphView::setYUnits(const QString &units) void GraphView::setXUnits() { - if (_graphType == Graph::Distance) { + if (_graphType == Distance) { if (_units == Metric) { if (bounds().width() < KMINM) { _xUnits = tr("m"); @@ -145,7 +145,7 @@ void GraphView::setUnits(Units units) setXUnits(); } -void GraphView::setGraphType(Graph::Type type) +void GraphView::setGraphType(GraphType type) { _graphType = type; _bounds = QRectF(); @@ -155,7 +155,7 @@ void GraphView::setGraphType(Graph::Type type) updateBounds(_graphs.at(i)->boundingRect()); } - if (type == Graph::Distance) + if (type == Distance) _xLabel = tr("Distance"); else _xLabel = tr("Time"); @@ -166,7 +166,7 @@ void GraphView::setGraphType(Graph::Type type) void GraphView::loadGraph(const Graph &graph, PathItem *path, int id) { - if (graph.y.size() < 2) + if (graph.size() < 2) return; GraphItem *gi = new GraphItem(graph); diff --git a/src/graphview.h b/src/graphview.h index f1ef7192..7431fb38 100644 --- a/src/graphview.h +++ b/src/graphview.h @@ -45,7 +45,7 @@ public: void clear(); void showGraph(bool show, int id = 0); - void setGraphType(Graph::Type type); + void setGraphType(GraphType type); void setUnits(Units units); const QString &yLabel() const {return _yLabel;} @@ -113,7 +113,7 @@ private: Palette _palette; Units _units; - Graph::Type _graphType; + GraphType _graphType; }; #endif // GRAPHVIEW_H diff --git a/src/gui.cpp b/src/gui.cpp index 2d123dad..a2fdf5e8 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -1096,13 +1096,13 @@ void GUI::setImperialUnits() void GUI::setDistanceGraph() { for (int i = 0; i <_tabs.count(); i++) - _tabs.at(i)->setGraphType(Graph::Distance); + _tabs.at(i)->setGraphType(Distance); } void GUI::setTimeGraph() { for (int i = 0; i <_tabs.count(); i++) - _tabs.at(i)->setGraphType(Graph::Time); + _tabs.at(i)->setGraphType(Time); } void GUI::next() @@ -1208,7 +1208,7 @@ void GUI::writeSettings() settings.beginGroup(GRAPH_SETTINGS_GROUP); settings.setValue(SHOW_GRAPHS_SETTING, _showGraphsAction->isChecked()); settings.setValue(GRAPH_TYPE_SETTING, _timeGraphAction->isChecked() - ? Graph::Time : Graph::Distance); + ? Time : Distance); settings.endGroup(); settings.beginGroup(POI_SETTINGS_GROUP); @@ -1280,8 +1280,7 @@ void GUI::readSettings() showGraphs(false); else _showGraphsAction->setChecked(true); - if (settings.value(GRAPH_TYPE_SETTING, Graph::Distance).toInt() - == Graph::Time) { + if (settings.value(GRAPH_TYPE_SETTING, Distance).toInt() == Time) { setTimeGraph(); _timeGraphAction->setChecked(true); } else diff --git a/src/heartrategraph.cpp b/src/heartrategraph.cpp index da92ce69..41ce1fc7 100644 --- a/src/heartrategraph.cpp +++ b/src/heartrategraph.cpp @@ -30,14 +30,14 @@ void HeartRateGraph::loadGPX(const GPX &gpx, const QList &paths) const Graph &graph = gpx.tracks().at(i)->heartRate(); qreal sum = 0, w = 0; - if (graph.y.count() < 2) { + if (graph.size() < 2) { skipColor(); continue; } - for (int j = 1; j < graph.y.size(); j++) { - qreal ds = graph.distance.at(j) - graph.distance.at(j-1); - sum += graph.y.at(j) * ds; + for (int j = 1; j < graph.size(); j++) { + qreal ds = graph.at(j).s() - graph.at(j-1).s(); + sum += graph.at(j).y() * ds; w += ds; } _avg.append(QPointF(gpx.tracks().at(i)->distance(), sum/w)); diff --git a/src/route.cpp b/src/route.cpp index 80d9a6f3..f145e21d 100644 --- a/src/route.cpp +++ b/src/route.cpp @@ -5,10 +5,10 @@ Route::Route(const QVector &data) : _data(data) { qreal dist = 0; - _dd.append(dist); + _distance.append(dist); for (int i = 1; i < data.count(); i++) { dist += llDistance(data.at(i).coordinates(), data.at(i-1).coordinates()); - _dd.append(dist); + _distance.append(dist); } } @@ -18,14 +18,13 @@ Graph Route::elevation() const for (int i = 0; i < _data.size(); i++) if (_data.at(i).hasElevation()) - graph.y.append(_data.at(i).elevation() - _data.at(i).geoidHeight()); - - graph.distance = _dd; + graph.append(GraphPoint(_distance.at(i), NAN, + _data.at(i).elevation() - _data.at(i).geoidHeight())); return graph; } qreal Route::distance() const { - return (_dd.isEmpty()) ? 0 : _dd.last(); + return (_distance.isEmpty()) ? 0 : _distance.last(); } diff --git a/src/route.h b/src/route.h index 2371a421..87366893 100644 --- a/src/route.h +++ b/src/route.h @@ -15,11 +15,11 @@ public: qreal distance() const; - bool isNull() const {return (_dd.count() < 2);} + bool isNull() const {return (_data.count() < 2);} private: const QVector &_data; - QVector _dd; + QVector _distance; }; #endif // ROUTE_H diff --git a/src/speedgraph.cpp b/src/speedgraph.cpp index ea8e95e1..2b365a32 100644 --- a/src/speedgraph.cpp +++ b/src/speedgraph.cpp @@ -29,7 +29,7 @@ void SpeedGraph::loadGPX(const GPX &gpx, const QList &paths) { for (int i = 0; i < gpx.tracks().count(); i++) { const Graph &graph = gpx.tracks().at(i)->speed(); - if (graph.y.count() < 2) { + if (graph.size() < 2) { skipColor(); continue; } diff --git a/src/temperaturegraph.cpp b/src/temperaturegraph.cpp index e5435229..a54cfb32 100644 --- a/src/temperaturegraph.cpp +++ b/src/temperaturegraph.cpp @@ -32,14 +32,14 @@ void TemperatureGraph::loadGPX(const GPX &gpx, const QList &paths) const Graph &graph = gpx.tracks().at(i)->temperature(); qreal sum = 0, w = 0; - if (graph.y.count() < 2) { + if (graph.size() < 2) { skipColor(); continue; } - for (int j = 1; j < graph.y.size(); j++) { - qreal ds = graph.distance.at(j) - graph.distance.at(j-1); - sum += graph.y.at(j) * ds; + for (int j = 1; j < graph.size(); j++) { + qreal ds = graph.at(j).s() - graph.at(j-1).s(); + sum += graph.at(j).y() * ds; w += ds; } _avg.append(QPointF(gpx.tracks().at(i)->distance(), sum/w)); diff --git a/src/track.cpp b/src/track.cpp index e4da1b37..ff58c41c 100644 --- a/src/track.cpp +++ b/src/track.cpp @@ -8,39 +8,40 @@ #define WINDOW_HE 11 #define WINDOW_HF 3 -static bool lt(qreal v1, qreal v2) + +static bool lt(const GraphPoint &v1, const GraphPoint &v2) { - return v1 < v2; + return v1.y() < v2.y(); } -static qreal median(QVector v) +static qreal median(QVector v) { qSort(v.begin(), v.end(), lt); - return v.at(v.size() / 2); + return v.at(v.size() / 2).y(); } -static qreal MAD(QVector v, qreal m) +static qreal MAD(QVector v, qreal m) { for (int i = 0; i < v.size(); i++) - v[i] = (qAbs(v.at(i) - m)); + v[i].setY(qAbs(v.at(i).y() - m)); qSort(v.begin(), v.end(), lt); - return v.at(v.size() / 2); + return v.at(v.size() / 2).y(); } -static QVector eliminate(const QVector &v, int window) +static QVector eliminate(const QVector &v, int window) { QList rm; - QVector ret; + QVector ret; qreal m, M; if (v.size() < window) - return QVector(v); + return QVector(v); for (int i = window/2; i < v.size() - window/2; i++) { m = median(v.mid(i - window/2, window)); M = MAD(v.mid(i - window/2, window), m); - if (qAbs((0.6745 * (v.at(i) - m)) / M) > 3.5) + if (qAbs((0.6745 * (v.at(i).y() - m)) / M) > 3.5) rm.append(i); } @@ -55,26 +56,26 @@ static QVector eliminate(const QVector &v, int window) return ret; } -static QVector filter(const QVector &v, int window) +static QVector filter(const QVector &v, int window) { qreal acc = 0; - QVector ret; + QVector ret; if (v.size() < window) - return QVector(v); + return QVector(v); for (int i = 0; i < window; i++) - acc += v.at(i); + acc += v.at(i).y(); for (int i = 0; i <= window/2; i++) - ret.append(acc/window); + ret.append(GraphPoint(v.at(i).s(), v.at(i).t(), acc/window)); for (int i = window/2 + 1; i < v.size() - window/2; i++) { - acc += v.at(i + window/2) - v.at(i - (window/2 + 1)); - ret.append(acc/window); + acc += v.at(i + window/2).y() - v.at(i - (window/2 + 1)).y(); + ret.append(GraphPoint(v.at(i).s(), v.at(i).t(), acc/window)); } for (int i = v.size() - window/2; i < v.size(); i++) - ret.append(acc/window); + ret.append(GraphPoint(v.at(i).s(), v.at(i).t(), acc/window)); return ret; } @@ -82,112 +83,93 @@ static QVector filter(const QVector &v, int window) Track::Track(const QVector &data) : _data(data) { qreal dist = 0; - qint64 time; - _dd.append(0); - _td.append(0); + _distance.append(0); + _time.append(0); for (int i = 1; i < data.count(); i++) { dist += llDistance(data.at(i).coordinates(), data.at(i-1).coordinates()); - _dd.append(dist); - if (data.first().hasTimestamp() && data.at(i).hasTimestamp()) { - time = _data.first().timestamp().msecsTo(_data.at(i).timestamp()); - _td.append((qreal)time / 1000.0); - } - } + _distance.append(dist); - if (_dd.size() != _td.size()) - _td.clear(); + if (data.first().hasTimestamp() && data.at(i).hasTimestamp()) + _time.append(_data.first().timestamp().msecsTo( + _data.at(i).timestamp()) / 1000.0); + else + _time.append(NAN); + } } Graph Track::elevation() const { - Graph ret; - QVector raw; - + QVector raw; if (!_data.size()) - return ret; + return raw; for (int i = 0; i < _data.size(); i++) if (_data.at(i).hasElevation()) - raw.append(_data.at(i).elevation() - _data.at(i).geoidHeight()); + raw.append(GraphPoint(_distance.at(i), _time.at(i), + _data.at(i).elevation() - _data.at(i).geoidHeight())); - ret.y = filter(raw, WINDOW_EF); - ret.distance = _dd; - ret.time = _td; - - return ret; + return filter(raw, WINDOW_EF); } Graph Track::speed() const { - Graph ret; + QVector raw; qreal v, ds, dt; - QVector raw; - if (!_data.size()) - return ret; + return raw; - raw.append(0); + raw.append(GraphPoint(_distance.at(0), _time.at(0), 0)); for (int i = 1; i < _data.size(); i++) { if (_data.at(i).hasSpeed()) v = _data.at(i).speed(); - else if (_data.at(i).hasTimestamp()) { - dt = _td.at(i) - _td.at(i-1); + else if (_data.at(i).hasTimestamp() && _data.at(i-1).hasTimestamp()) { + dt = _time.at(i) - _time.at(i-1); if (!dt) continue; - ds = _dd.at(i) - _dd.at(i-1); + ds = _distance.at(i) - _distance.at(i-1); v = ds / dt; } else continue; - raw.append(v); + raw.append(GraphPoint(_distance.at(i), _time.at(i), v)); } - ret.y = filter(eliminate(raw, WINDOW_SE), WINDOW_SF); - ret.distance = _dd; - ret.time = _td; - - return ret; + return filter(eliminate(raw, WINDOW_SE), WINDOW_SF); } Graph Track::heartRate() const { - Graph ret; - QVector raw; + QVector raw; if (!_data.size()) - return ret; + return raw; for (int i = 0; i < _data.count(); i++) if (_data.at(i).hasHeartRate()) - raw.append(_data.at(i).heartRate()); + raw.append(GraphPoint(_distance.at(i), _time.at(i), + _data.at(i).heartRate())); - ret.y = filter(eliminate(raw, WINDOW_HE), WINDOW_HF); - ret.distance = _dd; - ret.time = _td; - - return ret; + return filter(eliminate(raw, WINDOW_HE), WINDOW_HF); } Graph Track::temperature() const { - Graph ret; + QVector raw; for (int i = 0; i < _data.size(); i++) if (_data.at(i).hasTemperature()) - ret.y.append(_data.at(i).temperature()); + raw.append(GraphPoint(_distance.at(i), _time.at(i), + _data.at(i).temperature())); - ret.distance = _dd; - ret.time = _td; - - return ret; + return Graph(raw); } qreal Track::distance() const { - return (_dd.isEmpty()) ? 0 : _dd.last(); + return (_distance.isEmpty()) ? 0 : _distance.last(); } qreal Track::time() const diff --git a/src/track.h b/src/track.h index d6a515ce..1b90bd9d 100644 --- a/src/track.h +++ b/src/track.h @@ -21,12 +21,12 @@ public: qreal time() const; QDateTime date() const; - bool isNull() const {return (_dd.count() < 2);} + bool isNull() const {return (_data.size() < 2);} private: const QVector &_data; - QVector _dd; - QVector _td; + QVector _distance; + QVector _time; }; #endif // TRACK_H diff --git a/src/trackview.cpp b/src/trackview.cpp index 845a6d09..d2c707a9 100644 --- a/src/trackview.cpp +++ b/src/trackview.cpp @@ -45,7 +45,6 @@ TrackView::TrackView(QWidget *parent) _showRouteWaypoints = true; _plot = false; - //_markerPos = 0; } TrackView::~TrackView() @@ -68,7 +67,6 @@ PathItem *TrackView::addTrack(const Track &track) ti->setScale(1.0/_scale); ti->setColor(_palette.color()); ti->setVisible(_showTracks); - //ti->moveMarker(_markerPos); _scene->addItem(ti); return ti; @@ -90,7 +88,6 @@ PathItem *TrackView::addRoute(const Route &route) ri->setVisible(_showRoutes); ri->showWaypoints(_showRouteWaypoints); ri->showWaypointLabels(_showWaypointLabels); - //ri->moveMarker(_markerPos); _scene->addItem(ri); return ri; @@ -490,23 +487,8 @@ void TrackView::clear() _scale = mapScale(_zoom); _scene->setSceneRect(QRectF()); - - //_markerPos = 0; } -/* -void TrackView::movePositionMarker(qreal val) -{ - _markerPos = val; - - for (int i = 0; i < _tracks.size(); i++) - _tracks.at(i)->moveMarker(val); - - for (int i = 0; i < _routes.size(); i++) - _routes.at(i)->moveMarker(val); -} -*/ - void TrackView::showTracks(bool show) { _showTracks = show; diff --git a/src/trackview.h b/src/trackview.h index 27b579e2..0ba48946 100644 --- a/src/trackview.h +++ b/src/trackview.h @@ -44,7 +44,6 @@ public: int waypointCount() const {return _waypoints.count();} public slots: - //void movePositionMarker(qreal val); void redraw(); void setPOIOverlap(bool overlap); @@ -104,7 +103,6 @@ private: bool _showRouteWaypoints; bool _plot; - //qreal _markerPos; }; #endif // TRACKVIEW_H