1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-30 22:51:16 +01:00

Added cadence and power graphs

This commit is contained in:
Martin Tůma 2016-11-06 03:28:08 +01:00
parent aac9bf024b
commit 8a90a736d2
15 changed files with 469 additions and 184 deletions

View File

@ -66,7 +66,9 @@ HEADERS += src/config.h \
src/fitparser.h \
src/format.h \
src/path.h \
src/assert.h
src/assert.h \
src/cadencegraph.h \
src/powergraph.h
SOURCES += src/main.cpp \
src/gui.cpp \
src/poi.cpp \
@ -112,7 +114,9 @@ SOURCES += src/main.cpp \
src/kmlparser.cpp \
src/fitparser.cpp \
src/format.cpp \
src/graph.cpp
src/graph.cpp \
src/cadencegraph.cpp \
src/powergraph.cpp
RESOURCES += gpxsee.qrc
TRANSLATIONS = lang/gpxsee_cs.ts
macx {

View File

@ -1,6 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="cs_CZ">
<context>
<name>CadenceGraph</name>
<message>
<location filename="../src/cadencegraph.cpp" line="10"/>
<source>1/min</source>
<translation>1/min</translation>
</message>
<message>
<location filename="../src/cadencegraph.cpp" line="11"/>
<location filename="../src/cadencegraph.h" line="13"/>
<source>Cadence</source>
<translation>Kadence</translation>
</message>
<message>
<location filename="../src/cadencegraph.cpp" line="19"/>
<source>Average</source>
<translation>Průměr</translation>
</message>
<message>
<location filename="../src/cadencegraph.cpp" line="21"/>
<source>Maximum</source>
<translation>Maximum</translation>
</message>
</context>
<context>
<name>ElevationGraph</name>
<message>
@ -166,280 +190,280 @@
<context>
<name>GUI</name>
<message>
<location filename="../src/gui.cpp" line="546"/>
<location filename="../src/gui.cpp" line="550"/>
<source>GPXSee is distributed under the terms of the GNU General Public License version 3. For more info about GPXSee visit the project homepage at </source>
<translation>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 </translation>
</message>
<message>
<location filename="../src/gui.cpp" line="610"/>
<location filename="../src/gui.cpp" line="614"/>
<source>Open file</source>
<translation>Otevřít soubor</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="691"/>
<location filename="../src/gui.cpp" line="695"/>
<source>Open POI file</source>
<translation>Otevřít POI soubor</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="223"/>
<location filename="../src/gui.cpp" line="225"/>
<source>Open</source>
<translation>Otevřít</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="207"/>
<location filename="../src/gui.cpp" line="209"/>
<source>Quit</source>
<translation>Ukončit</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="215"/>
<location filename="../src/gui.cpp" line="562"/>
<location filename="../src/gui.cpp" line="563"/>
<location filename="../src/gui.cpp" line="217"/>
<location filename="../src/gui.cpp" line="566"/>
<location filename="../src/gui.cpp" line="567"/>
<source>Keyboard controls</source>
<translation>Ovládací klávesy</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="239"/>
<location filename="../src/gui.cpp" line="241"/>
<source>Close</source>
<translation>Zavřít</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="245"/>
<location filename="../src/gui.cpp" line="247"/>
<source>Reload</source>
<translation>Znovu načíst</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="474"/>
<location filename="../src/gui.cpp" line="476"/>
<source>Show</source>
<translation>Zobrazit</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="396"/>
<location filename="../src/gui.cpp" line="468"/>
<location filename="../src/gui.cpp" line="398"/>
<location filename="../src/gui.cpp" line="470"/>
<source>File</source>
<translation>Soubor</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="109"/>
<location filename="../src/gui.cpp" line="111"/>
<source>Supported files (*.csv *.fit *.gpx *.kml *.tcx)</source>
<translation>Podporované soubory (*.csv *.fit *.gpx *.kml *.tcx)</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="110"/>
<location filename="../src/gui.cpp" line="112"/>
<source>FIT files (*.fit)</source>
<translation>Soubory FIT (*.fit)</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="213"/>
<location filename="../src/gui.cpp" line="585"/>
<location filename="../src/gui.cpp" line="586"/>
<location filename="../src/gui.cpp" line="215"/>
<location filename="../src/gui.cpp" line="589"/>
<location filename="../src/gui.cpp" line="590"/>
<source>Data sources</source>
<translation>Zdroje dat</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="253"/>
<location filename="../src/gui.cpp" line="255"/>
<source>Load POI file</source>
<translation>Nahrát POI soubor</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="256"/>
<location filename="../src/gui.cpp" line="258"/>
<source>Close POI files</source>
<translation>Zavřit POI soubory</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="258"/>
<location filename="../src/gui.cpp" line="260"/>
<source>Overlap POIs</source>
<translation>Překrývat POI</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="262"/>
<location filename="../src/gui.cpp" line="264"/>
<source>Show POI labels</source>
<translation>Zobrazovat názvy POI</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="267"/>
<location filename="../src/gui.cpp" line="269"/>
<source>Show POIs</source>
<translation>Zobrazit POI</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="276"/>
<location filename="../src/gui.cpp" line="278"/>
<source>Show map</source>
<translation>Zobrazit mapu</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="282"/>
<location filename="../src/gui.cpp" line="284"/>
<source>Clear tile cache</source>
<translation>Vymazat mezipaměť dlaždic</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="291"/>
<location filename="../src/gui.cpp" line="295"/>
<location filename="../src/gui.cpp" line="572"/>
<location filename="../src/gui.cpp" line="293"/>
<location filename="../src/gui.cpp" line="297"/>
<location filename="../src/gui.cpp" line="576"/>
<source>Next map</source>
<translation>Následující mapa</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="302"/>
<location filename="../src/gui.cpp" line="304"/>
<source>Show tracks</source>
<translation>Zobrazit cesty</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="306"/>
<location filename="../src/gui.cpp" line="308"/>
<source>Show routes</source>
<translation>Zobrazit trasy</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="310"/>
<location filename="../src/gui.cpp" line="312"/>
<source>Show waypoints</source>
<translation>Zobrazit navigační body</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="314"/>
<location filename="../src/gui.cpp" line="316"/>
<source>Waypoint labels</source>
<translation>Názvy navigačních bodů</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="325"/>
<location filename="../src/gui.cpp" line="327"/>
<source>Show graphs</source>
<translation>Zobrazovat grafy</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="347"/>
<location filename="../src/gui.cpp" line="349"/>
<source>Show grid</source>
<translation>Zobrazit mřížku</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="353"/>
<location filename="../src/gui.cpp" line="355"/>
<source>Show toolbars</source>
<translation>Zobrazovat nástrojové lišty</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="359"/>
<location filename="../src/gui.cpp" line="361"/>
<source>Metric</source>
<translation>Metrické</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="364"/>
<location filename="../src/gui.cpp" line="366"/>
<source>Imperial</source>
<translation>Imperiální</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="370"/>
<location filename="../src/gui.cpp" line="372"/>
<source>Fullscreen mode</source>
<translation>Celoobrazovkový režim</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="378"/>
<location filename="../src/gui.cpp" line="380"/>
<source>Next</source>
<translation>Následující</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="381"/>
<location filename="../src/gui.cpp" line="383"/>
<source>Previous</source>
<translation>Předchozí</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="385"/>
<location filename="../src/gui.cpp" line="387"/>
<source>Last</source>
<translation>Poslední</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="388"/>
<location filename="../src/gui.cpp" line="390"/>
<source>First</source>
<translation>První</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="410"/>
<location filename="../src/gui.cpp" line="412"/>
<source>Map</source>
<translation>Mapa</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="417"/>
<location filename="../src/gui.cpp" line="419"/>
<source>Graph</source>
<translation>Graf</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="425"/>
<location filename="../src/gui.cpp" line="427"/>
<source>POI</source>
<translation>POI</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="426"/>
<location filename="../src/gui.cpp" line="428"/>
<source>POI files</source>
<translation>POI soubory</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="437"/>
<location filename="../src/gui.cpp" line="439"/>
<source>Data</source>
<translation>Data</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="438"/>
<location filename="../src/gui.cpp" line="440"/>
<source>Display</source>
<translation>Zobrazit</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="446"/>
<location filename="../src/gui.cpp" line="448"/>
<source>Settings</source>
<translation>Nastavení</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="447"/>
<location filename="../src/gui.cpp" line="449"/>
<source>Units</source>
<translation>Jednotky</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="455"/>
<location filename="../src/gui.cpp" line="457"/>
<source>Help</source>
<translation>Nápověda</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="574"/>
<location filename="../src/gui.cpp" line="578"/>
<source>Previous map</source>
<translation>Předchozí mapa</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="111"/>
<location filename="../src/gui.cpp" line="113"/>
<source>GPX files (*.gpx)</source>
<translation>Soubory GPX (*.gpx)</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="112"/>
<location filename="../src/gui.cpp" line="114"/>
<source>TCX files (*.tcx)</source>
<translation>Soubory TCX (*.tcx)</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="111"/>
<location filename="../src/gui.cpp" line="113"/>
<source>KML files (*.kml)</source>
<translation>Soubory KML (*.kml)</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="110"/>
<location filename="../src/gui.cpp" line="112"/>
<source>CSV files (*.csv)</source>
<translation>Soubory CSV (*.csv)</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="112"/>
<location filename="../src/gui.cpp" line="114"/>
<source>All files (*)</source>
<translation>Všechny soubory (*)</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="777"/>
<location filename="../src/gui.cpp" line="780"/>
<location filename="../src/gui.cpp" line="781"/>
<location filename="../src/gui.cpp" line="784"/>
<source>Date</source>
<translation>Datum</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="789"/>
<location filename="../src/gui.cpp" line="793"/>
<source>Routes</source>
<translation>Trasy</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="977"/>
<location filename="../src/gui.cpp" line="981"/>
<source>No GPX files loaded</source>
<translation>Nejsou načteny žádné GPX soubory</translation>
</message>
<message numerus="yes">
<location filename="../src/gui.cpp" line="981"/>
<location filename="../src/gui.cpp" line="985"/>
<source>%n files</source>
<translation>
<numerusform>%n soubor</numerusform>
@ -448,121 +472,121 @@
</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="565"/>
<location filename="../src/gui.cpp" line="569"/>
<source>Next file</source>
<translation>Následující soubor</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="542"/>
<location filename="../src/gui.cpp" line="546"/>
<source>Version </source>
<translation>Verze </translation>
</message>
<message>
<location filename="../src/gui.cpp" line="228"/>
<location filename="../src/gui.cpp" line="230"/>
<source>Print...</source>
<translation>Tisknout...</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="233"/>
<location filename="../src/gui.cpp" line="235"/>
<source>Export to PDF...</source>
<translation>Exportovat do PDF...</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="791"/>
<location filename="../src/gui.cpp" line="795"/>
<source>Waypoints</source>
<translation>Navigační body</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="566"/>
<location filename="../src/gui.cpp" line="570"/>
<source>Previous file</source>
<translation>Předchozí soubor</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="318"/>
<location filename="../src/gui.cpp" line="320"/>
<source>Route waypoints</source>
<translation>Body tras</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="568"/>
<location filename="../src/gui.cpp" line="572"/>
<source>First file</source>
<translation>První soubor</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="569"/>
<location filename="../src/gui.cpp" line="573"/>
<source>Last file</source>
<translation>Poslední soubor</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="570"/>
<location filename="../src/gui.cpp" line="574"/>
<source>Append modifier</source>
<translation>Modifikátor nahradit/přidat</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="589"/>
<location filename="../src/gui.cpp" line="593"/>
<source>Map (tiles) source URLs are read on program startup from the following file:</source>
<translation>URL mapových zdrojů (dlaždic) jsou načteny při startu programu z následujícího souboru:</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="592"/>
<location filename="../src/gui.cpp" line="596"/>
<source>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:</source>
<translation>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:</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="600"/>
<location filename="../src/gui.cpp" line="604"/>
<source>To make GPXSee load a POI file automatically on startup, add the file to the following directory:</source>
<translation>POI soubory, které se mají automaticky nahrát při startu programu jsou načítány z následujícího adresáře:</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="680"/>
<location filename="../src/gui.cpp" line="684"/>
<source>Error loading data file:</source>
<translation>Datový soubor nelze načíst:</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="683"/>
<location filename="../src/gui.cpp" line="708"/>
<location filename="../src/gui.cpp" line="687"/>
<location filename="../src/gui.cpp" line="712"/>
<source>Line: %1</source>
<translation>Řádka: %1</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="705"/>
<location filename="../src/gui.cpp" line="709"/>
<source>Error loading POI file:</source>
<translation>Soubor POI nelze načíst:</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="787"/>
<location filename="../src/gui.cpp" line="791"/>
<source>Tracks</source>
<translation>Cesty</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="218"/>
<location filename="../src/gui.cpp" line="540"/>
<location filename="../src/gui.cpp" line="220"/>
<location filename="../src/gui.cpp" line="544"/>
<source>About GPXSee</source>
<translation>O aplikaci GPXSee</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="479"/>
<location filename="../src/gui.cpp" line="481"/>
<source>Navigation</source>
<translation>Navigace</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="588"/>
<location filename="../src/gui.cpp" line="592"/>
<source>Map sources</source>
<translation>Mapové zdroje</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="599"/>
<location filename="../src/gui.cpp" line="603"/>
<source>POIs</source>
<translation>POI body</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="333"/>
<location filename="../src/gui.cpp" line="794"/>
<location filename="../src/gui.cpp" line="335"/>
<location filename="../src/gui.cpp" line="798"/>
<source>Distance</source>
<translation>Vzdálenost</translation>
</message>
<message>
<location filename="../src/gui.cpp" line="340"/>
<location filename="../src/gui.cpp" line="796"/>
<location filename="../src/gui.cpp" line="342"/>
<location filename="../src/gui.cpp" line="800"/>
<source>Time</source>
<translation>Čas</translation>
</message>
@ -640,6 +664,30 @@
<translation>Maximum</translation>
</message>
</context>
<context>
<name>PowerGraph</name>
<message>
<location filename="../src/powergraph.cpp" line="10"/>
<source>W</source>
<translation>W</translation>
</message>
<message>
<location filename="../src/powergraph.cpp" line="11"/>
<location filename="../src/powergraph.h" line="13"/>
<source>Power</source>
<translation>Výkon</translation>
</message>
<message>
<location filename="../src/powergraph.cpp" line="19"/>
<source>Average</source>
<translation>Průměr</translation>
</message>
<message>
<location filename="../src/powergraph.cpp" line="21"/>
<source>Maximum</source>
<translation>Maximum</translation>
</message>
</context>
<context>
<name>RouteItem</name>
<message>

84
src/cadencegraph.cpp Normal file
View File

@ -0,0 +1,84 @@
#include "data.h"
#include "cadencegraph.h"
CadenceGraph::CadenceGraph(QWidget *parent) : GraphTab(parent)
{
_units = Metric;
_showTracks = true;
GraphView::setYUnits(tr("1/min"));
setYLabel(tr("Cadence"));
setSliderPrecision(1);
}
void CadenceGraph::setInfo()
{
if (_showTracks) {
GraphView::addInfo(tr("Average"), QString::number(avg() * yScale()
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale()
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
} else
clearInfo();
}
void CadenceGraph::loadData(const Data &data, const QList<PathItem *> &paths)
{
for (int i = 0; i < data.tracks().count(); i++) {
const Graph &graph = data.tracks().at(i)->cadence();
qreal sum = 0, w = 0;
if (graph.size() < 2) {
skipColor();
continue;
}
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(data.tracks().at(i)->distance(), sum/w));
GraphView::loadGraph(graph, paths.at(i));
}
for (int i = 0; i < data.routes().count(); i++)
skipColor();
setInfo();
redraw();
}
qreal CadenceGraph::avg() const
{
qreal sum = 0, w = 0;
QList<QPointF>::const_iterator it;
for (it = _avg.begin(); it != _avg.end(); it++) {
sum += it->y() * it->x();
w += it->x();
}
return (sum / w);
}
void CadenceGraph::clear()
{
_avg.clear();
GraphView::clear();
}
void CadenceGraph::showTracks(bool show)
{
_showTracks = show;
showGraph(show);
setInfo();
redraw();
}

31
src/cadencegraph.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef CADENCEGRAPH_H
#define CADENCEGRAPH_H
#include "graphtab.h"
class CadenceGraph : public GraphTab
{
Q_OBJECT
public:
CadenceGraph(QWidget *parent = 0);
QString label() const {return tr("Cadence");}
void loadData(const Data &data, const QList<PathItem *> &paths);
void clear();
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 setInfo();
QList<QPointF> _avg;
enum Units _units;
bool _showTracks;
};
#endif // CADENCEGRAPH_H

View File

@ -230,10 +230,18 @@ bool FITParser::parseData(MessageDefinition *def, quint8 offset)
if (val != 0xff)
trackpoint.setHeartRate(val);
break;
case 4:
if (val != 0xff)
trackpoint.setCadence(val);
break;
case 6:
if (val != 0xffff)
trackpoint.setSpeed(val / 1000.0f);
break;
case 7:
if (val != 0xffff)
trackpoint.setPower(val);
break;
case 13:
if (val != 0x7f)
trackpoint.setTemperature((qint8)val);

View File

@ -51,56 +51,13 @@ Coordinates GPXParser::coordinates()
return Coordinates(lon, lat);
}
void GPXParser::handleTrackpointData(DataType type, Trackpoint &trackpoint)
{
switch (type) {
case Elevation:
trackpoint.setElevation(number());
break;
case Time:
trackpoint.setTimestamp(time());
break;
case Speed:
trackpoint.setSpeed(number());
break;
case HeartRate:
trackpoint.setHeartRate(number());
break;
case Temperature:
trackpoint.setTemperature(number());
break;
default:
break;
}
}
void GPXParser::handleWaypointData(DataType type, Waypoint &waypoint)
{
switch (type) {
case Name:
waypoint.setName(_reader.readElementText());
break;
case Description:
waypoint.setDescription(_reader.readElementText());
break;
case Time:
waypoint.setTimestamp(time());
break;
case Elevation:
waypoint.setElevation(number());
break;
default:
break;
}
}
void GPXParser::tpExtension(Trackpoint &trackpoint)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "hr")
handleTrackpointData(HeartRate, trackpoint);
trackpoint.setHeartRate(number());
else if (_reader.name() == "atemp")
handleTrackpointData(Temperature, trackpoint);
trackpoint.setTemperature(number());
else
_reader.skipCurrentElement();
}
@ -110,11 +67,15 @@ void GPXParser::extensions(Trackpoint &trackpoint)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "speed")
handleTrackpointData(Speed, trackpoint);
trackpoint.setSpeed(number());
else if (_reader.name() == "hr" || _reader.name() == "heartrate")
handleTrackpointData(HeartRate, trackpoint);
trackpoint.setHeartRate(number());
else if (_reader.name() == "temp")
handleTrackpointData(Temperature, trackpoint);
trackpoint.setTemperature(number());
else if (_reader.name() == "cadence")
trackpoint.setCadence(number());
else if (_reader.name() == "power")
trackpoint.setPower(number());
else if (_reader.name() == "TrackPointExtension")
tpExtension(trackpoint);
else
@ -128,9 +89,9 @@ void GPXParser::trackpointData(Trackpoint &trackpoint)
while (_reader.readNextStartElement()) {
if (_reader.name() == "ele")
handleTrackpointData(Elevation, trackpoint);
trackpoint.setElevation(number());
else if (_reader.name() == "time")
handleTrackpointData(Time, trackpoint);
trackpoint.setTimestamp(time());
else if (_reader.name() == "geoidheight")
gh = number();
else if (_reader.name() == "extensions")
@ -149,15 +110,15 @@ void GPXParser::waypointData(Waypoint &waypoint)
while (_reader.readNextStartElement()) {
if (_reader.name() == "name")
handleWaypointData(Name, waypoint);
waypoint.setName(_reader.readElementText());
else if (_reader.name() == "desc")
handleWaypointData(Description, waypoint);
waypoint.setDescription(_reader.readElementText());
else if (_reader.name() == "ele")
handleWaypointData(Elevation, waypoint);
waypoint.setElevation(number());
else if (_reader.name() == "geoidheight")
gh = number();
else if (_reader.name() == "time")
handleWaypointData(Time, waypoint);
waypoint.setTimestamp(time());
else
_reader.skipCurrentElement();
}

View File

@ -17,10 +17,6 @@ public:
int errorLine() const {return _reader.lineNumber();}
private:
enum DataType {
Name, Description, Elevation, Time, Speed, HeartRate, Temperature
};
bool parse();
void gpx();
void track(TrackData &track);
@ -34,9 +30,6 @@ private:
QDateTime time();
Coordinates coordinates();
void handleWaypointData(DataType type, Waypoint &waypoint);
void handleTrackpointData(DataType type, Trackpoint &trackpoint);
QXmlStreamReader _reader;
};

