1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-02-17 16:20:48 +01:00

Added support for GPX files with multiple tracks

This commit is contained in:
Martin Tůma 2016-02-08 17:53:09 +01:00
parent 82660caccb
commit 923a00479a
9 changed files with 179 additions and 159 deletions

View File

@ -31,11 +31,11 @@ void ElevationGraph::addInfo()
void ElevationGraph::loadGPX(const GPX &gpx) void ElevationGraph::loadGPX(const GPX &gpx)
{ {
for (int i = 0; i < gpx.count(); i++) {
QVector<QPointF> data; QVector<QPointF> data;
qreal min, max, ascent = 0, descent = 0; qreal min, max, ascent = 0, descent = 0;
gpx.elevationGraph(i, data);
gpx.elevationGraph(data);
if (data.isEmpty()) if (data.isEmpty())
return; return;
@ -64,6 +64,7 @@ void ElevationGraph::loadGPX(const GPX &gpx)
addInfo(); addInfo();
loadData(data); loadData(data);
} }
}
void ElevationGraph::clear() void ElevationGraph::clear()
{ {

View File

@ -94,7 +94,7 @@ bool GPX::loadFile(const QString &fileName)
return false; return false;
} }
if (!(ret = _parser.loadFile(&file, _data))) { if (!(ret = _parser.loadFile(&file, &_data))) {
_error = _parser.errorString(); _error = _parser.errorString();
_errorLine = _parser.errorLine(); _errorLine = _parser.errorLine();
} }
@ -103,44 +103,46 @@ bool GPX::loadFile(const QString &fileName)
return ret; return ret;
} }
void GPX::elevationGraph(QVector<QPointF> &graph) const void GPX::elevationGraph(int i, QVector<QPointF> &graph) const
{ {
const QVector<TrackPoint> &data = _data.at(i);
qreal dist = 0; qreal dist = 0;
QVector<QPointF> raw; QVector<QPointF> raw;
if (!_data.size()) if (!data.size())
return; return;
raw.append(QPointF(0, _data.at(0).elevation)); raw.append(QPointF(0, data.at(0).elevation));
for (int i = 1; i < _data.size(); i++) { for (int i = 1; i < data.size(); i++) {
dist += llDistance(_data.at(i).coordinates, _data.at(i-1).coordinates); dist += llDistance(data.at(i).coordinates, data.at(i-1).coordinates);
raw.append(QPointF(dist, _data.at(i).elevation raw.append(QPointF(dist, data.at(i).elevation
- _data.at(i).geoidheight)); - data.at(i).geoidheight));
} }
graph = filter(raw, WINDOW_EF); graph = filter(raw, WINDOW_EF);
} }
void GPX::speedGraph(QVector<QPointF> &graph) const void GPX::speedGraph(int i, QVector<QPointF> &graph) const
{ {
const QVector<TrackPoint> &data = _data.at(i);
qreal dist = 0, v, ds, dt; qreal dist = 0, v, ds, dt;
QVector<QPointF> raw; QVector<QPointF> raw;
if (!_data.size()) if (!data.size())
return; return;
raw.append(QPointF(0, 0)); raw.append(QPointF(0, 0));
for (int i = 1; i < _data.size(); i++) { for (int i = 1; i < data.size(); i++) {
ds = llDistance(_data.at(i).coordinates, _data.at(i-1).coordinates); ds = llDistance(data.at(i).coordinates, data.at(i-1).coordinates);
dt = _data.at(i-1).timestamp.msecsTo(_data.at(i).timestamp) / 1000.0; dt = data.at(i-1).timestamp.msecsTo(data.at(i).timestamp) / 1000.0;
dist += ds; dist += ds;
if (_data.at(i).speed < 0) { if (data.at(i).speed < 0) {
if (dt == 0) if (dt == 0)
continue; continue;
v = ds / dt; v = ds / dt;
} else } else
v = _data.at(i).speed; v = data.at(i).speed;
raw.append(QPointF(dist, v)); raw.append(QPointF(dist, v));
} }
@ -148,35 +150,42 @@ void GPX::speedGraph(QVector<QPointF> &graph) const
graph = filter(eliminate(raw, WINDOW_SE), WINDOW_SF); graph = filter(eliminate(raw, WINDOW_SE), WINDOW_SF);
} }
void GPX::track(QVector<QPointF> &track) const void GPX::track(int i, QVector<QPointF> &track) const
{ {
for (int i = 0; i < _data.size(); i++) const QVector<TrackPoint> &data = _data.at(i);
track.append(ll2mercator(_data.at(i).coordinates));
for (int i = 0; i < data.size(); i++)
track.append(ll2mercator(data.at(i).coordinates));
} }
qreal GPX::distance() const qreal GPX::distance(int i) const
{ {
const QVector<TrackPoint> &data = _data.at(i);
qreal dist = 0; qreal dist = 0;
for (int i = 1; i < _data.size(); i++) for (int i = 1; i < data.size(); i++)
dist += llDistance(_data.at(i).coordinates, _data.at(i-1).coordinates); dist += llDistance(data.at(i).coordinates, data.at(i-1).coordinates);
return dist; return dist;
} }
qreal GPX::time() const qreal GPX::time(int i) const
{ {
if (_data.size() < 2) const QVector<TrackPoint> &data = _data.at(i);
if (data.size() < 2)
return 0; return 0;
return (_data.at(0).timestamp.msecsTo(_data.at(_data.size() - 1).timestamp) return (data.at(0).timestamp.msecsTo(data.at(data.size() - 1).timestamp)
/ 1000.0); / 1000.0);
} }
QDateTime GPX::date() const QDateTime GPX::date(int i) const
{ {
if (_data.size()) const QVector<TrackPoint> &data = _data.at(i);
return _data.at(0).timestamp;
if (data.size())
return data.at(0).timestamp;
else else
return QDateTime(); return QDateTime();
} }

