From b99def1b300cef4fc5843a86c8b215c5eb8a5d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Mon, 24 Oct 2016 20:00:29 +0200 Subject: [PATCH] Added support for KML files Fixed some minor parser issues --- src/kmlparser.cpp | 177 ++++++++++++++++++++++++++++++++++++++++++++++ src/kmlparser.h | 37 ++++++++++ 2 files changed, 214 insertions(+) create mode 100644 src/kmlparser.cpp create mode 100644 src/kmlparser.h diff --git a/src/kmlparser.cpp b/src/kmlparser.cpp new file mode 100644 index 00000000..78c7a2f8 --- /dev/null +++ b/src/kmlparser.cpp @@ -0,0 +1,177 @@ +#include "kmlparser.h" + + +bool KMLParser::pointCoordinates() +{ + 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, vp = sp; cp <= ep; cp++) { + if (*cp == ',' || 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 == 2) { + Waypoint w(Coordinates(val[0], val[1])); + w.setElevation(val[2]); + _waypoints.append(w); + } + + c++; + vp = cp + 1; + } + } + + return true; +} + +bool KMLParser::lineCoordinates() +{ + 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, vp = sp; cp <= ep; cp++) { + if (*cp == ',' || 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 == 2) { + Waypoint w(Coordinates(val[0], val[1])); + w.setElevation(val[2]); + _route->append(w); + } + + c++; + vp = cp + 1; + } + if (cp->isSpace()) { + if (c < 3) + return false; + while (cp->isSpace()) + cp++; + c = 0; + } + } + + return true; +} + +void KMLParser::lineString() +{ + while (_reader.readNextStartElement()) { + if (_reader.name() == "coordinates") { + _routes.append(QVector()); + _route = &_routes.back(); + if (!lineCoordinates()) + _reader.raiseError("Invalid coordinates."); + } else + _reader.skipCurrentElement(); + } +} + +void KMLParser::point() +{ + while (_reader.readNextStartElement()) { + if (_reader.name() == "coordinates") { + if (!pointCoordinates()) + _reader.raiseError("Invalid coordinates."); + } else + _reader.skipCurrentElement(); + } +} + +void KMLParser::multiGeometry() +{ + while (_reader.readNextStartElement()) { + if (_reader.name() == "Point") + point(); + else if (_reader.name() == "LineString") + lineString(); + else + _reader.skipCurrentElement(); + } +} + +void KMLParser::placemark() +{ + while (_reader.readNextStartElement()) { + if (_reader.name() == "Point") + point(); + else if (_reader.name() == "LineString") + lineString(); + else if (_reader.name() == "MultiGeometry") + multiGeometry(); + else + _reader.skipCurrentElement(); + } +} + +void KMLParser::document() +{ + while (_reader.readNextStartElement()) { + if (_reader.name() == "Placemark") + placemark(); + else + _reader.skipCurrentElement(); + } +} + +void KMLParser::kml() +{ + while (_reader.readNextStartElement()) { + if (_reader.name() == "Document") + document(); + else + _reader.skipCurrentElement(); + } +} + +bool KMLParser::parse() +{ + if (_reader.readNextStartElement()) { + if (_reader.name() == "kml") + kml(); + else + _reader.raiseError("Not a KML file."); + } + + return !_reader.error(); +} + +bool KMLParser::loadFile(QIODevice *device) +{ + _reader.clear(); + _reader.setDevice(device); + + return parse(); +} diff --git a/src/kmlparser.h b/src/kmlparser.h new file mode 100644 index 00000000..b27f348f --- /dev/null +++ b/src/kmlparser.h @@ -0,0 +1,37 @@ +#ifndef KMLPARSER_H +#define KMLPARSER_H + +#include +#include +#include "parser.h" + +class KMLParser : public Parser +{ +public: + KMLParser(QList > &tracks, + QList > &routes, QList &waypoints) + : Parser(tracks, routes, waypoints) {_track = 0; _route = 0;} + ~KMLParser() {} + + bool loadFile(QIODevice *device); + QString errorString() const {return _reader.errorString();} + int errorLine() const {return _reader.lineNumber();} + const char *name() const {return "KML";} + +private: + bool parse(); + void kml(); + void document(); + void placemark(); + void multiGeometry(); + void lineString(); + void point(); + bool pointCoordinates(); + bool lineCoordinates(); + + QXmlStreamReader _reader; + QVector *_track; + QVector *_route; +}; + +#endif // KMLPARSER_H