View File

@ -33,6 +33,8 @@
#include "speedgraph.h"
#include "heartrategraph.h"
#include "temperaturegraph.h"
#include "cadencegraph.h"
#include "powergraph.h"
#include "pathview.h"
#include "trackinfo.h"
#include "filebrowser.h"
@ -512,6 +514,8 @@ void GUI::createGraphTabs()
_tabs.append(new ElevationGraph);
_tabs.append(new SpeedGraph);
_tabs.append(new HeartRateGraph);
_tabs.append(new CadenceGraph);
_tabs.append(new PowerGraph);
_tabs.append(new TemperatureGraph);
for (int i = 0; i < _tabs.count(); i++)

84
src/powergraph.cpp Normal file
View File

@ -0,0 +1,84 @@
#include "data.h"
#include "powergraph.h"
PowerGraph::PowerGraph(QWidget *parent) : GraphTab(parent)
{
_units = Metric;
_showTracks = true;
GraphView::setYUnits(tr("W"));
setYLabel(tr("Power"));
setSliderPrecision(1);
}
void PowerGraph::setInfo()
{
if (_showTracks) {
GraphView::addInfo(tr("Average"), QString::number(avg() * yScale()
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale()
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
} else
clearInfo();
}
void PowerGraph::loadData(const Data &data, const QList<PathItem *> &paths)
{
for (int i = 0; i < data.tracks().count(); i++) {
const Graph &graph = data.tracks().at(i)->power();
qreal sum = 0, w = 0;
if (graph.size() < 2) {
skipColor();
continue;
}
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(data.tracks().at(i)->distance(), sum/w));
GraphView::loadGraph(graph, paths.at(i));
}
for (int i = 0; i < data.routes().count(); i++)
skipColor();
setInfo();
redraw();
}
qreal PowerGraph::avg() const
{
qreal sum = 0, w = 0;
QList<QPointF>::const_iterator it;
for (it = _avg.begin(); it != _avg.end(); it++) {
sum += it->y() * it->x();
w += it->x();
}
return (sum / w);
}
void PowerGraph::clear()
{
_avg.clear();
GraphView::clear();
}
void PowerGraph::showTracks(bool show)
{
_showTracks = show;
showGraph(show);
setInfo();
redraw();
}

31
src/powergraph.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef POWERGRAPH_H
#define POWERGRAPH_H
#include "graphtab.h"
class PowerGraph : public GraphTab
{
Q_OBJECT
public:
PowerGraph(QWidget *parent = 0);
QString label() const {return tr("Power");}
void loadData(const Data &data, const QList<PathItem *> &paths);
void clear();
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 setInfo();
QList<QPointF> _avg;
enum Units _units;
bool _showTracks;
};
#endif // POWERGRAPH_H

View File

@ -56,6 +56,18 @@ Coordinates TCXParser::position()
return pos;
}
void TCXParser::extensions(Trackpoint &trackpoint)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == "RunCadence")
trackpoint.setCadence(number());
else if (_reader.name() == "Watts")
trackpoint.setPower(number());
else
_reader.skipCurrentElement();
}
}
void TCXParser::trackpointData(Trackpoint &trackpoint)
{
while (_reader.readNextStartElement()) {
@ -67,6 +79,10 @@ void TCXParser::trackpointData(Trackpoint &trackpoint)
trackpoint.setTimestamp(time());
else if (_reader.name() == "HeartRateBpm")
trackpoint.setHeartRate(number());
else if (_reader.name() == "Cadence")
trackpoint.setCadence(number());
else if (_reader.name() == "Extensions")
extensions(trackpoint);
else
_reader.skipCurrentElement();
}

View File

@ -27,6 +27,7 @@ private:
void trackpoints(TrackData &track);
void trackpointData(Trackpoint &trackpoint);
void waypointData(Waypoint &waypoint);
void extensions(Trackpoint &trackpoint);
Coordinates position();
qreal number();
QDateTime time();

View File

@ -6,6 +6,8 @@
#define WINDOW_EF 3
#define WINDOW_SF 7
#define WINDOW_HF 3
#define WINDOW_CF 3
#define WINDOW_PF 3
static qreal median(QVector<qreal> v)
@ -114,14 +116,10 @@ Graph Track::elevation() const
if (!_data.size())
return raw;
for (int i = 0; i < _data.size(); i++) {
if (_outliers.contains(i))
continue;
if (_data.at(i).hasElevation())
for (int i = 0; i < _data.size(); i++)
if (_data.at(i).hasElevation() && !_outliers.contains(i))
raw.append(GraphPoint(_distance.at(i), _time.at(i),
_data.at(i).elevation()));
}
return filter(raw, WINDOW_EF);
}
@ -135,12 +133,9 @@ Graph Track::speed() const
return raw;
for (int i = 0; i < _data.size(); i++) {
if (_outliers.contains(i))
continue;
if (_data.at(i).hasSpeed())
if (_data.at(i).hasSpeed() && !_outliers.contains(i))
v = _data.at(i).speed();
else if (!std::isnan(_speed.at(i)))
else if (!std::isnan(_speed.at(i)) && !_outliers.contains(i))
v = _speed.at(i);
else
continue;
@ -158,14 +153,10 @@ Graph Track::heartRate() const
if (!_data.size())
return raw;
for (int i = 0; i < _data.count(); i++) {
if (_outliers.contains(i))
continue;
if (_data.at(i).hasHeartRate())
for (int i = 0; i < _data.count(); i++)
if (_data.at(i).hasHeartRate() && !_outliers.contains(i))
raw.append(GraphPoint(_distance.at(i), _time.at(i),
_data.at(i).heartRate()));
}
return filter(raw, WINDOW_HF);
}
@ -174,16 +165,36 @@ Graph Track::temperature() const
{
Graph raw;
for (int i = 0; i < _data.size(); i++) {
if (_outliers.contains(i))
continue;
if (_data.at(i).hasTemperature())
for (int i = 0; i < _data.size(); i++)
if (_data.at(i).hasTemperature() && !_outliers.contains(i))
raw.append(GraphPoint(_distance.at(i), _time.at(i),
_data.at(i).temperature()));
}
return Graph(raw);
return raw;
}
Graph Track::cadence() const
{
Graph raw;
for (int i = 0; i < _data.size(); i++)
if (_data.at(i).hasCadence() && !_outliers.contains(i))
raw.append(GraphPoint(_distance.at(i), _time.at(i),
_data.at(i).cadence()));
return filter(raw, WINDOW_CF);
}
Graph Track::power() const
{
Graph raw;
for (int i = 0; i < _data.size(); i++)
if (_data.at(i).hasPower() && !_outliers.contains(i))
raw.append(GraphPoint(_distance.at(i), _time.at(i),
_data.at(i).power()));
return filter(raw, WINDOW_PF);
}
qreal Track::distance() const
@ -206,12 +217,9 @@ Path Track::track() const
{
Path ret;
for (int i = 0; i < _data.size(); i++) {
if (_outliers.contains(i))
continue;
for (int i = 0; i < _data.size(); i++)
if (!_outliers.contains(i))
ret.append(_data.at(i).coordinates());
}
return ret;
}

