diff --git a/gpxsee.pro b/gpxsee.pro
index 08a5da4b..fd75bf1e 100644
--- a/gpxsee.pro
+++ b/gpxsee.pro
@@ -50,7 +50,9 @@ HEADERS += src/config.h \
src/tooltip.h \
src/route.h \
src/routeitem.h \
- src/graphitem.h
+ src/graphitem.h \
+ src/graph.h \
+ src/pathitem.h
SOURCES += src/main.cpp \
src/gui.cpp \
src/gpx.cpp \
diff --git a/gpxsee.qrc b/gpxsee.qrc
index 928d15e9..ac4aedfb 100644
--- a/gpxsee.qrc
+++ b/gpxsee.qrc
@@ -14,6 +14,7 @@
icons/arrow-left-double.png
icons/arrow-right-double.png
icons/view-fullscreen.png
+ icons/office-chart-line-stacked.png
lang/gpxsee_cs.qm
diff --git a/lang/gpxsee_cs.ts b/lang/gpxsee_cs.ts
index ccc3555d..b14809e2 100644
--- a/lang/gpxsee_cs.ts
+++ b/lang/gpxsee_cs.ts
@@ -5,54 +5,37 @@
ElevationGraph
-
- Vzdálenost
-
-
-
-
+
Výška
-
-
- km
-
-
-
-
+
m
-
+
Stoupání
-
+
Klesání
-
+
Minimum
-
-
- mi
-
-
-
-
+
ft
-
+
Maximum
@@ -163,370 +146,377 @@
GUI
-
+
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
-
+
Otevřít soubor
-
+
Otevřít POI soubor
-
+
Otevřít
-
+
Ukončit
-
-
-
+
+
+
Ovládací klávesy
-
+
Zavřít
-
+
Znovu načíst
-
+
Zobrazit
-
-
+
+
Soubor
-
-
-
+
+
+
Zdroje dat
-
+
Nahrát POI soubor
-
+
Zavřit POI soubory
-
+
Překrývat POI
-
+
Zobrazovat názvy POI
-
+
Zobrazit POI
-
+
Zobrazit mapu
-
+
Vymazat mezipaměť dlaždic
-
-
-
+
+
+
Následující mapa
-
+
Zobrazit cesty
-
+
Zobrazit trasy
-
+
Zobrazit navigační body
-
+
Názvy navigačních bodů
-
+
Zobrazovat grafy
-
+
Zobrazovat nástrojové lišty
-
+
Metrické
-
+
Imperiální
-
+
Celoobrazovkový režim
-
+
Následující
-
+
Předchozí
-
+
Poslední
-
+
První
-
+
Mapa
-
+
+
+ Graf
+
+
+
POI
-
+
POI soubory
-
+
Data
-
+
Zobrazit
-
+
Nastavení
-
+
Jednotky
-
+
Nápověda
-
+
Předchozí mapa
-
-
+
+
Datum
-
+
Trasy
-
+
Nejsou načteny žádné GPX soubory
-
+
%1 souborů
-
+
Následující soubor
-
+
Verze
-
+
Tisknout...
-
+
Exportovat do PDF...
-
+
Navigační body
-
+
Předchozí soubor
-
+
Body tras
-
+
První soubor
-
+
Poslední soubor
-
+
Modifikátor nahradit/přidat
-
+
URL mapových zdrojů (dlaždic) jsou načteny při startu programu z následujícího souboru:
-
+
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:
-
+
POI soubory, které se mají automaticky nahrát při startu programu jsou načítány z následujícího adresáře:
-
+
Soubory GPX (*.gpx);;Všechny soubory (*)
-
-
+
+
Řádka: %1
-
+
Soubory GPX (*.gpx);;Soubory CSV (*.csv);;Všechny soubory (*)
-
+
Cesty
-
-
+
+
O aplikaci GPXSee
-
+
Navigace
-
+
Mapové zdroje
-
+
POI body
-
+
+
Vzdálenost
-
+
+
Čas
-
-
+
+
Chyba
-
+
Soubor GPX nelze otevřít:
%1
-
+
Soubor POI nelze otevřít:
@@ -534,53 +524,76 @@
- HeartRateGraph
+ GraphView
-
+
+
+ m
+
+
+
+
+ km
+
+
+
+
+ ft
+
+
+
+
+ mi
+
+
+
+
+ s
+
+
+
+
+ min
+
+
+
+
+ h
+
+
+
Vzdálenost
-
+
+
+ Čas
+
+
+
+ HeartRateGraph
+
+
Tep
-
-
-
- km
-
1/min
-
+
Průměr
-
+
Maximum
-
-
-
- m
-
-
-
-
- ft
-
-
-
-
- mi
-
Misc
@@ -610,7 +623,7 @@
RouteItem
-
+
Vzdálenost
@@ -618,22 +631,22 @@
ScaleItem
-
+
mi
-
+
ft
-
+
km
-
+
m
@@ -642,52 +655,27 @@
SpeedGraph
-
- Vzdálenost
-
-
-
Rychlost
-
-
- m
-
-
-
-
-
-
-
-
-
- ft
-
-
-
+
km/h
-
+
Průměr
-
+
Maximum
-
-
- mi
-
-
-
+
mi/h
@@ -696,57 +684,32 @@
TemperatureGraph
-
- Vzdálenost
-
-
-
Teplota
-
+
Průměr
-
+
Minimum
-
+
Maximum
-
-
- m
-
-
-
-
- km
-
-
-
-
- ft
-
-
-
-
- mi
-
-
-
+
C
-
+
F
@@ -754,17 +717,17 @@
TrackItem
-
+
Vzdálenost
-
+
Čas
-
+
Datum
@@ -772,27 +735,27 @@
WaypointItem
-
+
Název
-
+
Souřadnice
-
+
Výška
-
+
Datum
-
+
Popis
diff --git a/src/elevationgraph.cpp b/src/elevationgraph.cpp
index 3facfa47..06df870b 100644
--- a/src/elevationgraph.cpp
+++ b/src/elevationgraph.cpp
@@ -45,7 +45,6 @@ ElevationGraph::ElevationGraph(QWidget *parent) : GraphTab(parent)
_units = Metric;
setYUnits();
- setXLabel(tr("Distance"));
setYLabel(tr("Elevation"));
setMinYRange(50.0);
@@ -67,20 +66,20 @@ void ElevationGraph::setInfo()
}
}
-void ElevationGraph::loadPath(const QVector &data, Type type)
+void ElevationGraph::loadGraph(const Graph &graph, Type type, PathItem *path)
{
qreal ascent = 0, descent = 0;
qreal min, max;
- if (data.count() < 2) {
+ if (graph.y.count() < 2) {
skipColor();
return;
}
- max = min = data.at(0).y();
- for (int j = 1; j < data.size(); j++) {
- qreal cur = data.at(j).y();
- qreal prev = data.at(j-1).y();
+ 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);
if (cur > prev)
ascent += cur - prev;
@@ -105,17 +104,18 @@ void ElevationGraph::loadPath(const QVector &data, Type type)
_routeMin = nMin(_routeMin, min);
}
- loadData(data, type);
+ GraphView::loadGraph(graph, path, type);
}
-void ElevationGraph::loadGPX(const GPX &gpx)
+void ElevationGraph::loadGPX(const GPX &gpx, const QList &paths)
{
- for (int i = 0; i < gpx.tracks().count(); i++)
- loadPath(gpx.tracks().at(i)->elevation(), Track);
- for (int i = 0; i < gpx.routes().count(); i++)
- loadPath(gpx.routes().at(i)->elevation(), Route);
+ int p = 0;
+
+ for (int i = 0; i < gpx.tracks().count(); i++)
+ loadGraph(gpx.tracks().at(i)->elevation(), Track, paths.at(p++));
+ for (int i = 0; i < gpx.routes().count(); i++)
+ loadGraph(gpx.routes().at(i)->elevation(), Route, paths.at(p++));
- setXUnits();
setInfo();
redraw();
@@ -135,27 +135,6 @@ void ElevationGraph::clear()
GraphView::clear();
}
-void ElevationGraph::setXUnits()
-{
- if (_units == Metric) {
- if (bounds().width() < KMINM) {
- GraphView::setXUnits(tr("m"));
- setXScale(1);
- } else {
- GraphView::setXUnits(tr("km"));
- setXScale(M2KM);
- }
- } else {
- if (bounds().width() < MIINM) {
- GraphView::setXUnits(tr("ft"));
- setXScale(M2FT);
- } else {
- GraphView::setXUnits(tr("mi"));
- setXScale(M2MI);
- }
- }
-}
-
void ElevationGraph::setYUnits()
{
if (_units == Metric) {
@@ -171,9 +150,9 @@ void ElevationGraph::setUnits(enum Units units)
{
_units = units;
- setXUnits();
setYUnits();
setInfo();
+ GraphView::setUnits(units);
redraw();
}
@@ -184,7 +163,6 @@ void ElevationGraph::showTracks(bool show)
setInfo();
showGraph(show, Track);
- setXUnits();
redraw();
}
@@ -194,7 +172,6 @@ void ElevationGraph::showRoutes(bool show)
_showRoutes = show;
showGraph(show, Route);
- setXUnits();
setInfo();
redraw();
diff --git a/src/elevationgraph.h b/src/elevationgraph.h
index b49b73b2..b3a75585 100644
--- a/src/elevationgraph.h
+++ b/src/elevationgraph.h
@@ -4,6 +4,8 @@
#include "graphtab.h"
class GPX;
+class Graph;
+class PathItem;
class ElevationGraph : public GraphTab
{
@@ -13,7 +15,7 @@ public:
ElevationGraph(QWidget *parent = 0);
QString label() const {return tr("Elevation");}
- void loadGPX(const GPX &gpx);
+ void loadGPX(const GPX &gpx, const QList &paths);
void clear();
void setUnits(enum Units units);
void showTracks(bool show);
@@ -27,11 +29,10 @@ private:
qreal ascent() const;
qreal descent() const;
- void setXUnits();
void setYUnits();
void setInfo();
- void loadPath(const QVector &data, Type type);
+ void loadGraph(const Graph &graph, Type type, PathItem *path);
qreal _trackAscent, _trackDescent;
qreal _routeAscent, _routeDescent;
diff --git a/src/graphitem.cpp b/src/graphitem.cpp
index e9c8d625..b6ddc6f5 100644
--- a/src/graphitem.cpp
+++ b/src/graphitem.cpp
@@ -1,10 +1,118 @@
-#include
-#include
+#include
#include "graphitem.h"
+
+static qreal yAtX(const QPainterPath &path, qreal x)
+{
+ int low = 0;
+ int high = path.elementCount() - 1;
+ int mid = 0;
+
+ Q_ASSERT(high > low);
+ Q_ASSERT(x >= path.elementAt(low).x && x <= path.elementAt(high).x);
+
+ while (low <= high) {
+ mid = low + ((high - low) / 2);
+ const QPainterPath::Element &e = path.elementAt(mid);
+ if (e.x > x)
+ high = mid - 1;
+ else if (e.x < x)
+ low = mid + 1;
+ else
+ return e.y;
+ }
+
+ QLineF l;
+ if (path.elementAt(mid).x < x)
+ l = QLineF(path.elementAt(mid).x, path.elementAt(mid).y,
+ path.elementAt(mid+1).x, path.elementAt(mid+1).y);
+ else
+ l = QLineF(path.elementAt(mid-1).x, path.elementAt(mid-1).y,
+ path.elementAt(mid).x, path.elementAt(mid).y);
+
+ return l.pointAt((x - l.p1().x()) / (l.p2().x() - l.p1().x())).y();
+}
+
+GraphItem::GraphItem(const Graph &graph, QGraphicsItem *parent)
+ : QGraphicsObject(parent)
+{
+ _id = 0;
+ _pen = QPen(QBrush(Qt::SolidPattern), 0);
+ _type = Graph::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));
+
+ 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));
+ }
+}
+
+void GraphItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
+ QWidget *widget)
+{
+ Q_UNUSED(option);
+ Q_UNUSED(widget);
+
+ painter->setPen(_pen);
+ painter->drawPath((_type == Graph::Distance) ? _distancePath : _timePath);
+}
+
void GraphItem::setColor(const QColor &color)
{
QBrush brush(color, Qt::SolidPattern);
- QPen pen(brush, 0);
- setPen(pen);
+ _pen.setBrush(brush);
+}
+
+qreal GraphItem::yAtX(qreal x)
+{
+ return ::yAtX((_type == Graph::Distance) ? _distancePath : _timePath, x);
+}
+
+qreal GraphItem::distanceAtTime(qreal time)
+{
+ int low = 0;
+ int high = _timePath.elementCount() - 1;
+ int mid = 0;
+
+ Q_ASSERT(high > low);
+ Q_ASSERT(time >= _timePath.elementAt(low).x
+ && time <= _timePath.elementAt(high).x);
+
+ while (low <= high) {
+ mid = low + ((high - low) / 2);
+ const QPainterPath::Element &e = _timePath.elementAt(mid);
+ if (e.x > time)
+ high = mid - 1;
+ else if (e.x < time)
+ low = mid + 1;
+ else
+ return _distancePath.elementAt(mid).x;
+ }
+
+ if (_timePath.elementAt(mid).x < time)
+ return ((_distancePath.elementAt(mid+1).x
+ + _distancePath.elementAt(mid).x) / 2.0);
+ else
+ return ((_distancePath.elementAt(mid).x
+ + _distancePath.elementAt(mid-1).x) / 2.0);
+}
+
+void GraphItem::emitSliderPositionChanged(qreal pos)
+{
+ if (_type == Graph::Time) {
+ if (!_timePath.isEmpty()) {
+ if (pos <= _timePath.elementAt(_timePath.elementCount() - 1).x)
+ emit sliderPositionChanged(distanceAtTime(pos));
+ else
+ emit sliderPositionChanged(_distancePath.elementAt(
+ _distancePath.elementCount() - 1).x + 1);
+ } else
+ emit sliderPositionChanged(_distancePath.elementAt(
+ _distancePath.elementCount() - 1).x + 1);
+ } else
+ emit sliderPositionChanged(pos);
}
diff --git a/src/graphitem.h b/src/graphitem.h
index 39447a81..fc8d1ee2 100644
--- a/src/graphitem.h
+++ b/src/graphitem.h
@@ -1,20 +1,42 @@
#ifndef GRAPHITEM_H
#define GRAPHITEM_H
-#include
+#include
+#include
+#include "graph.h"
-class GraphItem : public QGraphicsPathItem
+class GraphItem : public QGraphicsObject
{
-public:
- GraphItem(const QPainterPath &path, QGraphicsItem * parent = 0)
- : QGraphicsPathItem(path, parent) {_id = 0;}
+ Q_OBJECT
+public:
+ GraphItem(const Graph &graph, QGraphicsItem *parent = 0);
+
+ QRectF boundingRect() const
+ {return (_type == Graph::Distance) ? _distancePath.boundingRect()
+ : _timePath.boundingRect();}
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
+ QWidget *widget);
+
+ void setGraphType(Graph::Type type) {_type = type;}
int id() const {return _id;}
void setId(int id) {_id = id;}
void setColor(const QColor &color);
+ qreal yAtX(qreal x);
+ qreal distanceAtTime(qreal time);
+
+signals:
+ void sliderPositionChanged(qreal);
+
+public slots:
+ void emitSliderPositionChanged(qreal);
+
private:
int _id;
+ QPen _pen;
+ QPainterPath _distancePath, _timePath;
+ Graph::Type _type;
};
#endif // GRAPHITEM_H
diff --git a/src/graphtab.h b/src/graphtab.h
index 77a8f82d..a68c386f 100644
--- a/src/graphtab.h
+++ b/src/graphtab.h
@@ -1,10 +1,12 @@
#ifndef GRAPHTAB_H
#define GRAPHTAB_H
+#include
#include "graphview.h"
#include "units.h"
class GPX;
+class PathItem;
class GraphTab : public GraphView
{
@@ -15,7 +17,7 @@ public:
{setFrameShape(QFrame::NoFrame);}
virtual QString label() const = 0;
- virtual void loadGPX(const GPX &gpx) = 0;
+ virtual void loadGPX(const GPX &gpx, const QList &paths) = 0;
virtual void clear() = 0;
virtual void setUnits(enum Units units) = 0;
virtual void showTracks(bool show) = 0;
diff --git a/src/graphview.cpp b/src/graphview.cpp
index e2e61e5a..bb3dfed0 100644
--- a/src/graphview.cpp
+++ b/src/graphview.cpp
@@ -7,7 +7,9 @@
#include "slideritem.h"
#include "sliderinfoitem.h"
#include "infoitem.h"
+#include "graph.h"
#include "graphitem.h"
+#include "pathitem.h"
#include "graphview.h"
@@ -55,6 +57,12 @@ GraphView::GraphView(QWidget *parent)
_minYRange = 0.01;
_sliderPos = 0;
+
+ _units = Metric;
+ _graphType = Graph::Distance;
+
+ setGraphType(_graphType);
+ setUnits(_units);
}
GraphView::~GraphView()
@@ -83,55 +91,101 @@ void GraphView::createYLabel()
_yAxis->setLabel(QString("%1 [%2]").arg(_yLabel).arg(_yUnits));
}
-void GraphView::setXLabel(const QString &label)
-{
- _xLabel = label;
- createXLabel();
-}
-
void GraphView::setYLabel(const QString &label)
{
_yLabel = label;
createYLabel();
}
-void GraphView::setXUnits(const QString &units)
-{
- _xUnits = units;
- createXLabel();
-}
-
void GraphView::setYUnits(const QString &units)
{
_yUnits = units;
createYLabel();
}
-void GraphView::loadData(const QVector &data, int id)
+void GraphView::setXUnits()
{
- QPainterPath path;
- GraphItem *pi;
-
-
- if (data.size() < 2)
- return;
-
- 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());
+ if (_graphType == Graph::Distance) {
+ if (_units == Metric) {
+ if (bounds().width() < KMINM) {
+ _xUnits = tr("m");
+ _xScale = 1;
+ } else {
+ _xUnits = tr("km");
+ _xScale = M2KM;
+ }
+ } else {
+ if (bounds().width() < MIINM) {
+ _xUnits = tr("ft");
+ _xScale = M2FT;
+ } else {
+ _xUnits = tr("mi");
+ _xScale = M2MI;
+ }
+ }
+ } else {
+ if (bounds().width() < MININS) {
+ _xUnits = tr("s");
+ _xScale = 1;
+ } else if (bounds().width() < HINS) {
+ _xUnits = tr("min");
+ _xScale = MIN2S;
+ } else {
+ _xUnits = tr("h");
+ _xScale = H2S;
+ }
}
- pi = new GraphItem(path);
- pi->setId(id);
- pi->setColor(_palette.color());
+ createXLabel();
+}
- _graphs.append(pi);
+void GraphView::setUnits(Units units)
+{
+ _units = units;
+ setXUnits();
+}
+
+void GraphView::setGraphType(Graph::Type type)
+{
+ _graphType = type;
+ _bounds = QRectF();
+
+ for (int i = 0; i < _graphs.count(); i++) {
+ _graphs.at(i)->setGraphType(type);
+ updateBounds(_graphs.at(i)->boundingRect());
+ }
+
+ if (type == Graph::Distance)
+ _xLabel = tr("Distance");
+ else
+ _xLabel = tr("Time");
+ setXUnits();
+
+ redraw();
+}
+
+void GraphView::loadGraph(const Graph &graph, PathItem *path, int id)
+{
+ if (graph.y.size() < 2)
+ return;
+
+ GraphItem *gi = new GraphItem(graph);
+ gi->setGraphType(_graphType);
+ gi->setId(id);
+ gi->setColor(_palette.color());
+
+ connect(this, SIGNAL(sliderPositionChanged(qreal)), gi,
+ SLOT(emitSliderPositionChanged(qreal)));
+ connect(gi, SIGNAL(sliderPositionChanged(qreal)), path,
+ SLOT(moveMarker(qreal)));
+
+ _graphs.append(gi);
if (!_hide.contains(id)) {
- _visible.append(pi);
- _scene->addItem(pi);
- updateBounds(path);
+ _visible.append(gi);
+ _scene->addItem(gi);
+ updateBounds(gi->boundingRect());
+ setXUnits();
}
}
@@ -163,7 +217,7 @@ void GraphView::showGraph(bool show, int id)
else {
addItem(gi);
_visible.append(gi);
- updateBounds(gi->path());
+ updateBounds(gi->boundingRect());
}
}
}
@@ -173,9 +227,9 @@ void GraphView::redraw()
redraw(viewport()->size() - QSizeF(MARGIN, MARGIN));
}
-void GraphView::updateBounds(const QPainterPath &path)
+void GraphView::updateBounds(const QRectF &boundingRect)
{
- QRectF br = path.boundingRect();
+ QRectF br(boundingRect);
br.moveTopLeft(QPointF(br.left(), -br.top() - br.height()));
_bounds |= br;
}
@@ -213,8 +267,8 @@ void GraphView::redraw(const QSizeF &size)
addItem(_slider);
addItem(_info);
- rx = RangeF(_bounds.left() * _xScale, _bounds.right() * _xScale);
- ry = RangeF(_bounds.top() * _yScale + _yOffset, _bounds.bottom() * _yScale
+ rx = RangeF(bounds().left() * _xScale, bounds().right() * _xScale);
+ ry = RangeF(bounds().top() * _yScale + _yOffset, bounds().bottom() * _yScale
+ _yOffset);
if (ry.size() < _minYRange)
ry.resize(_minYRange);
@@ -299,45 +353,14 @@ void GraphView::clear()
_scene->setSceneRect(0, 0, 0, 0);
}
-static qreal yAtX(const QPainterPath &path, qreal x)
-{
- int low = 0;
- int high = path.elementCount() - 1;
- int mid = 0;
-
- Q_ASSERT(high > low);
- Q_ASSERT(x >= path.elementAt(low).x && x <= path.elementAt(high).x);
-
- while (low <= high) {
- mid = low + ((high - low) / 2);
- const QPainterPath::Element &e = path.elementAt(mid);
- if (e.x > x)
- high = mid - 1;
- else if (e.x < x)
- low = mid + 1;
- else
- return e.y;
- }
-
- QLineF l;
- if (path.elementAt(mid).x < x)
- l = QLineF(path.elementAt(mid).x, path.elementAt(mid).y,
- path.elementAt(mid+1).x, path.elementAt(mid+1).y);
- else
- l = QLineF(path.elementAt(mid-1).x, path.elementAt(mid-1).y,
- path.elementAt(mid).x, path.elementAt(mid).y);
-
- return l.pointAt((x - l.p1().x()) / (l.p2().x() - l.p1().x())).y();
-}
-
void GraphView::updateSliderPosition()
{
- if (_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());
+ if (_sliderPos <= bounds().right() && _sliderPos >= bounds().left()) {
+ _slider->setPos((_sliderPos / bounds().width())
+ * _slider->area().width(), _slider->area().bottom());
_slider->setVisible(!_visible.isEmpty());
} else {
_slider->setPos(_slider->area().left(), _slider->area().bottom());
@@ -353,16 +376,15 @@ void GraphView::updateSliderInfo()
if (!_sliderInfo->isVisible())
return;
- const QPainterPath &path = _visible.first()->path();
- QRectF br = path.boundingRect();
+ QRectF br(_visible.first()->boundingRect());
if (br.height() < _minYRange)
br.adjust(0, -(_minYRange/2 - br.height()/2), 0,
_minYRange/2 - br.height()/2);
- qreal y = yAtX(path, _sliderPos);
+ qreal y = _visible.first()->yAtX(_sliderPos);
qreal r = (y - br.bottom()) / br.height();
- qreal pos = (_sliderPos / _bounds.width()) * _slider->area().width();
+ qreal pos = (_sliderPos / bounds().width()) * _slider->area().width();
SliderInfoItem::Side s = (pos + _sliderInfo->boundingRect().width()
> _slider->area().right()) ? SliderInfoItem::Left : SliderInfoItem::Right;
@@ -377,7 +399,7 @@ void GraphView::emitSliderPositionChanged(const QPointF &pos)
if (_slider->area().width() <= 0)
return;
- _sliderPos = (pos.x() / _slider->area().width()) * _bounds.width();
+ _sliderPos = (pos.x() / _slider->area().width()) * bounds().width();
updateSliderPosition();
emit sliderPositionChanged(_sliderPos);
diff --git a/src/graphview.h b/src/graphview.h
index af22d467..f1ef7192 100644
--- a/src/graphview.h
+++ b/src/graphview.h
@@ -8,12 +8,16 @@
#include
#include
#include "palette.h"
+#include "units.h"
+#include "graph.h"
+
class AxisItem;
class SliderItem;
class SliderInfoItem;
class InfoItem;
class GraphItem;
+class PathItem;
class Scene : public QGraphicsScene
{
@@ -35,26 +39,21 @@ public:
GraphView(QWidget *parent = 0);
~GraphView();
- void loadData(const QVector &data, int id = 0);
+ void loadGraph(const Graph &graph, PathItem *path, int id = 0);
int count() const {return _graphs.count();}
void redraw();
void clear();
void showGraph(bool show, int id = 0);
+ void setGraphType(Graph::Type type);
+ void setUnits(Units units);
- const QString &xLabel() const {return _xLabel;}
const QString &yLabel() const {return _yLabel;}
- const QString &xUnits() const {return _xUnits;}
const QString &yUnits() const {return _yUnits;}
- qreal xScale() const {return _xScale;}
qreal yScale() const {return _yScale;}
qreal yOffset() const {return _yOffset;}
-
- void setXLabel(const QString &label);
void setYLabel(const QString &label);
- void setXUnits(const QString &units);
void setYUnits(const QString &units);
- void setXScale(qreal scale) {_xScale = scale;}
void setYScale(qreal scale) {_yScale = scale;}
void setYOffset(qreal offset) {_yOffset = offset;}
@@ -82,11 +81,12 @@ private slots:
void newSliderPosition(const QPointF &pos);
private:
+ void setXUnits();
void createXLabel();
void createYLabel();
void updateSliderPosition();
void updateSliderInfo();
- void updateBounds(const QPainterPath &path);
+ void updateBounds(const QRectF &boundingRect);
QRectF graphsBoundingRect() const;
void removeItem(QGraphicsItem *item);
void addItem(QGraphicsItem *item);
@@ -111,6 +111,9 @@ private:
QSet _hide;
QRectF _bounds;
Palette _palette;
+
+ Units _units;
+ Graph::Type _graphType;
};
#endif // GRAPHVIEW_H
diff --git a/src/gui.cpp b/src/gui.cpp
index a4fa9749..2d123dad 100644
--- a/src/gui.cpp
+++ b/src/gui.cpp
@@ -173,6 +173,9 @@ QAction *GUI::createPOIFileAction(int index)
void GUI::createActions()
{
+ QActionGroup *ag;
+
+
// Action Groups
_fileActionGroup = new QActionGroup(this);
_fileActionGroup->setExclusive(false);
@@ -297,18 +300,35 @@ void GUI::createActions()
connect(_showRouteWaypointsAction, SIGNAL(triggered(bool)), _track,
SLOT(showRouteWaypoints(bool)));
- // Settings actions
- _showGraphsAction = new QAction(tr("Show graphs"), this);
+ // Graph actions
+ _showGraphsAction = new QAction(QIcon(QPixmap(SHOW_GRAPHS_ICON)),
+ tr("Show graphs"), this);
_showGraphsAction->setCheckable(true);
_showGraphsAction->setShortcut(SHOW_GRAPHS_SHORTCUT);
connect(_showGraphsAction, SIGNAL(triggered(bool)), this,
SLOT(showGraphs(bool)));
addAction(_showGraphsAction);
+ ag = new QActionGroup(this);
+ ag->setExclusive(true);
+ _distanceGraphAction = new QAction(tr("Distance"), this);
+ _distanceGraphAction->setCheckable(true);
+ _distanceGraphAction->setActionGroup(ag);
+ _distanceGraphAction->setShortcut(DISTANCE_GRAPH_SHORTCUT);
+ connect(_distanceGraphAction, SIGNAL(triggered()), this,
+ SLOT(setDistanceGraph()));
+ _timeGraphAction = new QAction(tr("Time"), this);
+ _timeGraphAction->setCheckable(true);
+ _timeGraphAction->setActionGroup(ag);
+ _timeGraphAction->setShortcut(TIME_GRAPH_SHORTCUT);
+ connect(_timeGraphAction, SIGNAL(triggered()), this,
+ SLOT(setTimeGraph()));
+
+ // Settings actions
_showToolbarsAction = new QAction(tr("Show toolbars"), this);
_showToolbarsAction->setCheckable(true);
connect(_showToolbarsAction, SIGNAL(triggered(bool)), this,
SLOT(showToolbars(bool)));
- QActionGroup *ag = new QActionGroup(this);
+ ag = new QActionGroup(this);
ag->setExclusive(true);
_metricUnitsAction = new QAction(tr("Metric"), this);
_metricUnitsAction->setCheckable(true);
@@ -368,6 +388,12 @@ void GUI::createMenus()
mapMenu->addSeparator();
mapMenu->addAction(_showMapAction);
+ QMenu *graphMenu = menuBar()->addMenu(tr("Graph"));
+ graphMenu->addAction(_distanceGraphAction);
+ graphMenu->addAction(_timeGraphAction);
+ graphMenu->addSeparator();
+ graphMenu->addAction(_showGraphsAction);
+
QMenu *poiMenu = menuBar()->addMenu(tr("POI"));
_poiFilesMenu = poiMenu->addMenu(tr("POI files"));
_poiFilesMenu->addActions(_poiFilesActions);
@@ -395,7 +421,6 @@ void GUI::createMenus()
unitsMenu->addAction(_imperialUnitsAction);
settingsMenu->addSeparator();
settingsMenu->addAction(_showToolbarsAction);
- settingsMenu->addAction(_showGraphsAction);
settingsMenu->addSeparator();
settingsMenu->addAction(_fullscreenAction);
@@ -421,6 +446,7 @@ void GUI::createToolBars()
_showToolBar = addToolBar(tr("Show"));
_showToolBar->addAction(_showPOIAction);
_showToolBar->addAction(_showMapAction);
+ _showToolBar->addAction(_showGraphsAction);
_navigationToolBar = addToolBar(tr("Navigation"));
_navigationToolBar->addAction(_firstAction);
@@ -586,13 +612,14 @@ bool GUI::openFile(const QString &fileName)
bool GUI::loadFile(const QString &fileName)
{
GPX gpx;
+ QList paths;
if (gpx.loadFile(fileName)) {
+ paths = _track->loadGPX(gpx);
for (int i = 0; i < _tabs.count(); i++)
- _tabs.at(i)->loadGPX(gpx);
+ _tabs.at(i)->loadGPX(gpx, paths);
updateGraphTabs();
_track->setHidden(false);
- _track->loadGPX(gpx);
if (_showPOIAction->isChecked())
_track->loadPOI(_poi);
@@ -986,7 +1013,7 @@ void GUI::poiFileChecked(int index)
void GUI::sliderPositionChanged(qreal pos)
{
_sliderPos = pos;
- _track->movePositionMarker(_sliderPos);
+ //_track->movePositionMarker(_sliderPos);
}
void GUI::graphChanged(int index)
@@ -1066,6 +1093,18 @@ void GUI::setImperialUnits()
updateStatusBarInfo();
}
+void GUI::setDistanceGraph()
+{
+ for (int i = 0; i <_tabs.count(); i++)
+ _tabs.at(i)->setGraphType(Graph::Distance);
+}
+
+void GUI::setTimeGraph()
+{
+ for (int i = 0; i <_tabs.count(); i++)
+ _tabs.at(i)->setGraphType(Graph::Time);
+}
+
void GUI::next()
{
QString file = _browser->next();
@@ -1158,7 +1197,6 @@ void GUI::writeSettings()
settings.setValue(UNITS_SETTING, _imperialUnitsAction->isChecked()
? Imperial : Metric);
settings.setValue(SHOW_TOOLBARS_SETTING, _showToolbarsAction->isChecked());
- settings.setValue(SHOW_GRAPHS_SETTING, _showGraphsAction->isChecked());
settings.endGroup();
settings.beginGroup(MAP_SETTINGS_GROUP);
@@ -1167,6 +1205,12 @@ void GUI::writeSettings()
settings.setValue(SHOW_MAP_SETTING, _showMapAction->isChecked());
settings.endGroup();
+ settings.beginGroup(GRAPH_SETTINGS_GROUP);
+ settings.setValue(SHOW_GRAPHS_SETTING, _showGraphsAction->isChecked());
+ settings.setValue(GRAPH_TYPE_SETTING, _timeGraphAction->isChecked()
+ ? Graph::Time : Graph::Distance);
+ settings.endGroup();
+
settings.beginGroup(POI_SETTINGS_GROUP);
settings.setValue(SHOW_POI_SETTING, _showPOIAction->isChecked());
settings.setValue(OVERLAP_POI_SETTING, _overlapPOIAction->isChecked());
@@ -1216,10 +1260,6 @@ void GUI::readSettings()
showToolbars(false);
else
_showToolbarsAction->setChecked(true);
- if (settings.value(SHOW_GRAPHS_SETTING, true).toBool() == false)
- showGraphs(false);
- else
- _showGraphsAction->setChecked(true);
settings.endGroup();
settings.beginGroup(MAP_SETTINGS_GROUP);
@@ -1235,6 +1275,19 @@ void GUI::readSettings()
_currentMap = 0;
settings.endGroup();
+ settings.beginGroup(GRAPH_SETTINGS_GROUP);
+ if (settings.value(SHOW_GRAPHS_SETTING, true).toBool() == false)
+ showGraphs(false);
+ else
+ _showGraphsAction->setChecked(true);
+ if (settings.value(GRAPH_TYPE_SETTING, Graph::Distance).toInt()
+ == Graph::Time) {
+ setTimeGraph();
+ _timeGraphAction->setChecked(true);
+ } else
+ _distanceGraphAction->setChecked(true);
+ settings.endGroup();
+
settings.beginGroup(POI_SETTINGS_GROUP);
if (settings.value(OVERLAP_POI_SETTING, true).toBool() == false)
_track->setPOIOverlap(false);
diff --git a/src/gui.h b/src/gui.h
index cd5c8f1c..4c7d20eb 100644
--- a/src/gui.h
+++ b/src/gui.h
@@ -58,8 +58,6 @@ private slots:
void graphChanged(int);
void poiFileChecked(int);
-
-
void next();
void prev();
void last();
@@ -67,6 +65,8 @@ private slots:
void setMetricUnits();
void setImperialUnits();
+ void setDistanceGraph();
+ void setTimeGraph();
void sliderPositionChanged(qreal pos);
@@ -132,6 +132,8 @@ private:
QAction *_fullscreenAction;
QAction *_clearMapCacheAction;
QAction *_showGraphsAction;
+ QAction *_distanceGraphAction;
+ QAction *_timeGraphAction;
QAction *_showToolbarsAction;
QAction *_nextAction;
QAction *_prevAction;
diff --git a/src/heartrategraph.cpp b/src/heartrategraph.cpp
index 2e83cf39..da92ce69 100644
--- a/src/heartrategraph.cpp
+++ b/src/heartrategraph.cpp
@@ -8,7 +8,6 @@ HeartRateGraph::HeartRateGraph(QWidget *parent) : GraphTab(parent)
_showTracks = true;
GraphView::setYUnits(tr("1/min"));
- setXLabel(tr("Distance"));
setYLabel(tr("Heart rate"));
setSliderPrecision(0);
@@ -25,30 +24,30 @@ void HeartRateGraph::setInfo()
clearInfo();
}
-void HeartRateGraph::loadGPX(const GPX &gpx)
+void HeartRateGraph::loadGPX(const GPX &gpx, const QList &paths)
{
for (int i = 0; i < gpx.tracks().count(); i++) {
- QVector data = gpx.tracks().at(i)->heartRate();
+ const Graph &graph = gpx.tracks().at(i)->heartRate();
qreal sum = 0, w = 0;
- if (data.count() < 2) {
+ if (graph.y.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();
+ 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;
+ w += ds;
}
_avg.append(QPointF(gpx.tracks().at(i)->distance(), sum/w));
- loadData(data);
+ GraphView::loadGraph(graph, paths.at(i));
}
for (int i = 0; i < gpx.routes().count(); i++)
skipColor();
- setXUnits();
setInfo();
redraw();
@@ -74,43 +73,11 @@ void HeartRateGraph::clear()
GraphView::clear();
}
-void HeartRateGraph::setXUnits()
-{
- if (_units == Metric) {
- if (bounds().width() < KMINM) {
- GraphView::setXUnits(tr("m"));
- setXScale(1);
- } else {
- GraphView::setXUnits(tr("km"));
- setXScale(M2KM);
- }
- } else {
- if (bounds().width() < MIINM) {
- GraphView::setXUnits(tr("ft"));
- setXScale(M2FT);
- } else {
- GraphView::setXUnits(tr("mi"));
- setXScale(M2MI);
- }
- }
-}
-
-void HeartRateGraph::setUnits(enum Units units)
-{
- _units = units;
-
- setXUnits();
- setInfo();
-
- redraw();
-}
-
void HeartRateGraph::showTracks(bool show)
{
_showTracks = show;
showGraph(show);
- setXUnits();
setInfo();
redraw();
diff --git a/src/heartrategraph.h b/src/heartrategraph.h
index b193677e..c70fb2a9 100644
--- a/src/heartrategraph.h
+++ b/src/heartrategraph.h
@@ -13,16 +13,15 @@ public:
HeartRateGraph(QWidget *parent = 0);
QString label() const {return tr("Heart rate");}
- void loadGPX(const GPX &gpx);
+ void loadGPX(const GPX &gpx, const QList &paths);
void clear();
- void setUnits(enum Units units);
+ void setUnits(enum Units) {}
void showTracks(bool show);
void showRoutes(bool show) {Q_UNUSED(show);}
private:
qreal avg() const;
qreal max() const {return bounds().bottom();}
- void setXUnits();
void setInfo();
QList _avg;
diff --git a/src/icons.h b/src/icons.h
index 0cf2ae06..705b4770 100644
--- a/src/icons.h
+++ b/src/icons.h
@@ -8,6 +8,7 @@
#define CLOSE_FILE_ICON ":/icons/dialog-close.png"
#define SHOW_POI_ICON ":/icons/flag.png"
#define SHOW_MAP_ICON ":/icons/applications-internet.png"
+#define SHOW_GRAPHS_ICON ":/icons/office-chart-line-stacked.png"
#define QUIT_ICON ":/icons/application-exit.png"
#define RELOAD_FILE_ICON ":/icons/view-refresh.png"
#define NEXT_FILE_ICON ":/icons/arrow-right.png"
diff --git a/src/keys.h b/src/keys.h
index 42b81c60..99b4503e 100644
--- a/src/keys.h
+++ b/src/keys.h
@@ -4,26 +4,28 @@
#include
#include
-#define NEXT_KEY Qt::Key_Space
-#define PREV_KEY Qt::Key_Backspace
-#define FIRST_KEY Qt::Key_Home
-#define LAST_KEY Qt::Key_End
-#define MODIFIER Qt::ShiftModifier
+#define NEXT_KEY Qt::Key_Space
+#define PREV_KEY Qt::Key_Backspace
+#define FIRST_KEY Qt::Key_Home
+#define LAST_KEY Qt::Key_End
+#define MODIFIER Qt::ShiftModifier
-#define QUIT_SHORTCUT QKeySequence::Quit
-#define OPEN_SHORTCUT QKeySequence::Open
-#define CLOSE_SHORTCUT QKeySequence::Close
-#define RELOAD_SHORTCUT QKeySequence::Refresh
-#define EXPORT_SHORTCUT QKeySequence(Qt::CTRL + Qt::Key_E)
-#define SHOW_POI_SHORTCUT QKeySequence(Qt::CTRL + Qt::Key_P)
-#define SHOW_MAP_SHORTCUT QKeySequence(Qt::CTRL + Qt::Key_M)
-#define NEXT_MAP_SHORTCUT QKeySequence::Forward
-#define PREV_MAP_SHORTCUT QKeySequence::Back
-#define SHOW_GRAPHS_SHORTCUT QKeySequence(Qt::CTRL + Qt::Key_G)
+#define QUIT_SHORTCUT QKeySequence::Quit
+#define OPEN_SHORTCUT QKeySequence::Open
+#define CLOSE_SHORTCUT QKeySequence::Close
+#define RELOAD_SHORTCUT QKeySequence::Refresh
+#define EXPORT_SHORTCUT QKeySequence(Qt::CTRL + Qt::Key_E)
+#define SHOW_POI_SHORTCUT QKeySequence(Qt::CTRL + Qt::Key_P)
+#define SHOW_MAP_SHORTCUT QKeySequence(Qt::CTRL + Qt::Key_M)
+#define NEXT_MAP_SHORTCUT QKeySequence::Forward
+#define PREV_MAP_SHORTCUT QKeySequence::Back
+#define SHOW_GRAPHS_SHORTCUT QKeySequence(Qt::CTRL + Qt::Key_G)
+#define DISTANCE_GRAPH_SHORTCUT QKeySequence(Qt::CTRL + Qt::Key_D)
+#define TIME_GRAPH_SHORTCUT QKeySequence(Qt::CTRL + Qt::Key_T)
#ifdef Q_OS_MAC
-#define FULLSCREEN_SHORTCUT QKeySequence(Qt::META + Qt::CTRL + Qt::Key_F)
+#define FULLSCREEN_SHORTCUT QKeySequence(Qt::META + Qt::CTRL + Qt::Key_F)
#else // Q_OS_MAC
-#define FULLSCREEN_SHORTCUT QKeySequence(Qt::Key_F11)
+#define FULLSCREEN_SHORTCUT QKeySequence(Qt::Key_F11)
#endif // Q_OS_MAC
#endif // KEYS_H
diff --git a/src/pathitem.h b/src/pathitem.h
index adb9b867..de883bfd 100644
--- a/src/pathitem.h
+++ b/src/pathitem.h
@@ -1,4 +1,19 @@
#ifndef PATHITEM_H
#define PATHITEM_H
+#include
+#include "units.h"
+
+class PathItem : public QGraphicsObject
+{
+ Q_OBJECT
+
+public:
+ PathItem(QGraphicsItem *parent = 0) : QGraphicsObject(parent) {}
+ virtual void showMarker(bool show) = 0;
+
+public slots:
+ virtual void moveMarker(qreal distance) = 0;
+};
+
#endif // PATHITEM_H
diff --git a/src/route.cpp b/src/route.cpp
index 9f0bfcf0..80d9a6f3 100644
--- a/src/route.cpp
+++ b/src/route.cpp
@@ -12,14 +12,15 @@ Route::Route(const QVector &data) : _data(data)
}
}
-QVector Route::elevation() const
+Graph Route::elevation() const
{
- QVector graph;
+ Graph graph;
for (int i = 0; i < _data.size(); i++)
if (_data.at(i).hasElevation())
- graph.append(QPointF(_dd.at(i), _data.at(i).elevation()
- - _data.at(i).geoidHeight()));
+ graph.y.append(_data.at(i).elevation() - _data.at(i).geoidHeight());
+
+ graph.distance = _dd;
return graph;
}
diff --git a/src/route.h b/src/route.h
index 60a654d7..2371a421 100644
--- a/src/route.h
+++ b/src/route.h
@@ -3,6 +3,7 @@
#include
#include "waypoint.h"
+#include "graph.h"
class Route
{
@@ -10,7 +11,7 @@ public:
Route(const QVector &data);
const QVector &route() const {return _data;}
- QVector elevation() const;
+ Graph elevation() const;
qreal distance() const;
diff --git a/src/routeitem.cpp b/src/routeitem.cpp
index 931628ed..87df61a8 100644
--- a/src/routeitem.cpp
+++ b/src/routeitem.cpp
@@ -34,7 +34,7 @@ void RouteItem::updateShape()
}
RouteItem::RouteItem(const Route &route, QGraphicsItem *parent)
- : QGraphicsItem(parent)
+ : PathItem(parent)
{
WaypointItem *wi;
diff --git a/src/routeitem.h b/src/routeitem.h
index e2be4d62..e987b8de 100644
--- a/src/routeitem.h
+++ b/src/routeitem.h
@@ -1,14 +1,17 @@
#ifndef ROUTEITEM_H
#define ROUTEITEM_H
-#include
+#include
+#include "pathitem.h"
#include "markeritem.h"
#include "route.h"
#include "units.h"
-class RouteItem : public QGraphicsItem
+class RouteItem : public PathItem
{
+ Q_OBJECT
+
public:
RouteItem(const Route &route, QGraphicsItem *parent = 0);
diff --git a/src/settings.h b/src/settings.h
index 3b34238e..2b89035f 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -8,7 +8,10 @@
#define SETTINGS_SETTINGS_GROUP "Settings"
#define UNITS_SETTING "units"
#define SHOW_TOOLBARS_SETTING "toolbar"
-#define SHOW_GRAPHS_SETTING "graphs"
+
+#define GRAPH_SETTINGS_GROUP "Graph"
+#define SHOW_GRAPHS_SETTING "show"
+#define GRAPH_TYPE_SETTING "type"
#define MAP_SETTINGS_GROUP "Map"
#define CURRENT_MAP_SETTING "map"
diff --git a/src/slideritem.cpp b/src/slideritem.cpp
index bfb18b8e..6d4fc9f4 100644
--- a/src/slideritem.cpp
+++ b/src/slideritem.cpp
@@ -4,7 +4,7 @@
#define SIZE 10
-SliderItem::SliderItem(QGraphicsObject *parent) : QGraphicsObject(parent)
+SliderItem::SliderItem(QGraphicsItem *parent) : QGraphicsObject(parent)
{
setFlag(ItemIsMovable);
setFlag(ItemSendsGeometryChanges);
diff --git a/src/slideritem.h b/src/slideritem.h
index 39a45d49..ab490a99 100644
--- a/src/slideritem.h
+++ b/src/slideritem.h
@@ -1,14 +1,14 @@
#ifndef SLIDERITEM_H
#define SLIDERITEM_H
-#include
+#include
class SliderItem : public QGraphicsObject
{
Q_OBJECT
public:
- SliderItem(QGraphicsObject *parent = 0);
+ SliderItem(QGraphicsItem *parent = 0);
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
diff --git a/src/speedgraph.cpp b/src/speedgraph.cpp
index f792ce75..ea8e95e1 100644
--- a/src/speedgraph.cpp
+++ b/src/speedgraph.cpp
@@ -9,7 +9,6 @@ SpeedGraph::SpeedGraph(QWidget *parent) : GraphTab(parent)
_showTracks = true;
setYUnits();
- setXLabel(tr("Distance"));
setYLabel(tr("Speed"));
setSliderPrecision(1);
@@ -26,11 +25,11 @@ void SpeedGraph::setInfo()
clearInfo();
}
-void SpeedGraph::loadGPX(const GPX &gpx)
+void SpeedGraph::loadGPX(const GPX &gpx, const QList &paths)
{
for (int i = 0; i < gpx.tracks().count(); i++) {
- QVector data = gpx.tracks().at(i)->speed();
- if (data.count() < 2) {
+ const Graph &graph = gpx.tracks().at(i)->speed();
+ if (graph.y.count() < 2) {
skipColor();
continue;
}
@@ -38,13 +37,12 @@ void SpeedGraph::loadGPX(const GPX &gpx)
_avg.append(QPointF(gpx.tracks().at(i)->distance(),
gpx.tracks().at(i)->distance() / gpx.tracks().at(i)->time()));
- loadData(data);
+ GraphView::loadGraph(graph, paths.at(i));
}
for (int i = 0; i < gpx.routes().count(); i++)
skipColor();
- setXUnits();
setInfo();
redraw();
@@ -70,27 +68,6 @@ void SpeedGraph::clear()
GraphView::clear();
}
-void SpeedGraph::setXUnits()
-{
- if (_units == Metric) {
- if (bounds().width() < KMINM) {
- GraphView::setXUnits(tr("m"));
- setXScale(1);
- } else {
- GraphView::setXUnits(tr("km"));
- setXScale(M2KM);
- }
- } else {
- if (bounds().width() < MIINM) {
- GraphView::setXUnits(tr("ft"));
- setXScale(M2FT);
- } else {
- GraphView::setXUnits(tr("mi"));
- setXScale(M2MI);
- }
- }
-}
-
void SpeedGraph::setYUnits()
{
if (_units == Metric) {
@@ -106,9 +83,9 @@ void SpeedGraph::setUnits(enum Units units)
{
_units = units;
- setXUnits();
setYUnits();
setInfo();
+ GraphView::setUnits(units);
redraw();
}
@@ -118,7 +95,6 @@ void SpeedGraph::showTracks(bool show)
_showTracks = show;
showGraph(show);
- setXUnits();
setInfo();
redraw();
diff --git a/src/speedgraph.h b/src/speedgraph.h
index b483e7dc..e5c50831 100644
--- a/src/speedgraph.h
+++ b/src/speedgraph.h
@@ -14,7 +14,7 @@ public:
SpeedGraph(QWidget *parent = 0);
QString label() const {return tr("Speed");}
- void loadGPX(const GPX &gpx);
+ void loadGPX(const GPX &gpx, const QList &paths);
void clear();
void setUnits(enum Units units);
void showTracks(bool show);
@@ -23,7 +23,6 @@ public:
private:
qreal avg() const;
qreal max() const {return bounds().bottom();}
- void setXUnits();
void setYUnits();
void setInfo();
diff --git a/src/temperaturegraph.cpp b/src/temperaturegraph.cpp
index 174e0d88..e5435229 100644
--- a/src/temperaturegraph.cpp
+++ b/src/temperaturegraph.cpp
@@ -8,7 +8,6 @@ TemperatureGraph::TemperatureGraph(QWidget *parent) : GraphTab(parent)
_showTracks = true;
setYUnits();
- setXLabel(tr("Distance"));
setYLabel(tr("Temperature"));
setSliderPrecision(1);
@@ -27,30 +26,30 @@ void TemperatureGraph::setInfo()
clearInfo();
}
-void TemperatureGraph::loadGPX(const GPX &gpx)
+void TemperatureGraph::loadGPX(const GPX &gpx, const QList &paths)
{
for (int i = 0; i < gpx.tracks().count(); i++) {
- QVector data = gpx.tracks().at(i)->temperature();
+ const Graph &graph = gpx.tracks().at(i)->temperature();
qreal sum = 0, w = 0;
- if (data.count() < 2) {
+ if (graph.y.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();
+ 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;
+ w += ds;
}
_avg.append(QPointF(gpx.tracks().at(i)->distance(), sum/w));
- loadData(data);
+ GraphView::loadGraph(graph, paths.at(i));
}
for (int i = 0; i < gpx.routes().count(); i++)
skipColor();
- setXUnits();
setInfo();
redraw();
@@ -76,27 +75,6 @@ void TemperatureGraph::clear()
GraphView::clear();
}
-void TemperatureGraph::setXUnits()
-{
- if (_units == Metric) {
- if (bounds().width() < KMINM) {
- GraphView::setXUnits(tr("m"));
- setXScale(1);
- } else {
- GraphView::setXUnits(tr("km"));
- setXScale(M2KM);
- }
- } else {
- if (bounds().width() < MIINM) {
- GraphView::setXUnits(tr("ft"));
- setXScale(M2FT);
- } else {
- GraphView::setXUnits(tr("mi"));
- setXScale(M2MI);
- }
- }
-}
-
void TemperatureGraph::setYUnits()
{
if (_units == Metric) {
@@ -114,9 +92,9 @@ void TemperatureGraph::setUnits(enum Units units)
{
_units = units;
- setXUnits();
setYUnits();
setInfo();
+ GraphView::setUnits(units);
redraw();
}
@@ -126,7 +104,6 @@ void TemperatureGraph::showTracks(bool show)
_showTracks = show;
showGraph(show);
- setXUnits();
setInfo();
redraw();
diff --git a/src/temperaturegraph.h b/src/temperaturegraph.h
index 27a61891..4960f724 100644
--- a/src/temperaturegraph.h
+++ b/src/temperaturegraph.h
@@ -13,7 +13,7 @@ public:
TemperatureGraph(QWidget *parent = 0);
QString label() const {return tr("Temperature");}
- void loadGPX(const GPX &gpx);
+ void loadGPX(const GPX &gpx, const QList &paths);
void clear();
void setUnits(enum Units units);
void showTracks(bool show);
@@ -23,7 +23,6 @@ private:
qreal avg() const;
qreal min() const {return bounds().top();}
qreal max() const {return bounds().bottom();}
- void setXUnits();
void setYUnits();
void setInfo();
diff --git a/src/track.cpp b/src/track.cpp
index 04834246..e4da1b37 100644
--- a/src/track.cpp
+++ b/src/track.cpp
@@ -8,39 +8,39 @@
#define WINDOW_HE 11
#define WINDOW_HF 3
-static bool lt(const QPointF &p1, const QPointF &p2)
+static bool lt(qreal v1, qreal v2)
{
- return p1.y() < p2.y();
+ return v1 < v2;
}
-static qreal median(QVector v)
+static qreal median(QVector v)
{
qSort(v.begin(), v.end(), lt);
- return v.at(v.size() / 2).y();
+ return v.at(v.size() / 2);
}
-static qreal MAD(QVector v, qreal m)
+static qreal MAD(QVector v, qreal m)
{
for (int i = 0; i < v.size(); i++)
- v[i].setY(qAbs(v.at(i).y() - m));
+ v[i] = (qAbs(v.at(i) - m));
qSort(v.begin(), v.end(), lt);
- return v.at(v.size() / 2).y();
+ return v.at(v.size() / 2);
}
-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).y() - m)) / M) > 3.5)
+ if (qAbs((0.6745 * (v.at(i) - m)) / M) > 3.5)
rm.append(i);
}
@@ -55,26 +55,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).y();
+ acc += v.at(i);
for (int i = 0; i <= window/2; i++)
- ret.append(QPointF(v.at(i).x(), acc/window));
+ ret.append(acc/window);
for (int i = window/2 + 1; i < v.size() - window/2; i++) {
- acc += v.at(i + window/2).y() - v.at(i - (window/2 + 1)).y();
- ret.append(QPointF(v.at(i).x(), acc/window));
+ acc += v.at(i + window/2) - v.at(i - (window/2 + 1));
+ ret.append(acc/window);
}
for (int i = v.size() - window/2; i < v.size(); i++)
- ret.append(QPointF(v.at(i).x(), acc/window));
+ ret.append(acc/window);
return ret;
}
@@ -82,80 +82,107 @@ static QVector filter(const QVector &v, int window)
Track::Track(const QVector &data) : _data(data)
{
qreal dist = 0;
+ qint64 time;
- _dd.append(dist);
+ _dd.append(0);
+ _td.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);
+ }
}
+
+ if (_dd.size() != _td.size())
+ _td.clear();
}
-QVector Track::elevation() const
+Graph Track::elevation() const
{
- QVector raw;
+ Graph ret;
+ QVector raw;
+
if (!_data.size())
- return raw;
+ return ret;
for (int i = 0; i < _data.size(); i++)
if (_data.at(i).hasElevation())
- raw.append(QPointF(_dd.at(i), _data.at(i).elevation()
- - _data.at(i).geoidHeight()));
+ raw.append(_data.at(i).elevation() - _data.at(i).geoidHeight());
- return filter(raw, WINDOW_EF);
+ ret.y = filter(raw, WINDOW_EF);
+ ret.distance = _dd;
+ ret.time = _td;
+
+ return ret;
}
-QVector Track::speed() const
+Graph Track::speed() const
{
- qreal v, ds;
- qint64 dt;
- QVector raw;
+ Graph ret;
+ qreal v, ds, dt;
+ QVector raw;
+
if (!_data.size())
- return raw;
+ return ret;
- raw.append(QPointF(0, 0));
+ raw.append(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 = _data.at(i-1).timestamp().msecsTo(_data.at(i).timestamp());
+ dt = _td.at(i) - _td.at(i-1);
if (!dt)
continue;
ds = _dd.at(i) - _dd.at(i-1);
- v = ds / ((qreal)dt / 1000.0);
+ v = ds / dt;
} else
continue;
- raw.append(QPointF(_dd.at(i), v));
+ raw.append(v);
}
- return filter(eliminate(raw, WINDOW_SE), WINDOW_SF);
+ ret.y = filter(eliminate(raw, WINDOW_SE), WINDOW_SF);
+ ret.distance = _dd;
+ ret.time = _td;
+
+ return ret;
}
-QVector Track::heartRate() const
+Graph Track::heartRate() const
{
- QVector raw;
+ Graph ret;
+ QVector raw;
if (!_data.size())
- return raw;
+ return ret;
for (int i = 0; i < _data.count(); i++)
if (_data.at(i).hasHeartRate())
- raw.append(QPointF(_dd.at(i), _data.at(i).heartRate()));
+ raw.append(_data.at(i).heartRate());
- return filter(eliminate(raw, WINDOW_HE), WINDOW_HF);
+ ret.y = filter(eliminate(raw, WINDOW_HE), WINDOW_HF);
+ ret.distance = _dd;
+ ret.time = _td;
+
+ return ret;
}
-QVector Track::temperature() const
+Graph Track::temperature() const
{
- QVector graph;
+ Graph ret;
for (int i = 0; i < _data.size(); i++)
if (_data.at(i).hasTemperature())
- graph.append(QPointF(_dd.at(i), _data.at(i).temperature()));
+ ret.y.append(_data.at(i).temperature());
- return graph;
+ ret.distance = _dd;
+ ret.time = _td;
+
+ return ret;
}
qreal Track::distance() const
diff --git a/src/track.h b/src/track.h
index a2c03683..d6a515ce 100644
--- a/src/track.h
+++ b/src/track.h
@@ -4,6 +4,7 @@
#include
#include
#include "trackpoint.h"
+#include "graph.h"
class Track
{
@@ -11,10 +12,10 @@ public:
Track(const QVector &data);
const QVector &track() const {return _data;}
- QVector elevation() const;
- QVector speed() const;
- QVector heartRate() const;
- QVector temperature() const;
+ Graph elevation() const;
+ Graph speed() const;
+ Graph heartRate() const;
+ Graph temperature() const;
qreal distance() const;
qreal time() const;
@@ -25,6 +26,7 @@ public:
private:
const QVector &_data;
QVector _dd;
+ QVector _td;
};
#endif // TRACK_H
diff --git a/src/trackitem.cpp b/src/trackitem.cpp
index 69166bc2..13f53997 100644
--- a/src/trackitem.cpp
+++ b/src/trackitem.cpp
@@ -38,7 +38,7 @@ void TrackItem::updateShape()
}
TrackItem::TrackItem(const Track &track, QGraphicsItem *parent)
- : QGraphicsItem(parent)
+ : PathItem(parent)
{
const QVector &t = track.track();
Q_ASSERT(t.count() >= 2);
diff --git a/src/trackitem.h b/src/trackitem.h
index 8483070b..11e694fd 100644
--- a/src/trackitem.h
+++ b/src/trackitem.h
@@ -1,15 +1,18 @@
#ifndef TRACKITEM_H
#define TRACKITEM_H
-#include
#include
+#include
+#include "pathitem.h"
#include "units.h"
#include "track.h"
#include "markeritem.h"
-class TrackItem : public QGraphicsItem
+class TrackItem : public PathItem
{
+ Q_OBJECT
+
public:
TrackItem(const Track &track, QGraphicsItem *parent = 0);
diff --git a/src/trackview.cpp b/src/trackview.cpp
index c6d06c8b..845a6d09 100644
--- a/src/trackview.cpp
+++ b/src/trackview.cpp
@@ -45,7 +45,7 @@ TrackView::TrackView(QWidget *parent)
_showRouteWaypoints = true;
_plot = false;
- _markerPos = 0;
+ //_markerPos = 0;
}
TrackView::~TrackView()
@@ -54,11 +54,11 @@ TrackView::~TrackView()
delete _mapScale;
}
-void TrackView::addTrack(const Track &track)
+PathItem *TrackView::addTrack(const Track &track)
{
if (track.isNull()) {
_palette.color();
- return;
+ return 0;
}
TrackItem *ti = new TrackItem(track);
@@ -68,15 +68,17 @@ void TrackView::addTrack(const Track &track)
ti->setScale(1.0/_scale);
ti->setColor(_palette.color());
ti->setVisible(_showTracks);
- ti->moveMarker(_markerPos);
+ //ti->moveMarker(_markerPos);
_scene->addItem(ti);
+
+ return ti;
}
-void TrackView::addRoute(const Route &route)
+PathItem *TrackView::addRoute(const Route &route)
{
if (route.isNull()) {
_palette.color();
- return;
+ return 0;
}
RouteItem *ri = new RouteItem(route);
@@ -88,8 +90,10 @@ void TrackView::addRoute(const Route &route)
ri->setVisible(_showRoutes);
ri->showWaypoints(_showRouteWaypoints);
ri->showWaypointLabels(_showWaypointLabels);
- ri->moveMarker(_markerPos);
+ //ri->moveMarker(_markerPos);
_scene->addItem(ri);
+
+ return ri;
}
void TrackView::addWaypoints(const QList &waypoints)
@@ -111,18 +115,25 @@ void TrackView::addWaypoints(const QList &waypoints)
_scale = mapScale(_zoom);
}
-void TrackView::loadGPX(const GPX &gpx)
+QList TrackView::loadGPX(const GPX &gpx)
{
+ QList paths;
+ PathItem *pi;
+
int zoom = _zoom;
- for (int i = 0; i < gpx.tracks().count(); i++)
- addTrack(*(gpx.tracks().at(i)));
- for (int i = 0; i < gpx.routes().count(); i++)
- addRoute(*(gpx.routes().at(i)));
+ for (int i = 0; i < gpx.tracks().count(); i++) {
+ if ((pi = addTrack(*(gpx.tracks().at(i)))))
+ paths.append(pi);
+ }
+ for (int i = 0; i < gpx.routes().count(); i++) {
+ if ((pi = addRoute(*(gpx.routes().at(i)))))
+ paths.append(pi);
+ }
addWaypoints(gpx.waypoints());
if (_tracks.empty() && _routes.empty() && _waypoints.empty())
- return;
+ return paths;
if ((_tracks.size() > 1 && _zoom < zoom)
|| (_routes.size() > 1 && _zoom < zoom)
@@ -138,6 +149,8 @@ void TrackView::loadGPX(const GPX &gpx)
_mapScale->setZoom(_zoom, -(br.center().ry() * _scale));
if (_mapScale->scene() != _scene)
_scene->addItem(_mapScale);
+
+ return paths;
}
QRectF TrackView::trackBoundingRect() const
@@ -478,9 +491,10 @@ void TrackView::clear()
_scene->setSceneRect(QRectF());
- _markerPos = 0;
+ //_markerPos = 0;
}
+/*
void TrackView::movePositionMarker(qreal val)
{
_markerPos = val;
@@ -491,6 +505,7 @@ void TrackView::movePositionMarker(qreal val)
for (int i = 0; i < _routes.size(); i++)
_routes.at(i)->moveMarker(val);
}
+*/
void TrackView::showTracks(bool show)
{
diff --git a/src/trackview.h b/src/trackview.h
index 13794e7a..27b579e2 100644
--- a/src/trackview.h
+++ b/src/trackview.h
@@ -18,6 +18,7 @@ class TrackItem;
class RouteItem;
class WaypointItem;
class ScaleItem;
+class PathItem;
class TrackView : public QGraphicsView
{
@@ -27,7 +28,7 @@ public:
TrackView(QWidget *parent = 0);
~TrackView();
- void loadGPX(const GPX &gpx);
+ QList loadGPX(const GPX &gpx);
void loadPOI(const POI &poi);
void clearPOI();
@@ -43,7 +44,7 @@ public:
int waypointCount() const {return _waypoints.count();}
public slots:
- void movePositionMarker(qreal val);
+ //void movePositionMarker(qreal val);
void redraw();
void setPOIOverlap(bool overlap);
@@ -55,8 +56,8 @@ public slots:
void showRouteWaypoints(bool show);
private:
- void addTrack(const Track &track);
- void addRoute(const Route &route);
+ PathItem *addTrack(const Track &track);
+ PathItem *addRoute(const Route &route);
void addWaypoints(const QList &waypoints);
void addPOI(const QVector &waypoints);
@@ -103,7 +104,7 @@ private:
bool _showRouteWaypoints;
bool _plot;
- qreal _markerPos;
+ //qreal _markerPos;
};
#endif // TRACKVIEW_H
diff --git a/src/units.h b/src/units.h
index cf53388b..734c661e 100644
--- a/src/units.h
+++ b/src/units.h
@@ -13,10 +13,14 @@ enum Units {
#define MS2MIH 2.236936290000 // m/s -> mi/h
#define FT2MI 0.000189393939 // ft -> mi
#define MM2IN 0.039370100000 // mm -> in
+#define H2S 0.000277777778 // h -> s
+#define MIN2S 0.016666666667 // min -> s
#define KMINM 1000 // 1 km in m
#define MIINFT 5280 // 1 mi in ft
-#define MIINM 1609.344 // 1mi in m
+#define MIINM 1609.344 // 1 mi in m
+#define MININS 60 // 1 min in s
+#define HINS 3600 // 1 hins
#define C2FS 1.8 // Celsius to Farenheit - scale
#define C2FO 32 // Celsius to Farenheit - offset