2016-10-23 11:09:20 +02:00
|
|
|
#include "gpxparser.h"
|
2015-10-05 01:43:48 +02:00
|
|
|
|
2015-10-15 01:30:21 +02:00
|
|
|
|
2016-10-27 00:20:00 +02:00
|
|
|
qreal GPXParser::number()
|
2015-10-15 01:30:21 +02:00
|
|
|
{
|
2016-10-27 00:20:00 +02:00
|
|
|
bool res;
|
|
|
|
qreal ret = _reader.readElementText().toDouble(&res);
|
|
|
|
if (!res)
|
|
|
|
_reader.raiseError(QString("Invalid %1.").arg(
|
|
|
|
_reader.name().toString()));
|
2015-10-05 01:43:48 +02:00
|
|
|
|
2016-10-27 00:20:00 +02:00
|
|
|
return ret;
|
2016-02-11 20:58:52 +01:00
|
|
|
}
|
|
|
|
|
2016-10-27 00:20:00 +02:00
|
|
|
QDateTime GPXParser::time()
|
2016-08-09 01:16:19 +02:00
|
|
|
{
|
2016-10-27 00:20:00 +02:00
|
|
|
QDateTime d = QDateTime::fromString(_reader.readElementText(),
|
|
|
|
Qt::ISODate);
|
|
|
|
if (!d.isValid())
|
|
|
|
_reader.raiseError(QString("Invalid %1.").arg(
|
|
|
|
_reader.name().toString()));
|
|
|
|
|
|
|
|
return d;
|
2016-08-09 01:16:19 +02:00
|
|
|
}
|
|
|
|
|
2016-10-27 00:20:00 +02:00
|
|
|
Coordinates GPXParser::coordinates()
|
2016-10-24 00:21:40 +02:00
|
|
|
{
|
|
|
|
bool res;
|
|
|
|
qreal lon, lat;
|
2016-10-27 00:20:00 +02:00
|
|
|
const QXmlStreamAttributes &attr = _reader.attributes();
|
2016-10-24 00:21:40 +02:00
|
|
|
|
2016-10-25 19:46:44 +02:00
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
|
|
|
lon = attr.value("lon").toString().toDouble(&res);
|
|
|
|
#else // QT_VERSION < 5
|
2016-10-24 00:21:40 +02:00
|
|
|
lon = attr.value("lon").toDouble(&res);
|
2016-10-25 19:46:44 +02:00
|
|
|
#endif // QT_VERSION < 5
|
2016-10-24 00:21:40 +02:00
|
|
|
if (!res || (lon < -180.0 || lon > 180.0)) {
|
|
|
|
_reader.raiseError("Invalid longitude.");
|
|
|
|
return Coordinates();
|
|
|
|
}
|
2016-10-25 19:46:44 +02:00
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
|
|
|
lat = attr.value("lat").toString().toDouble(&res);
|
|
|
|
#else // QT_VERSION < 5
|
2016-10-24 00:21:40 +02:00
|
|
|
lat = attr.value("lat").toDouble(&res);
|
2016-10-25 19:46:44 +02:00
|
|
|
#endif // QT_VERSION < 5
|
2016-10-24 00:21:40 +02:00
|
|
|
if (!res || (lat < -90.0 || lat > 90.0)) {
|
|
|
|
_reader.raiseError("Invalid latitude.");
|
|
|
|
return Coordinates();
|
|
|
|
}
|
|
|
|
|
|
|
|
return Coordinates(lon, lat);
|
|
|
|
}
|
|
|
|
|
2016-10-27 00:20:00 +02:00
|
|
|
void GPXParser::handleTrackpointData(DataType type)
|
2016-08-09 01:16:19 +02:00
|
|
|
{
|
2016-10-27 00:20:00 +02:00
|
|
|
switch (type) {
|
|
|
|
case Elevation:
|
|
|
|
_track->last().setElevation(number());
|
|
|
|
break;
|
|
|
|
case Time:
|
|
|
|
_track->last().setTimestamp(time());
|
|
|
|
break;
|
|
|
|
case Speed:
|
|
|
|
_track->last().setSpeed(number());
|
|
|
|
break;
|
|
|
|
case HeartRate:
|
|
|
|
_track->last().setHeartRate(number());
|
|
|
|
break;
|
|
|
|
case Temperature:
|
|
|
|
_track->last().setTemperature(number());
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2016-08-09 01:16:19 +02:00
|
|
|
}
|
|
|
|
|
2016-10-27 00:20:00 +02:00
|
|
|
void GPXParser::handleWaypointData(DataType type, Waypoint &waypoint)
|
2016-02-11 20:58:52 +01:00
|
|
|
{
|
2016-10-27 00:20:00 +02:00
|
|
|
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;
|
|
|
|
}
|
2016-02-11 20:58:52 +01:00
|
|
|
}
|
2015-10-05 01:43:48 +02:00
|
|
|
|
2016-10-23 11:09:20 +02:00
|
|
|
void GPXParser::tpExtension()
|
2016-03-21 23:13:46 +01:00
|
|
|
{
|
|
|
|
while (_reader.readNextStartElement()) {
|
2016-06-20 23:56:42 +02:00
|
|
|
if (_reader.name() == "hr")
|
2016-10-27 00:20:00 +02:00
|
|
|
handleTrackpointData(HeartRate);
|
2016-06-20 23:56:42 +02:00
|
|
|
else if (_reader.name() == "atemp")
|
2016-10-27 00:20:00 +02:00
|
|
|
handleTrackpointData(Temperature);
|
2016-03-21 23:13:46 +01:00
|
|
|
else
|
|
|
|
_reader.skipCurrentElement();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-23 11:09:20 +02:00
|
|
|
void GPXParser::extensions()
|
2015-10-15 01:30:21 +02:00
|
|
|
{
|
|
|
|
while (_reader.readNextStartElement()) {
|
2016-06-20 23:56:42 +02:00
|
|
|
if (_reader.name() == "speed")
|
2016-10-27 00:20:00 +02:00
|
|
|
handleTrackpointData(Speed);
|
2016-06-20 23:56:42 +02:00
|
|
|
else if (_reader.name() == "hr" || _reader.name() == "heartrate")
|
2016-10-27 00:20:00 +02:00
|
|
|
handleTrackpointData(HeartRate);
|
2016-06-20 23:56:42 +02:00
|
|
|
else if (_reader.name() == "temp")
|
2016-10-27 00:20:00 +02:00
|
|
|
handleTrackpointData(Temperature);
|
2016-03-21 23:13:46 +01:00
|
|
|
else if (_reader.name() == "TrackPointExtension")
|
|
|
|
tpExtension();
|
2015-10-15 01:30:21 +02:00
|
|
|
else
|
|
|
|
_reader.skipCurrentElement();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-23 11:09:20 +02:00
|
|
|
void GPXParser::trackpointData()
|
2015-10-05 01:43:48 +02:00
|
|
|
{
|
2016-10-27 00:20:00 +02:00
|
|
|
qreal gh = NAN;
|
|
|
|
|
2015-10-05 01:43:48 +02:00
|
|
|
while (_reader.readNextStartElement()) {
|
2016-06-20 23:56:42 +02:00
|
|
|
if (_reader.name() == "ele")
|
2016-10-27 00:20:00 +02:00
|
|
|
handleTrackpointData(Elevation);
|
2016-06-20 23:56:42 +02:00
|
|
|
else if (_reader.name() == "time")
|
2016-10-27 00:20:00 +02:00
|
|
|
handleTrackpointData(Time);
|
2016-06-20 23:56:42 +02:00
|
|
|
else if (_reader.name() == "geoidheight")
|
2016-10-27 00:20:00 +02:00
|
|
|
gh = number();
|
2015-10-15 01:30:21 +02:00
|
|
|
else if (_reader.name() == "extensions")
|
2016-02-08 17:53:09 +01:00
|
|
|
extensions();
|
2015-10-05 01:43:48 +02:00
|
|
|
else
|
|
|
|
_reader.skipCurrentElement();
|
|
|
|
}
|
|
|
|
|
2016-10-27 00:20:00 +02:00
|
|
|
Trackpoint &t = _track->last();
|
|
|
|
if (!std::isnan(gh) && !std::isnan(t.elevation()))
|
|
|
|
t.setElevation(t.elevation() - gh);
|
2016-08-09 01:16:19 +02:00
|
|
|
}
|
|
|
|
|
2016-10-27 00:20:00 +02:00
|
|
|
void GPXParser::waypointData(Waypoint &waypoint)
|
2016-10-23 11:09:20 +02:00
|
|
|
{
|
2016-10-27 00:20:00 +02:00
|
|
|
qreal gh = NAN;
|
|
|
|
|
2016-10-23 11:09:20 +02:00
|
|
|
while (_reader.readNextStartElement()) {
|
|
|
|
if (_reader.name() == "name")
|
2016-10-27 00:20:00 +02:00
|
|
|
handleWaypointData(Name, waypoint);
|
2016-10-23 11:09:20 +02:00
|
|
|
else if (_reader.name() == "desc")
|
2016-10-27 00:20:00 +02:00
|
|
|
handleWaypointData(Description, waypoint);
|
2016-10-23 11:09:20 +02:00
|
|
|
else if (_reader.name() == "ele")
|
2016-10-27 00:20:00 +02:00
|
|
|
handleWaypointData(Elevation, waypoint);
|
2016-10-23 11:09:20 +02:00
|
|
|
else if (_reader.name() == "geoidheight")
|
2016-10-27 00:20:00 +02:00
|
|
|
gh = number();
|
2016-10-23 11:09:20 +02:00
|
|
|
else if (_reader.name() == "time")
|
2016-10-27 00:20:00 +02:00
|
|
|
handleWaypointData(Time, waypoint);
|
2016-10-23 11:09:20 +02:00
|
|
|
else
|
|
|
|
_reader.skipCurrentElement();
|
|
|
|
}
|
2016-10-27 00:20:00 +02:00
|
|
|
|
|
|
|
if (!std::isnan(gh) && !std::isnan(waypoint.elevation()))
|
|
|
|
waypoint.setElevation(waypoint.elevation() - gh);
|
2016-10-23 11:09:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void GPXParser::trackpoints()
|
2015-10-05 01:43:48 +02:00
|
|
|
{
|
|
|
|
while (_reader.readNextStartElement()) {
|
|
|
|
if (_reader.name() == "trkpt") {
|
2016-10-27 00:20:00 +02:00
|
|
|
_track->append(Trackpoint(coordinates()));
|
2016-06-21 00:12:34 +02:00
|
|
|
trackpointData();
|
2015-10-05 01:43:48 +02:00
|
|
|
} else
|
|
|
|
_reader.skipCurrentElement();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-23 11:09:20 +02:00
|
|
|
void GPXParser::routepoints()
|
2016-08-09 01:16:19 +02:00
|
|
|
{
|
|
|
|
while (_reader.readNextStartElement()) {
|
|
|
|
if (_reader.name() == "rtept") {
|
2016-10-27 00:20:00 +02:00
|
|
|
_route->append(Waypoint(coordinates()));
|
|
|
|
waypointData(_route->last());
|
2016-08-09 01:16:19 +02:00
|
|
|
} else
|
|
|
|
_reader.skipCurrentElement();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-23 11:09:20 +02:00
|
|
|
void GPXParser::track()
|
2015-10-05 01:43:48 +02:00
|
|
|
{
|
|
|
|
while (_reader.readNextStartElement()) {
|
|
|
|
if (_reader.name() == "trkseg") {
|
2016-06-21 00:12:34 +02:00
|
|
|
trackpoints();
|
2015-10-05 01:43:48 +02:00
|
|
|
} else
|
|
|
|
_reader.skipCurrentElement();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-23 11:09:20 +02:00
|
|
|
void GPXParser::gpx()
|
2015-10-05 01:43:48 +02:00
|
|
|
{
|
|
|
|
while (_reader.readNextStartElement()) {
|
2016-02-08 17:53:09 +01:00
|
|
|
if (_reader.name() == "trk") {
|
2016-02-19 21:42:54 +01:00
|
|
|
_tracks.append(QVector<Trackpoint>());
|
2016-02-11 20:58:52 +01:00
|
|
|
_track = &_tracks.back();
|
2016-02-08 17:53:09 +01:00
|
|
|
track();
|
2016-08-09 01:16:19 +02:00
|
|
|
} else if (_reader.name() == "rte") {
|
|
|
|
_routes.append(QVector<Waypoint>());
|
|
|
|
_route = &_routes.back();
|
|
|
|
routepoints();
|
2016-02-11 20:58:52 +01:00
|
|
|
} else if (_reader.name() == "wpt") {
|
2016-10-27 00:20:00 +02:00
|
|
|
_waypoints.append(Waypoint(coordinates()));
|
|
|
|
waypointData(_waypoints.last());
|
2016-02-08 17:53:09 +01:00
|
|
|
} else
|
2015-10-05 01:43:48 +02:00
|
|
|
_reader.skipCurrentElement();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-23 11:09:20 +02:00
|
|
|
bool GPXParser::parse()
|
2015-10-05 01:43:48 +02:00
|
|
|
{
|
|
|
|
if (_reader.readNextStartElement()) {
|
|
|
|
if (_reader.name() == "gpx")
|
2016-02-08 17:53:09 +01:00
|
|
|
gpx();
|
2015-10-05 01:43:48 +02:00
|
|
|
else
|
2015-11-26 19:13:59 +01:00
|
|
|
_reader.raiseError("Not a GPX file.");
|
2015-10-05 01:43:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return !_reader.error();
|
|
|
|
}
|
|
|
|
|
2016-10-23 11:09:20 +02:00
|
|
|
bool GPXParser::loadFile(QIODevice *device)
|
2015-10-05 01:43:48 +02:00
|
|
|
{
|
|
|
|
_reader.clear();
|
|
|
|
_reader.setDevice(device);
|
|
|
|
|
2016-02-08 17:53:09 +01:00
|
|
|
return parse();
|
2015-10-05 01:43:48 +02:00
|
|
|
}
|