From eb5692a0ab63cbeb27408b3514e04bc5a5c0fba9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Mon, 14 Nov 2016 22:12:43 +0100 Subject: [PATCH] Fixed path marker inaccuracy issue. --- gpxsee.pro | 3 ++- src/graph.cpp | 6 +++--- src/graph.h | 2 +- src/path.cpp | 9 +++++++++ src/path.h | 21 ++++++++++++++++++++- src/pathitem.cpp | 38 +++++++++++++++++++++++++++++++++++--- src/pathitem.h | 4 +++- src/route.h | 5 ++++- src/routeitem.cpp | 7 +++---- src/track.cpp | 2 +- src/trackitem.cpp | 9 +++++---- 11 files changed, 86 insertions(+), 20 deletions(-) create mode 100644 src/path.cpp diff --git a/gpxsee.pro b/gpxsee.pro index 9b41d85f..af3e9e1b 100644 --- a/gpxsee.pro +++ b/gpxsee.pro @@ -118,7 +118,8 @@ SOURCES += src/main.cpp \ src/graph.cpp \ src/cadencegraph.cpp \ src/powergraph.cpp \ - src/igcparser.cpp + src/igcparser.cpp \ + src/path.cpp RESOURCES += gpxsee.qrc TRANSLATIONS = lang/gpxsee_cs.ts macx { diff --git a/src/graph.cpp b/src/graph.cpp index 8b34aec4..229ae621 100644 --- a/src/graph.cpp +++ b/src/graph.cpp @@ -1,9 +1,9 @@ #include "graph.h" -QDebug operator<<(QDebug dbg, const GraphPoint &graphpoint) +QDebug operator<<(QDebug dbg, const GraphPoint &point) { - dbg.nospace() << "GraphPoint(" << graphpoint.s() << ", " - << graphpoint.t() << ", " << graphpoint.y() << ")"; + dbg.nospace() << "GraphPoint(" << point.s() << ", " << point.t() << ", " + << point.y() << ")"; return dbg.maybeSpace(); } diff --git a/src/graph.h b/src/graph.h index 76265a1d..31a9d033 100644 --- a/src/graph.h +++ b/src/graph.h @@ -29,7 +29,7 @@ private: }; Q_DECLARE_TYPEINFO(GraphPoint, Q_PRIMITIVE_TYPE); -QDebug operator<<(QDebug dbg, const GraphPoint &graphpoint); +QDebug operator<<(QDebug dbg, const GraphPoint &point); class Graph : public QVector diff --git a/src/path.cpp b/src/path.cpp new file mode 100644 index 00000000..d71d01a1 --- /dev/null +++ b/src/path.cpp @@ -0,0 +1,9 @@ +#include "path.h" + +QDebug operator<<(QDebug dbg, const PathPoint &point) +{ + dbg.nospace() << "PathPoint(" << point.distance() << ", " + << point.coordinates() << ")"; + + return dbg.maybeSpace(); +} diff --git a/src/path.h b/src/path.h index 2dd9f598..9b75b2f0 100644 --- a/src/path.h +++ b/src/path.h @@ -4,6 +4,25 @@ #include #include "coordinates.h" -typedef QVector Path; +class PathPoint +{ +public: + PathPoint() : + _coordinates(Coordinates()), _distance(NAN) {} + PathPoint(const Coordinates &coordinates, qreal distance) + : _coordinates(coordinates), _distance(distance) {} + + const Coordinates &coordinates() const {return _coordinates;} + qreal distance() const {return _distance;} + +private: + Coordinates _coordinates; + qreal _distance; +}; + +Q_DECLARE_TYPEINFO(PathPoint, Q_PRIMITIVE_TYPE); +QDebug operator<<(QDebug dbg, const PathPoint &point); + +typedef QVector Path; #endif // PATH_H diff --git a/src/pathitem.cpp b/src/pathitem.cpp index 1e62d194..87c0a7df 100644 --- a/src/pathitem.cpp +++ b/src/pathitem.cpp @@ -26,7 +26,6 @@ PathItem::PathItem(QGraphicsItem *parent) : QGraphicsObject(parent) _pen = QPen(brush, PATH_WIDTH); _units = Metric; - _distance = 0; _marker = new MarkerItem(this); @@ -72,13 +71,46 @@ void PathItem::setUnits(enum Units units) _units = units; } +QPointF PathItem::position(qreal x) const +{ + int low = 0; + int high = _distance.count() - 1; + int mid = 0; + + Q_ASSERT(high > low); + Q_ASSERT(x >= _distance.at(low) && x <= _distance.at(high)); + + while (low <= high) { + mid = low + ((high - low) / 2); + qreal val = _distance.at(mid); + if (val > x) + high = mid - 1; + else if (val < x) + low = mid + 1; + else + return _path.elementAt(mid); + } + + QLineF l; + qreal p1, p2; + if (_distance.at(mid) < x) { + l = QLineF(_path.elementAt(mid), _path.elementAt(mid+1)); + p1 = _distance.at(mid); p2 = _distance.at(mid+1); + } else { + l = QLineF(_path.elementAt(mid-1), _path.elementAt(mid)); + p1 = _distance.at(mid-1); p2 = _distance.at(mid); + } + + return l.pointAt((x - p1) / (p2 - p1)); +} + void PathItem::moveMarker(qreal distance) { - if (distance > _distance) + if (distance > _distance.last()) _marker->setVisible(false); else { _marker->setVisible(true); - _marker->setPos(_path.pointAtPercent(distance / _distance)); + _marker->setPos(position(distance)); } } diff --git a/src/pathitem.h b/src/pathitem.h index 151fe141..6f40982a 100644 --- a/src/pathitem.h +++ b/src/pathitem.h @@ -34,6 +34,7 @@ signals: protected: void updateShape(); + QVector _distance; QPainterPath _path; QPainterPath _shape; QPen _pen; @@ -41,9 +42,10 @@ protected: MarkerItem *_marker; Units _units; - qreal _distance; private: + QPointF position(qreal distance) const; + void hoverEnterEvent(QGraphicsSceneHoverEvent *event); void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); }; diff --git a/src/route.h b/src/route.h index 6befe2fb..c3b77037 100644 --- a/src/route.h +++ b/src/route.h @@ -4,13 +4,16 @@ #include #include "routedata.h" #include "graph.h" +#include "path.h" class Route { public: Route(const RouteData &data); - const RouteData &route() const {return _data;} + const RouteData &routeData() const {return _data;} + const QVector &distanceData() const {return _distance;} + Graph elevation() const; qreal distance() const; diff --git a/src/routeitem.cpp b/src/routeitem.cpp index 2502ab70..11383f8d 100644 --- a/src/routeitem.cpp +++ b/src/routeitem.cpp @@ -16,7 +16,7 @@ QString RouteItem::toolTip() if (!_desc.isEmpty()) tt.insert(qApp->translate("RouteItem", "Description"), _desc); tt.insert(qApp->translate("RouteItem", "Distance"), - Format::distance(_distance, _units)); + Format::distance(_distance.last(), _units)); return tt.toString(); } @@ -24,12 +24,13 @@ QString RouteItem::toolTip() RouteItem::RouteItem(const Route &route, QGraphicsItem *parent) : PathItem(parent) { - const RouteData &r = route.route(); + const RouteData &r = route.routeData(); Q_ASSERT(r.count() >= 2); QPointF p; _name = r.name(); _desc = r.description(); + _distance = route.distanceData(); new WaypointItem(r.at(0), this); p = r.at(0).coordinates().toMercator(); @@ -42,8 +43,6 @@ RouteItem::RouteItem(const Route &route, QGraphicsItem *parent) updateShape(); - _distance = route.distance(); - _marker->setPos(_path.pointAtPercent(0)); _pen.setStyle(Qt::DotLine); diff --git a/src/track.cpp b/src/track.cpp index ef5c00e1..f4363c2a 100644 --- a/src/track.cpp +++ b/src/track.cpp @@ -219,7 +219,7 @@ Path Track::path() const for (int i = 0; i < _data.size(); i++) if (!_outliers.contains(i)) - ret.append(_data.at(i).coordinates()); + ret.append(PathPoint(_data.at(i).coordinates(), _distance.at(i))); return ret; } diff --git a/src/trackitem.cpp b/src/trackitem.cpp index 42f0cb74..cb8c39e2 100644 --- a/src/trackitem.cpp +++ b/src/trackitem.cpp @@ -15,7 +15,7 @@ QString TrackItem::toolTip() if (!_desc.isEmpty()) tt.insert(qApp->translate("TrackItem", "Description"), _desc); tt.insert(qApp->translate("TrackItem", "Distance"), - Format::distance(_distance, _units)); + Format::distance(_distance.last(), _units)); if (_time > 0) tt.insert(qApp->translate("TrackItem", "Time"), Format::timeSpan(_time)); @@ -33,11 +33,13 @@ TrackItem::TrackItem(const Track &track, QGraphicsItem *parent) const Path &path = track.path(); Q_ASSERT(path.count() >= 2); - p = path.first().toMercator(); + p = path.first().coordinates().toMercator(); _path.moveTo(QPointF(p.x(), -p.y())); + _distance.append(path.first().distance()); for (int i = 1; i < path.size(); i++) { - p = path.at(i).toMercator(); + p = path.at(i).coordinates().toMercator(); _path.lineTo(QPointF(p.x(), -p.y())); + _distance.append(path.at(i).distance()); } updateShape(); @@ -45,7 +47,6 @@ TrackItem::TrackItem(const Track &track, QGraphicsItem *parent) _name = track.name(); _desc = track.description(); _date = track.date(); - _distance = track.distance(); _time = track.time(); _marker->setPos(_path.pointAtPercent(0));