View File

@ -19,6 +19,8 @@ public:
Graph speed() const;
Graph heartRate() const;
Graph temperature() const;
Graph cadence() const;
Graph power() const;
qreal distance() const;
qreal time() const;

View File

@ -10,9 +10,11 @@ class Trackpoint
{
public:
Trackpoint()
{_elevation = NAN; _speed = NAN; _heartRate = NAN; _temperature = NAN;}
{_elevation = NAN; _speed = NAN; _heartRate = NAN; _temperature = NAN;
_cadence = NAN; _power = NAN;}
Trackpoint(const Coordinates &coordinates) : _coordinates(coordinates)
{_elevation = NAN; _speed = NAN; _heartRate = NAN; _temperature = NAN;}
{_elevation = NAN; _speed = NAN; _heartRate = NAN; _temperature = NAN;
_cadence = NAN; _power = NAN;}
const Coordinates &coordinates() const {return _coordinates;}
Coordinates &rcoordinates() {return _coordinates;}
@ -21,6 +23,8 @@ public:
qreal speed() const {return _speed;}
qreal heartRate() const {return _heartRate;}
qreal temperature() const {return _temperature;}
qreal cadence() const {return _cadence;}
qreal power() const {return _power;}
void setCoordinates(const Coordinates &coordinates)
{_coordinates = coordinates;}
@ -29,12 +33,16 @@ public:
void setSpeed(qreal speed) {_speed = speed;}
void setHeartRate(qreal heartRate) {_heartRate = heartRate;}
void setTemperature(qreal temperature) {_temperature = temperature;}
void setCadence(qreal cadence) {_cadence = cadence;}
void setPower(qreal power) {_power = power;}
bool hasTimestamp() const {return !_timestamp.isNull();}
bool hasElevation() const {return !std::isnan(_elevation);}
bool hasSpeed() const {return !std::isnan(_speed);}
bool hasHeartRate() const {return !std::isnan(_heartRate);}
bool hasTemperature() const {return !std::isnan(_temperature);}
bool hasCadence() const {return !std::isnan(_cadence);}
bool hasPower() const {return !std::isnan(_power);}
private:
Coordinates _coordinates;
@ -43,6 +51,8 @@ private:
qreal _speed;
qreal _heartRate;
qreal _temperature;
qreal _cadence;
qreal _power;
};
QDebug operator<<(QDebug dbg, const Trackpoint &trackpoint);