1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-28 13:41:16 +01:00
GPXSee/src/data/kmlparser.cpp

629 lines
14 KiB
C++
Raw Normal View History

#include "kmlparser.h"
2016-10-27 22:33:35 +02:00
qreal KMLParser::number()
{
bool res;
qreal ret = _reader.readElementText().toDouble(&res);
if (!res)
2016-10-29 12:22:28 +02:00
_reader.raiseError(QString("Invalid %1").arg(
2016-10-27 22:33:35 +02:00
_reader.name().toString()));
return ret;
}
QDateTime KMLParser::time()
{
QDateTime d = QDateTime::fromString(_reader.readElementText(),
Qt::ISODate);
if (!d.isValid())
2016-10-29 12:22:28 +02:00
_reader.raiseError(QString("Invalid %1").arg(
2016-10-27 22:33:35 +02:00
_reader.name().toString()));
return d;
}
2016-10-28 19:12:40 +02:00
bool KMLParser::coord(Trackpoint &trackpoint)
{
QString data = _reader.readElementText();
const QChar *sp, *ep, *cp, *vp;
int c = 0;
qreal val[3];
bool res;
sp = data.constData();
ep = sp + data.size();
for (cp = sp; cp < ep; cp++)
if (!cp->isSpace())
break;
for (vp = cp; cp <= ep; cp++) {
if (cp->isSpace() || cp->isNull()) {
if (c > 2)
return false;
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
val[c] = QString(vp, cp - vp).toDouble(&res);
#else // QT_VERSION < 5
val[c] = QStringRef(&data, vp - sp, cp - vp).toDouble(&res);
#endif // QT_VERSION < 5
if (!res)
return false;
if (c == 1) {
trackpoint.setCoordinates(Coordinates(val[0], val[1]));
if (!trackpoint.coordinates().isValid())
return false;
} else if (c == 2)
trackpoint.setElevation(val[2]);
while (cp->isSpace())
cp++;
vp = cp;
c++;
}
}
return true;
}
2016-10-27 22:33:35 +02:00
bool KMLParser::pointCoordinates(Waypoint &waypoint)
{
QString data = _reader.readElementText();
const QChar *sp, *ep, *cp, *vp;
int c = 0;
qreal val[3];
bool res;
sp = data.constData();
ep = sp + data.size();
2016-10-25 22:50:11 +02:00
for (cp = sp; cp < ep; cp++)
if (!cp->isSpace())
break;
for (vp = cp; cp <= ep; cp++) {
if (*cp == ',') {
2016-11-11 22:04:26 +01:00
if (c > 1)
return false;
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
val[c] = QString(vp, cp - vp).toDouble(&res);
#else // QT_VERSION < 5
val[c] = QStringRef(&data, vp - sp, cp - vp).toDouble(&res);
#endif // QT_VERSION < 5
if (!res)
return false;
c++;
vp = cp + 1;
2016-10-25 22:50:11 +02:00
} else if (cp->isSpace() || cp->isNull()) {
if (c < 1)
return false;
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
val[c] = QString(vp, cp - vp).toDouble(&res);
#else // QT_VERSION < 5
val[c] = QStringRef(&data, vp - sp, cp - vp).toDouble(&res);
#endif // QT_VERSION < 5
if (!res)
return false;
2016-10-27 22:33:35 +02:00
waypoint.setCoordinates(Coordinates(val[0], val[1]));
2016-10-28 19:12:40 +02:00
if (!waypoint.coordinates().isValid())
return false;
2016-10-25 22:50:11 +02:00
if (c == 2)
2016-10-27 22:33:35 +02:00
waypoint.setElevation(val[2]);
2016-10-25 22:50:11 +02:00
while (cp->isSpace())
cp++;
c = 3;
}
}
return true;
}
2019-02-11 23:28:08 +01:00
bool KMLParser::lineCoordinates(SegmentData &segment)
{
QString data = _reader.readElementText();
const QChar *sp, *ep, *cp, *vp;
int c = 0;
qreal val[3];
bool res;
sp = data.constData();
ep = sp + data.size();
2016-10-25 22:50:11 +02:00
for (cp = sp; cp < ep; cp++)
if (!cp->isSpace())
break;
for (vp = cp; cp <= ep; cp++) {
if (*cp == ',') {
2016-11-11 22:04:26 +01:00
if (c > 1)
return false;
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
val[c] = QString(vp, cp - vp).toDouble(&res);
#else // QT_VERSION < 5
val[c] = QStringRef(&data, vp - sp, cp - vp).toDouble(&res);
#endif // QT_VERSION < 5
if (!res)
return false;
c++;
vp = cp + 1;
2016-10-25 22:50:11 +02:00
} else if (cp->isSpace() || cp->isNull()) {
if (c < 1 || c > 2)
return false;
2016-10-25 22:50:11 +02:00
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
val[c] = QString(vp, cp - vp).toDouble(&res);
#else // QT_VERSION < 5
val[c] = QStringRef(&data, vp - sp, cp - vp).toDouble(&res);
#endif // QT_VERSION < 5
if (!res)
return false;
2019-02-11 23:28:08 +01:00
segment.append(Trackpoint(Coordinates(val[0], val[1])));
if (!segment.last().coordinates().isValid())
2016-10-28 19:12:40 +02:00
return false;
2016-10-25 22:50:11 +02:00
if (c == 2)
2019-02-11 23:28:08 +01:00
segment.last().setElevation(val[2]);
2016-10-25 22:50:11 +02:00
while (cp->isSpace())
cp++;
c = 0;
2016-10-25 22:50:11 +02:00
vp = cp;
}
}
2016-10-25 22:50:11 +02:00
return true;
}
2019-01-31 01:46:53 +01:00
bool KMLParser::polygonCoordinates(QVector<Coordinates> &points)
{
QString data = _reader.readElementText();
const QChar *sp, *ep, *cp, *vp;
int c = 0;
qreal val[3];
bool res;
sp = data.constData();
ep = sp + data.size();
for (cp = sp; cp < ep; cp++)
if (!cp->isSpace())
break;
for (vp = cp; cp <= ep; cp++) {
if (*cp == ',') {
if (c > 1)
return false;
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
val[c] = QString(vp, cp - vp).toDouble(&res);
#else // QT_VERSION < 5
val[c] = QStringRef(&data, vp - sp, cp - vp).toDouble(&res);
#endif // QT_VERSION < 5
if (!res)
return false;
c++;
vp = cp + 1;
} else if (cp->isSpace() || cp->isNull()) {
if (c < 1 || c > 2)
return false;
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
val[c] = QString(vp, cp - vp).toDouble(&res);
#else // QT_VERSION < 5
val[c] = QStringRef(&data, vp - sp, cp - vp).toDouble(&res);
#endif // QT_VERSION < 5
if (!res)
return false;
points.append(Coordinates(val[0], val[1]));
if (!points.last().isValid())
return false;
while (cp->isSpace())
cp++;
c = 0;
vp = cp;
}
}
return true;
}
QDateTime KMLParser::timeStamp()
2016-10-25 22:50:11 +02:00
{
QDateTime ts;
2016-10-25 22:50:11 +02:00
while (_reader.readNextStartElement()) {
2018-08-27 22:25:55 +02:00
if (_reader.name() == QLatin1String("when"))
ts = time();
2016-10-27 22:33:35 +02:00
else
2016-10-25 22:50:11 +02:00
_reader.skipCurrentElement();
}
return ts;
}
2019-02-11 23:28:08 +01:00
void KMLParser::lineString(SegmentData &segment)
{
while (_reader.readNextStartElement()) {
2018-08-27 22:25:55 +02:00
if (_reader.name() == QLatin1String("coordinates")) {
2019-02-11 23:28:08 +01:00
if (!lineCoordinates(segment))
2016-10-29 12:22:28 +02:00
_reader.raiseError("Invalid coordinates");
} else
_reader.skipCurrentElement();
}
}
2019-01-31 01:46:53 +01:00
void KMLParser::linearRing(QVector<Coordinates> &coordinates)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("coordinates")) {
if (!polygonCoordinates(coordinates))
_reader.raiseError("Invalid coordinates");
} else
_reader.skipCurrentElement();
}
}
void KMLParser::boundary(QVector<Coordinates> &coordinates)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("LinearRing"))
linearRing(coordinates);
else
_reader.skipCurrentElement();
}
}
void KMLParser::polygon(Area &area)
{
area.append(Polygon());
Polygon &polygon = area.last();
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("outerBoundaryIs")) {
2019-02-01 00:25:41 +01:00
if (!polygon.isEmpty()) {
2019-01-31 01:46:53 +01:00
_reader.raiseError("Multiple polygon outerBoundaryIss");
return;
}
polygon.append(QVector<Coordinates>());
boundary(polygon.last());
} else if (_reader.name() == QLatin1String("innerBoundaryIs")) {
2019-02-01 00:25:41 +01:00
if (polygon.isEmpty()) {
2019-01-31 01:46:53 +01:00
_reader.raiseError("Missing polygon outerBoundaryIs");
return;
}
polygon.append(QVector<Coordinates>());
boundary(polygon.last());
} else
_reader.skipCurrentElement();
}
}
2016-10-27 22:33:35 +02:00
void KMLParser::point(Waypoint &waypoint)
{
while (_reader.readNextStartElement()) {
2018-08-27 22:25:55 +02:00
if (_reader.name() == QLatin1String("coordinates")) {
2016-10-27 22:33:35 +02:00
if (!pointCoordinates(waypoint))
2016-10-29 12:22:28 +02:00
_reader.raiseError("Invalid coordinates");
} else
_reader.skipCurrentElement();
}
2016-10-29 10:40:30 +02:00
if (waypoint.coordinates().isNull())
2016-10-29 12:22:28 +02:00
_reader.raiseError("Missing Point coordinates");
}
2019-02-11 23:28:08 +01:00
void KMLParser::heartRate(SegmentData &segment, int start)
{
int i = start;
const char error[] = "Heartrate data count mismatch";
while (_reader.readNextStartElement()) {
2018-08-27 22:25:55 +02:00
if (_reader.name() == QLatin1String("value")) {
2019-02-11 23:28:08 +01:00
if (i < segment.size())
segment[i++].setHeartRate(number());
else {
_reader.raiseError(error);
return;
}
} else
_reader.skipCurrentElement();
}
2019-02-11 23:28:08 +01:00
if (i != segment.size())
_reader.raiseError(error);
}
2019-02-11 23:28:08 +01:00
void KMLParser::cadence(SegmentData &segment, int start)
{
int i = start;
const char error[] = "Cadence data count mismatch";
while (_reader.readNextStartElement()) {
2018-08-27 22:25:55 +02:00
if (_reader.name() == QLatin1String("value")) {
2019-02-11 23:28:08 +01:00
if (i < segment.size())
segment[i++].setCadence(number());
else {
_reader.raiseError(error);
return;
}
} else
_reader.skipCurrentElement();
}
2019-02-11 23:28:08 +01:00
if (i != segment.size())
_reader.raiseError(error);
}
2019-02-11 23:28:08 +01:00
void KMLParser::speed(SegmentData &segment, int start)
{
int i = start;
const char error[] = "Speed data count mismatch";
while (_reader.readNextStartElement()) {
2018-08-27 22:25:55 +02:00
if (_reader.name() == QLatin1String("value")) {
2019-02-11 23:28:08 +01:00
if (i < segment.size())
segment[i++].setSpeed(number());
else {
_reader.raiseError(error);
return;
}
} else
_reader.skipCurrentElement();
}
2019-02-11 23:28:08 +01:00
if (i != segment.size())
_reader.raiseError(error);
}
2019-02-11 23:28:08 +01:00
void KMLParser::temperature(SegmentData &segment, int start)
{
int i = start;
const char error[] = "Temperature data count mismatch";
while (_reader.readNextStartElement()) {
2018-08-27 22:25:55 +02:00
if (_reader.name() == QLatin1String("value")) {
2019-02-11 23:28:08 +01:00
if (i < segment.size())
segment[i++].setTemperature(number());
else {
_reader.raiseError(error);
return;
}
} else
_reader.skipCurrentElement();
}
2019-02-11 23:28:08 +01:00
if (i != segment.size())
_reader.raiseError(error);
}
2019-02-11 23:28:08 +01:00
void KMLParser::schemaData(SegmentData &segment, int start)
{
while (_reader.readNextStartElement()) {
2018-08-27 22:25:55 +02:00
if (_reader.name() == QLatin1String("SimpleArrayData")) {
QXmlStreamAttributes attr = _reader.attributes();
QStringRef name = attr.value("name");
2018-08-27 22:25:55 +02:00
if (name == QLatin1String("Heartrate"))
2019-02-11 23:28:08 +01:00
heartRate(segment, start);
2018-08-27 22:25:55 +02:00
else if (name == QLatin1String("Cadence"))
2019-02-11 23:28:08 +01:00
cadence(segment, start);
2018-08-27 22:25:55 +02:00
else if (name == QLatin1String("Speed"))
2019-02-11 23:28:08 +01:00
speed(segment, start);
2018-08-27 22:25:55 +02:00
else if (name == QLatin1String("Temperature"))
2019-02-11 23:28:08 +01:00
temperature(segment, start);
else
_reader.skipCurrentElement();
} else
_reader.skipCurrentElement();
}
}
2019-02-11 23:28:08 +01:00
void KMLParser::extendedData(SegmentData &segment, int start)
{
while (_reader.readNextStartElement()) {
2018-08-27 22:25:55 +02:00
if (_reader.name() == QLatin1String("SchemaData"))
2019-02-11 23:28:08 +01:00
schemaData(segment, start);
else
_reader.skipCurrentElement();
}
}
2019-02-11 23:28:08 +01:00
void KMLParser::track(SegmentData &segment)
2016-10-28 19:12:40 +02:00
{
const char error[] = "gx:coord/when element count mismatch";
2019-02-11 23:28:08 +01:00
int first = segment.size();
int i = first;
2016-10-28 19:12:40 +02:00
while (_reader.readNextStartElement()) {
2018-08-27 22:25:55 +02:00
if (_reader.name() == QLatin1String("when")) {
2019-02-11 23:28:08 +01:00
segment.append(Trackpoint());
segment.last().setTimestamp(time());
2018-08-27 22:25:55 +02:00
} else if (_reader.name() == QLatin1String("coord")) {
2019-02-11 23:28:08 +01:00
if (i == segment.size()) {
_reader.raiseError(error);
2016-10-28 19:12:40 +02:00
return;
2019-02-11 23:28:08 +01:00
} else if (!coord(segment[i])) {
2016-10-29 12:22:28 +02:00
_reader.raiseError("Invalid coordinates");
2016-10-28 19:12:40 +02:00
return;
}
i++;
2018-08-27 22:25:55 +02:00
} else if (_reader.name() == QLatin1String("ExtendedData"))
2019-02-11 23:28:08 +01:00
extendedData(segment, first);
else
2016-10-28 19:12:40 +02:00
_reader.skipCurrentElement();
}
2019-02-11 23:28:08 +01:00
if (i != segment.size())
_reader.raiseError(error);
2016-10-28 19:12:40 +02:00
}
void KMLParser::multiTrack(TrackData &t)
{
while (_reader.readNextStartElement()) {
2019-02-11 23:28:08 +01:00
if (_reader.name() == QLatin1String("Track")) {
t.append(SegmentData());
track(t.last());
} else
_reader.skipCurrentElement();
}
}
2019-01-31 01:46:53 +01:00
void KMLParser::multiGeometry(QList<TrackData> &tracks, QList<Area> &areas,
2019-01-18 00:17:28 +01:00
QVector<Waypoint> &waypoints, const QString &name, const QString &desc,
const QDateTime timestamp)
{
while (_reader.readNextStartElement()) {
2018-08-27 22:25:55 +02:00
if (_reader.name() == QLatin1String("Point")) {
2017-07-27 19:47:46 +02:00
waypoints.append(Waypoint());
Waypoint &w = waypoints.last();
w.setName(name);
w.setDescription(desc);
w.setTimestamp(timestamp);
point(w);
2018-08-27 22:25:55 +02:00
} else if (_reader.name() == QLatin1String("LineString")) {
2017-07-27 19:47:46 +02:00
tracks.append(TrackData());
TrackData &t = tracks.last();
2019-02-11 23:28:08 +01:00
t.append(SegmentData());
t.setName(name);
t.setDescription(desc);
2019-02-11 23:28:08 +01:00
lineString(t.last());
2019-01-31 01:46:53 +01:00
} else if (_reader.name() == QLatin1String("Polygon")) {
areas.append(Area());
Area &a = areas.last();
a.setName(name);
a.setDescription(desc);
polygon(a);
} else
_reader.skipCurrentElement();
}
}
2019-01-31 01:46:53 +01:00
void KMLParser::placemark(QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints)
{
QString name, desc;
QDateTime timestamp;
2016-10-25 22:50:11 +02:00
while (_reader.readNextStartElement()) {
2018-08-27 22:25:55 +02:00
if (_reader.name() == QLatin1String("name"))
name = _reader.readElementText();
2018-08-27 22:25:55 +02:00
else if (_reader.name() == QLatin1String("description"))
desc = _reader.readElementText();
2018-08-27 22:25:55 +02:00
else if (_reader.name() == QLatin1String("TimeStamp"))
timestamp = timeStamp();
2018-08-27 22:25:55 +02:00
else if (_reader.name() == QLatin1String("MultiGeometry"))
2019-01-31 01:46:53 +01:00
multiGeometry(tracks, areas, waypoints, name, desc, timestamp);
2018-08-27 22:25:55 +02:00
else if (_reader.name() == QLatin1String("Point")) {
2017-07-27 19:47:46 +02:00
waypoints.append(Waypoint());
Waypoint &w = waypoints.last();
w.setName(name);
w.setDescription(desc);
w.setTimestamp(timestamp);
point(w);
2018-08-27 22:25:55 +02:00
} else if (_reader.name() == QLatin1String("LineString")
|| _reader.name() == QLatin1String("LinearRing")) {
2017-07-27 19:47:46 +02:00
tracks.append(TrackData());
TrackData &t = tracks.last();
2019-02-11 23:28:08 +01:00
t.append(SegmentData());
t.setName(name);
t.setDescription(desc);
2019-02-11 23:28:08 +01:00
lineString(t.last());
2018-08-27 22:25:55 +02:00
} else if (_reader.name() == QLatin1String("Track")) {
2017-07-27 19:47:46 +02:00
tracks.append(TrackData());
TrackData &t = tracks.last();
2019-02-11 23:28:08 +01:00
t.append(SegmentData());
t.setName(name);
t.setDescription(desc);
2019-02-11 23:28:08 +01:00
track(t.last());
2018-08-27 22:25:55 +02:00
} else if (_reader.name() == QLatin1String("MultiTrack")) {
tracks.append(TrackData());
TrackData &t = tracks.last();
t.setName(name);
t.setDescription(desc);
multiTrack(t);
2019-01-31 01:46:53 +01:00
} else if (_reader.name() == QLatin1String("Polygon")) {
areas.append(Area());
Area &a = areas.last();
a.setName(name);
a.setDescription(desc);
polygon(a);
2016-10-27 22:33:35 +02:00
} else
2016-10-25 22:50:11 +02:00
_reader.skipCurrentElement();
}
}
2019-01-31 01:46:53 +01:00
void KMLParser::folder(QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints)
2016-10-25 22:50:11 +02:00
{
while (_reader.readNextStartElement()) {
2018-08-27 22:25:55 +02:00
if (_reader.name() == QLatin1String("Placemark"))
2019-01-31 01:46:53 +01:00
placemark(tracks, areas, waypoints);
2018-08-27 22:25:55 +02:00
else if (_reader.name() == QLatin1String("Folder"))
2019-01-31 01:46:53 +01:00
folder(tracks, areas, waypoints);
else
_reader.skipCurrentElement();
}
}
2019-01-31 01:46:53 +01:00
void KMLParser::document(QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints)
{
while (_reader.readNextStartElement()) {
2018-08-27 22:25:55 +02:00
if (_reader.name() == QLatin1String("Placemark"))
2019-01-31 01:46:53 +01:00
placemark(tracks, areas, waypoints);
2018-08-27 22:25:55 +02:00
else if (_reader.name() == QLatin1String("Folder"))
2019-01-31 01:46:53 +01:00
folder(tracks, areas, waypoints);
else
_reader.skipCurrentElement();
}
}
2019-01-31 01:46:53 +01:00
void KMLParser::kml(QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints)
{
while (_reader.readNextStartElement()) {
2018-08-27 22:25:55 +02:00
if (_reader.name() == QLatin1String("Document"))
2019-01-31 01:46:53 +01:00
document(tracks, areas, waypoints);
2018-08-27 22:25:55 +02:00
else if (_reader.name() == QLatin1String("Placemark"))
2019-01-31 01:46:53 +01:00
placemark(tracks, areas, waypoints);
2018-08-27 22:25:55 +02:00
else if (_reader.name() == QLatin1String("Folder"))
2019-01-31 01:46:53 +01:00
folder(tracks, areas, waypoints);
else
_reader.skipCurrentElement();
}
}
2017-07-27 19:47:46 +02:00
bool KMLParser::parse(QFile *file, QList<TrackData> &tracks,
2019-01-31 01:46:53 +01:00
QList<RouteData> &routes, QList<Area> &areas, QVector<Waypoint> &waypoints)
{
2017-07-27 19:47:46 +02:00
Q_UNUSED(routes);
_reader.clear();
_reader.setDevice(file);
if (_reader.readNextStartElement()) {
2018-08-27 22:25:55 +02:00
if (_reader.name() == QLatin1String("kml"))
2019-01-31 01:46:53 +01:00
kml(tracks, areas, waypoints);
else
2016-10-29 12:22:28 +02:00
_reader.raiseError("Not a KML file");
}
return !_reader.error();
}