View File

@ -2,6 +2,7 @@
#define GPX_H #define GPX_H
#include <QVector> #include <QVector>
#include <QList>
#include <QPointF> #include <QPointF>
#include <QString> #include <QString>
#include "parser.h" #include "parser.h"
@ -13,16 +14,17 @@ public:
const QString &errorString() const {return _error;} const QString &errorString() const {return _error;}
int errorLine() const {return _errorLine;} int errorLine() const {return _errorLine;}
void elevationGraph(QVector<QPointF> &graph) const; int count() const {return _data.count();}
void speedGraph(QVector<QPointF> &graph) const; void elevationGraph(int i, QVector<QPointF> &graph) const;
void track(QVector<QPointF> &track) const; void speedGraph(int i, QVector<QPointF> &graph) const;
qreal distance() const; void track(int i, QVector<QPointF> &track) const;
qreal time() const; qreal distance(int i) const;
QDateTime date() const; qreal time(int i) const;
QDateTime date(int i) const;
private: private:
Parser _parser; Parser _parser;
QVector<TrackPoint> _data; QList<QVector<TrackPoint> > _data;
QString _error; QString _error;
int _errorLine; int _errorLine;
}; };

View File

@ -67,6 +67,7 @@ GUI::GUI()
_distance = 0; _distance = 0;
_time = 0; _time = 0;
_trackCount = 0;
resize(600, 800); resize(600, 800);
} }
@ -443,8 +444,12 @@ bool GUI::loadFile(const QString &fileName)
if (_showPOIAction->isChecked()) if (_showPOIAction->isChecked())
_track->loadPOI(_poi); _track->loadPOI(_poi);
_distance += gpx.distance(); for (int i = 0; i < gpx.count(); i++) {
_time += gpx.time(); _distance += gpx.distance(i);
_time += gpx.time(i);
}
_trackCount += gpx.count();
return true; return true;
} else { } else {
@ -571,6 +576,7 @@ void GUI::closeFile()
{ {
_distance = 0; _distance = 0;
_time = 0; _time = 0;
_trackCount = 0;
_elevationGraph->clear(); _elevationGraph->clear();
_speedGraph->clear(); _speedGraph->clear();
@ -621,17 +627,15 @@ void GUI::showToolbars(bool checked)
void GUI::updateStatusBarInfo() void GUI::updateStatusBarInfo()
{ {
int files = _files.size(); if (_files.count() == 0) {
if (files == 0) {
_fileNameLabel->clear(); _fileNameLabel->clear();
_distanceLabel->clear(); _distanceLabel->clear();
_timeLabel->clear(); _timeLabel->clear();
return; return;
} else if (files == 1) } else if (_files.count() == 1)
_fileNameLabel->setText(_files.at(0)); _fileNameLabel->setText(_files.at(0));
else else
_fileNameLabel->setText(tr("%1 tracks").arg(_files.size())); _fileNameLabel->setText(tr("%1 tracks").arg(_trackCount));
if (_imperialUnitsAction->isChecked()) if (_imperialUnitsAction->isChecked())
_distanceLabel->setText(QString::number(_distance * M2MI, 'f', 1) _distanceLabel->setText(QString::number(_distance * M2MI, 'f', 1)

View File

@ -126,6 +126,7 @@ private:
qreal _distance; qreal _distance;
qreal _time; qreal _time;
int _trackCount;
}; };
#endif // GUI_H #endif // GUI_H

View File

@ -1,96 +1,95 @@
#include "parser.h" #include "parser.h"
void Parser::handleExtensionData(QVector<TrackPoint> &data, void Parser::handleExtensionData(QStringRef element, const QString &value)
QStringRef element, const QString &value)
{ {
if (element == "speed") if (element == "speed")
data.last().speed = value.toDouble(); _track->last().speed = value.toDouble();
} }
void Parser::handleTrekPointData(QVector<TrackPoint> &data, void Parser::handleTrekPointData(QStringRef element, const QString &value)
QStringRef element, const QString &value)
{ {
if (element == "ele") if (element == "ele")
data.last().elevation = value.toLatin1().toDouble(); _track->last().elevation = value.toLatin1().toDouble();
if (element == "time") if (element == "time")
data.last().timestamp = QDateTime::fromString(value.toLatin1(), _track->last().timestamp = QDateTime::fromString(value.toLatin1(),
Qt::ISODate); Qt::ISODate);
if (element == "geoidheight") if (element == "geoidheight")
data.last().geoidheight = value.toLatin1().toDouble(); _track->last().geoidheight = value.toLatin1().toDouble();
} }
void Parser::handleTrekPointAttributes(QVector<TrackPoint> &data, void Parser::handleTrekPointAttributes(const QXmlStreamAttributes &attr)
const QXmlStreamAttributes &attr)
{ {
data.last().coordinates.setY(attr.value("lat").toLatin1().toDouble()); _track->last().coordinates.setY(attr.value("lat").toLatin1().toDouble());
data.last().coordinates.setX(attr.value("lon").toLatin1().toDouble()); _track->last().coordinates.setX(attr.value("lon").toLatin1().toDouble());
} }
void Parser::extensions(QVector<TrackPoint> &data) void Parser::extensions()
{ {
while (_reader.readNextStartElement()) { while (_reader.readNextStartElement()) {
if (_reader.name() == "speed") if (_reader.name() == "speed")
handleExtensionData(data, _reader.name(), _reader.readElementText()); handleExtensionData(_reader.name(), _reader.readElementText());
else else
_reader.skipCurrentElement(); _reader.skipCurrentElement();
} }
} }
void Parser::trekPointData(QVector<TrackPoint> &data) void Parser::trackPointData()
{ {
while (_reader.readNextStartElement()) { while (_reader.readNextStartElement()) {
if (_reader.name() == "ele" || _reader.name() == "time" if (_reader.name() == "ele" || _reader.name() == "time"
|| _reader.name() == "geoidheight") || _reader.name() == "geoidheight")
handleTrekPointData(data, _reader.name(), _reader.readElementText()); handleTrekPointData(_reader.name(), _reader.readElementText());
else if (_reader.name() == "extensions") else if (_reader.name() == "extensions")
extensions(data); extensions();
else else
_reader.skipCurrentElement(); _reader.skipCurrentElement();
} }
} }
void Parser::trekPoints(QVector<TrackPoint> &data) void Parser::trackPoints()
{ {
QXmlStreamAttributes attr; QXmlStreamAttributes attr;
while (_reader.readNextStartElement()) { while (_reader.readNextStartElement()) {
if (_reader.name() == "trkpt") { if (_reader.name() == "trkpt") {
attr = _reader.attributes(); attr = _reader.attributes();
data.append(TrackPoint()); _track->append(TrackPoint());
handleTrekPointAttributes(data, attr); handleTrekPointAttributes(attr);
trekPointData(data); trackPointData();
} else } else
_reader.skipCurrentElement(); _reader.skipCurrentElement();
} }
} }
void Parser::trek(QVector<TrackPoint> &data) void Parser::track()
{ {
while (_reader.readNextStartElement()) { while (_reader.readNextStartElement()) {
if (_reader.name() == "trkseg") { if (_reader.name() == "trkseg") {
trekPoints(data); trackPoints();
} else } else
_reader.skipCurrentElement(); _reader.skipCurrentElement();
} }
} }
void Parser::gpx(QVector<TrackPoint> &data) void Parser::gpx()
{ {
while (_reader.readNextStartElement()) { while (_reader.readNextStartElement()) {
if (_reader.name() == "trk") if (_reader.name() == "trk") {
trek(data); _data->append(QVector<TrackPoint>());
else _track = &_data->back();
track();
} else
_reader.skipCurrentElement(); _reader.skipCurrentElement();
} }
} }
bool Parser::parse(QVector<TrackPoint> &data) bool Parser::parse()
{ {
if (_reader.readNextStartElement()) { if (_reader.readNextStartElement()) {
if (_reader.name() == "gpx") if (_reader.name() == "gpx")
gpx(data); gpx();
else else
_reader.raiseError("Not a GPX file."); _reader.raiseError("Not a GPX file.");
} }
@ -98,10 +97,11 @@ bool Parser::parse(QVector<TrackPoint> &data)
return !_reader.error(); return !_reader.error();
} }
bool Parser::loadFile(QIODevice *device, QVector<TrackPoint> &data) bool Parser::loadFile(QIODevice *device, QList<QVector<TrackPoint> > *data)
{ {
_reader.clear(); _reader.clear();
_reader.setDevice(device); _reader.setDevice(device);
_data = data;
return parse(data); return parse();
} }

View File

@ -19,26 +19,26 @@ struct TrackPoint
class Parser class Parser
{ {
public: public:
bool loadFile(QIODevice *device, QVector<TrackPoint> &data); Parser() {_data = 0; _track = 0;}
bool loadFile(QIODevice *device, QList<QVector<TrackPoint> > *data);
QString errorString() const {return _reader.errorString();} QString errorString() const {return _reader.errorString();}
int errorLine() const {return _reader.lineNumber();} int errorLine() const {return _reader.lineNumber();}
private: private:
bool parse(QVector<TrackPoint> &data); bool parse();
void gpx(QVector<TrackPoint> &data); void gpx();
void trek(QVector<TrackPoint> &data); void track();
void trekPoints(QVector<TrackPoint> &data); void trackPoints();
void extensions(QVector<TrackPoint> &data); void extensions();
void trekPointData(QVector<TrackPoint> &data); void trackPointData();
void handleTrekPointAttributes(QVector<TrackPoint> &data, void handleTrekPointAttributes(const QXmlStreamAttributes &attr);
const QXmlStreamAttributes &attr); void handleTrekPointData(QStringRef element, const QString &value);
void handleTrekPointData(QVector<TrackPoint> &data, QStringRef element, void handleExtensionData(QStringRef element, const QString &value);
const QString &value);
void handleExtensionData(QVector<TrackPoint> &data, QStringRef element,
const QString &value);
QXmlStreamReader _reader; QXmlStreamReader _reader;
QList<QVector<TrackPoint> > *_data;
QVector<TrackPoint> *_track;
}; };
#endif // PARSER_H #endif // PARSER_H

View File

@ -25,15 +25,15 @@ void SpeedGraph::addInfo()
void SpeedGraph::loadGPX(const GPX &gpx) void SpeedGraph::loadGPX(const GPX &gpx)
{ {
for (int i = 0; i < gpx.count(); i++) {
QVector<QPointF> data; QVector<QPointF> data;
qreal max = 0; qreal max = 0;
gpx.speedGraph(i, data);
gpx.speedGraph(data);
if (data.isEmpty()) if (data.isEmpty())
return; return;
_avg.append(QPointF(gpx.distance(), gpx.distance() / gpx.time())); _avg.append(QPointF(gpx.distance(i), gpx.distance(i) / gpx.time(i)));
for (int i = 0; i < data.size(); i++) for (int i = 0; i < data.size(); i++)
max = qMax(max, data.at(i).y()); max = qMax(max, data.at(i).y());
@ -42,6 +42,7 @@ void SpeedGraph::loadGPX(const GPX &gpx)
addInfo(); addInfo();
loadData(data); loadData(data);
} }
}
qreal SpeedGraph::avg() const qreal SpeedGraph::avg() const
{ {

View File

@ -41,6 +41,7 @@ Track::~Track()
void Track::loadGPX(const GPX &gpx) void Track::loadGPX(const GPX &gpx)
{ {
for (int i = 0; i < gpx.count(); i++) {
QVector<QPointF> track; QVector<QPointF> track;
QPainterPath path; QPainterPath path;
QGraphicsPathItem *pi; QGraphicsPathItem *pi;
@ -49,10 +50,10 @@ void Track::loadGPX(const GPX &gpx)
qreal prevScale = _scale; qreal prevScale = _scale;
gpx.track(track); gpx.track(i, track);
if (track.size() < 2) if (track.size() < 2)
return; continue;
_tracks.append(track); _tracks.append(track);
@ -92,6 +93,7 @@ void Track::loadGPX(const GPX &gpx)
_mapScale->setLatitude(track.at(track.size() / 2).y()); _mapScale->setLatitude(track.at(track.size() / 2).y());
_mapScale->setZoom(_zoom); _mapScale->setZoom(_zoom);
} }
}
QRectF Track::trackBoundingRect() const QRectF Track::trackBoundingRect() const
{ {