mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-24 03:35:53 +01:00
Added support for GPX files with multiple tracks
This commit is contained in:
parent
82660caccb
commit
923a00479a
@ -31,11 +31,11 @@ void ElevationGraph::addInfo()
|
||||
|
||||
void ElevationGraph::loadGPX(const GPX &gpx)
|
||||
{
|
||||
for (int i = 0; i < gpx.count(); i++) {
|
||||
QVector<QPointF> data;
|
||||
qreal min, max, ascent = 0, descent = 0;
|
||||
|
||||
|
||||
gpx.elevationGraph(data);
|
||||
gpx.elevationGraph(i, data);
|
||||
if (data.isEmpty())
|
||||
return;
|
||||
|
||||
@ -64,6 +64,7 @@ void ElevationGraph::loadGPX(const GPX &gpx)
|
||||
addInfo();
|
||||
loadData(data);
|
||||
}
|
||||
}
|
||||
|
||||
void ElevationGraph::clear()
|
||||
{
|
||||
|
63
src/gpx.cpp
63
src/gpx.cpp
@ -94,7 +94,7 @@ bool GPX::loadFile(const QString &fileName)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(ret = _parser.loadFile(&file, _data))) {
|
||||
if (!(ret = _parser.loadFile(&file, &_data))) {
|
||||
_error = _parser.errorString();
|
||||
_errorLine = _parser.errorLine();
|
||||
}
|
||||
@ -103,44 +103,46 @@ bool GPX::loadFile(const QString &fileName)
|
||||
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;
|
||||
QVector<QPointF> raw;
|
||||
|
||||
if (!_data.size())
|
||||
if (!data.size())
|
||||
return;
|
||||
|
||||
raw.append(QPointF(0, _data.at(0).elevation));
|
||||
for (int i = 1; i < _data.size(); i++) {
|
||||
dist += llDistance(_data.at(i).coordinates, _data.at(i-1).coordinates);
|
||||
raw.append(QPointF(dist, _data.at(i).elevation
|
||||
- _data.at(i).geoidheight));
|
||||
raw.append(QPointF(0, data.at(0).elevation));
|
||||
for (int i = 1; i < data.size(); i++) {
|
||||
dist += llDistance(data.at(i).coordinates, data.at(i-1).coordinates);
|
||||
raw.append(QPointF(dist, data.at(i).elevation
|
||||
- data.at(i).geoidheight));
|
||||
}
|
||||
|
||||
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;
|
||||
QVector<QPointF> raw;
|
||||
|
||||
if (!_data.size())
|
||||
if (!data.size())
|
||||
return;
|
||||
|
||||
raw.append(QPointF(0, 0));
|
||||
for (int i = 1; i < _data.size(); i++) {
|
||||
ds = llDistance(_data.at(i).coordinates, _data.at(i-1).coordinates);
|
||||
dt = _data.at(i-1).timestamp.msecsTo(_data.at(i).timestamp) / 1000.0;
|
||||
for (int i = 1; i < data.size(); i++) {
|
||||
ds = llDistance(data.at(i).coordinates, data.at(i-1).coordinates);
|
||||
dt = data.at(i-1).timestamp.msecsTo(data.at(i).timestamp) / 1000.0;
|
||||
dist += ds;
|
||||
|
||||
if (_data.at(i).speed < 0) {
|
||||
if (data.at(i).speed < 0) {
|
||||
if (dt == 0)
|
||||
continue;
|
||||
v = ds / dt;
|
||||
} else
|
||||
v = _data.at(i).speed;
|
||||
v = data.at(i).speed;
|
||||
|
||||
raw.append(QPointF(dist, v));
|
||||
}
|
||||
@ -148,35 +150,42 @@ void GPX::speedGraph(QVector<QPointF> &graph) const
|
||||
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++)
|
||||
track.append(ll2mercator(_data.at(i).coordinates));
|
||||
const QVector<TrackPoint> &data = _data.at(i);
|
||||
|
||||
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;
|
||||
|
||||
for (int i = 1; i < _data.size(); i++)
|
||||
dist += llDistance(_data.at(i).coordinates, _data.at(i-1).coordinates);
|
||||
for (int i = 1; i < data.size(); i++)
|
||||
dist += llDistance(data.at(i).coordinates, data.at(i-1).coordinates);
|
||||
|
||||
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 (_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);
|
||||
}
|
||||
|
||||
QDateTime GPX::date() const
|
||||
QDateTime GPX::date(int i) const
|
||||
{
|
||||
if (_data.size())
|
||||
return _data.at(0).timestamp;
|
||||
const QVector<TrackPoint> &data = _data.at(i);
|
||||
|
||||
if (data.size())
|
||||
return data.at(0).timestamp;
|
||||
else
|
||||
return QDateTime();
|
||||
}
|
||||
|
16
src/gpx.h
16
src/gpx.h
@ -2,6 +2,7 @@
|
||||
#define GPX_H
|
||||
|
||||
#include <QVector>
|
||||
#include <QList>
|
||||
#include <QPointF>
|
||||
#include <QString>
|
||||
#include "parser.h"
|
||||
@ -13,16 +14,17 @@ public:
|
||||
const QString &errorString() const {return _error;}
|
||||
int errorLine() const {return _errorLine;}
|
||||
|
||||
void elevationGraph(QVector<QPointF> &graph) const;
|
||||
void speedGraph(QVector<QPointF> &graph) const;
|
||||
void track(QVector<QPointF> &track) const;
|
||||
qreal distance() const;
|
||||
qreal time() const;
|
||||
QDateTime date() const;
|
||||
int count() const {return _data.count();}
|
||||
void elevationGraph(int i, QVector<QPointF> &graph) const;
|
||||
void speedGraph(int i, QVector<QPointF> &graph) const;
|
||||
void track(int i, QVector<QPointF> &track) const;
|
||||
qreal distance(int i) const;
|
||||
qreal time(int i) const;
|
||||
QDateTime date(int i) const;
|
||||
|
||||
private:
|
||||
Parser _parser;
|
||||
QVector<TrackPoint> _data;
|
||||
QList<QVector<TrackPoint> > _data;
|
||||
QString _error;
|
||||
int _errorLine;
|
||||
};
|
||||
|
18
src/gui.cpp
18
src/gui.cpp
@ -67,6 +67,7 @@ GUI::GUI()
|
||||
|
||||
_distance = 0;
|
||||
_time = 0;
|
||||
_trackCount = 0;
|
||||
|
||||
resize(600, 800);
|
||||
}
|
||||
@ -443,8 +444,12 @@ bool GUI::loadFile(const QString &fileName)
|
||||
if (_showPOIAction->isChecked())
|
||||
_track->loadPOI(_poi);
|
||||
|
||||
_distance += gpx.distance();
|
||||
_time += gpx.time();
|
||||
for (int i = 0; i < gpx.count(); i++) {
|
||||
_distance += gpx.distance(i);
|
||||
_time += gpx.time(i);
|
||||
}
|
||||
|
||||
_trackCount += gpx.count();
|
||||
|
||||
return true;
|
||||
} else {
|
||||
@ -571,6 +576,7 @@ void GUI::closeFile()
|
||||
{
|
||||
_distance = 0;
|
||||
_time = 0;
|
||||
_trackCount = 0;
|
||||
|
||||
_elevationGraph->clear();
|
||||
_speedGraph->clear();
|
||||
@ -621,17 +627,15 @@ void GUI::showToolbars(bool checked)
|
||||
|
||||
void GUI::updateStatusBarInfo()
|
||||
{
|
||||
int files = _files.size();
|
||||
|
||||
if (files == 0) {
|
||||
if (_files.count() == 0) {
|
||||
_fileNameLabel->clear();
|
||||
_distanceLabel->clear();
|
||||
_timeLabel->clear();
|
||||
return;
|
||||
} else if (files == 1)
|
||||
} else if (_files.count() == 1)
|
||||
_fileNameLabel->setText(_files.at(0));
|
||||
else
|
||||
_fileNameLabel->setText(tr("%1 tracks").arg(_files.size()));
|
||||
_fileNameLabel->setText(tr("%1 tracks").arg(_trackCount));
|
||||
|
||||
if (_imperialUnitsAction->isChecked())
|
||||
_distanceLabel->setText(QString::number(_distance * M2MI, 'f', 1)
|
||||
|
@ -126,6 +126,7 @@ private:
|
||||
|
||||
qreal _distance;
|
||||
qreal _time;
|
||||
int _trackCount;
|
||||
};
|
||||
|
||||
#endif // GUI_H
|
||||
|
@ -1,96 +1,95 @@
|
||||
#include "parser.h"
|
||||
|
||||
|
||||
void Parser::handleExtensionData(QVector<TrackPoint> &data,
|
||||
QStringRef element, const QString &value)
|
||||
void Parser::handleExtensionData(QStringRef element, const QString &value)
|
||||
{
|
||||
if (element == "speed")
|
||||
data.last().speed = value.toDouble();
|
||||
_track->last().speed = value.toDouble();
|
||||
}
|
||||
|
||||
void Parser::handleTrekPointData(QVector<TrackPoint> &data,
|
||||
QStringRef element, const QString &value)
|
||||
void Parser::handleTrekPointData(QStringRef element, const QString &value)
|
||||
{
|
||||
if (element == "ele")
|
||||
data.last().elevation = value.toLatin1().toDouble();
|
||||
_track->last().elevation = value.toLatin1().toDouble();
|
||||
if (element == "time")
|
||||
data.last().timestamp = QDateTime::fromString(value.toLatin1(),
|
||||
_track->last().timestamp = QDateTime::fromString(value.toLatin1(),
|
||||
Qt::ISODate);
|
||||
if (element == "geoidheight")
|
||||
data.last().geoidheight = value.toLatin1().toDouble();
|
||||
_track->last().geoidheight = value.toLatin1().toDouble();
|
||||
}
|
||||
|
||||
void Parser::handleTrekPointAttributes(QVector<TrackPoint> &data,
|
||||
const QXmlStreamAttributes &attr)
|
||||
void Parser::handleTrekPointAttributes(const QXmlStreamAttributes &attr)
|
||||
{
|
||||
data.last().coordinates.setY(attr.value("lat").toLatin1().toDouble());
|
||||
data.last().coordinates.setX(attr.value("lon").toLatin1().toDouble());
|
||||
_track->last().coordinates.setY(attr.value("lat").toLatin1().toDouble());
|
||||
_track->last().coordinates.setX(attr.value("lon").toLatin1().toDouble());
|
||||
}
|
||||
|
||||
|
||||
void Parser::extensions(QVector<TrackPoint> &data)
|
||||
void Parser::extensions()
|
||||
{
|
||||
while (_reader.readNextStartElement()) {
|
||||
if (_reader.name() == "speed")
|
||||
handleExtensionData(data, _reader.name(), _reader.readElementText());
|
||||
handleExtensionData(_reader.name(), _reader.readElementText());
|
||||
else
|
||||
_reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
void Parser::trekPointData(QVector<TrackPoint> &data)
|
||||
void Parser::trackPointData()
|
||||
{
|
||||
while (_reader.readNextStartElement()) {
|
||||
if (_reader.name() == "ele" || _reader.name() == "time"
|
||||
|| _reader.name() == "geoidheight")
|
||||
handleTrekPointData(data, _reader.name(), _reader.readElementText());
|
||||
handleTrekPointData(_reader.name(), _reader.readElementText());
|
||||
else if (_reader.name() == "extensions")
|
||||
extensions(data);
|
||||
extensions();
|
||||
else
|
||||
_reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
void Parser::trekPoints(QVector<TrackPoint> &data)
|
||||
void Parser::trackPoints()
|
||||
{
|
||||
QXmlStreamAttributes attr;
|
||||
|
||||
while (_reader.readNextStartElement()) {
|
||||
if (_reader.name() == "trkpt") {
|
||||
attr = _reader.attributes();
|
||||
data.append(TrackPoint());
|
||||
handleTrekPointAttributes(data, attr);
|
||||
trekPointData(data);
|
||||
_track->append(TrackPoint());
|
||||
handleTrekPointAttributes(attr);
|
||||
trackPointData();
|
||||
} else
|
||||
_reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
void Parser::trek(QVector<TrackPoint> &data)
|
||||
void Parser::track()
|
||||
{
|
||||
while (_reader.readNextStartElement()) {
|
||||
if (_reader.name() == "trkseg") {
|
||||
trekPoints(data);
|
||||
trackPoints();
|
||||
} else
|
||||
_reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
void Parser::gpx(QVector<TrackPoint> &data)
|
||||
void Parser::gpx()
|
||||
{
|
||||
while (_reader.readNextStartElement()) {
|
||||
if (_reader.name() == "trk")
|
||||
trek(data);
|
||||
else
|
||||
if (_reader.name() == "trk") {
|
||||
_data->append(QVector<TrackPoint>());
|
||||
_track = &_data->back();
|
||||
track();
|
||||
} else
|
||||
_reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
bool Parser::parse(QVector<TrackPoint> &data)
|
||||
bool Parser::parse()
|
||||
{
|
||||
if (_reader.readNextStartElement()) {
|
||||
if (_reader.name() == "gpx")
|
||||
gpx(data);
|
||||
gpx();
|
||||
else
|
||||
_reader.raiseError("Not a GPX file.");
|
||||
}
|
||||
@ -98,10 +97,11 @@ bool Parser::parse(QVector<TrackPoint> &data)
|
||||
return !_reader.error();
|
||||
}
|
||||
|
||||
bool Parser::loadFile(QIODevice *device, QVector<TrackPoint> &data)
|
||||
bool Parser::loadFile(QIODevice *device, QList<QVector<TrackPoint> > *data)
|
||||
{
|
||||
_reader.clear();
|
||||
_reader.setDevice(device);
|
||||
_data = data;
|
||||
|
||||
return parse(data);
|
||||
return parse();
|
||||
}
|
||||
|
26
src/parser.h
26
src/parser.h
@ -19,26 +19,26 @@ struct TrackPoint
|
||||
class Parser
|
||||
{
|
||||
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();}
|
||||
int errorLine() const {return _reader.lineNumber();}
|
||||
|
||||
private:
|
||||
bool parse(QVector<TrackPoint> &data);
|
||||
void gpx(QVector<TrackPoint> &data);
|
||||
void trek(QVector<TrackPoint> &data);
|
||||
void trekPoints(QVector<TrackPoint> &data);
|
||||
void extensions(QVector<TrackPoint> &data);
|
||||
void trekPointData(QVector<TrackPoint> &data);
|
||||
bool parse();
|
||||
void gpx();
|
||||
void track();
|
||||
void trackPoints();
|
||||
void extensions();
|
||||
void trackPointData();
|
||||
|
||||
void handleTrekPointAttributes(QVector<TrackPoint> &data,
|
||||
const QXmlStreamAttributes &attr);
|
||||
void handleTrekPointData(QVector<TrackPoint> &data, QStringRef element,
|
||||
const QString &value);
|
||||
void handleExtensionData(QVector<TrackPoint> &data, QStringRef element,
|
||||
const QString &value);
|
||||
void handleTrekPointAttributes(const QXmlStreamAttributes &attr);
|
||||
void handleTrekPointData(QStringRef element, const QString &value);
|
||||
void handleExtensionData(QStringRef element, const QString &value);
|
||||
|
||||
QXmlStreamReader _reader;
|
||||
QList<QVector<TrackPoint> > *_data;
|
||||
QVector<TrackPoint> *_track;
|
||||
};
|
||||
|
||||
#endif // PARSER_H
|
||||
|
@ -25,15 +25,15 @@ void SpeedGraph::addInfo()
|
||||
|
||||
void SpeedGraph::loadGPX(const GPX &gpx)
|
||||
{
|
||||
for (int i = 0; i < gpx.count(); i++) {
|
||||
QVector<QPointF> data;
|
||||
qreal max = 0;
|
||||
|
||||
|
||||
gpx.speedGraph(data);
|
||||
gpx.speedGraph(i, data);
|
||||
if (data.isEmpty())
|
||||
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++)
|
||||
max = qMax(max, data.at(i).y());
|
||||
@ -42,6 +42,7 @@ void SpeedGraph::loadGPX(const GPX &gpx)
|
||||
addInfo();
|
||||
loadData(data);
|
||||
}
|
||||
}
|
||||
|
||||
qreal SpeedGraph::avg() const
|
||||
{
|
||||
|
@ -41,6 +41,7 @@ Track::~Track()
|
||||
|
||||
void Track::loadGPX(const GPX &gpx)
|
||||
{
|
||||
for (int i = 0; i < gpx.count(); i++) {
|
||||
QVector<QPointF> track;
|
||||
QPainterPath path;
|
||||
QGraphicsPathItem *pi;
|
||||
@ -49,10 +50,10 @@ void Track::loadGPX(const GPX &gpx)
|
||||
qreal prevScale = _scale;
|
||||
|
||||
|
||||
gpx.track(track);
|
||||
gpx.track(i, track);
|
||||
|
||||
if (track.size() < 2)
|
||||
return;
|
||||
continue;
|
||||
|
||||
_tracks.append(track);
|
||||
|
||||
@ -92,6 +93,7 @@ void Track::loadGPX(const GPX &gpx)
|
||||
_mapScale->setLatitude(track.at(track.size() / 2).y());
|
||||
_mapScale->setZoom(_zoom);
|
||||
}
|
||||
}
|
||||
|
||||
QRectF Track::trackBoundingRect() const
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user