2016-10-24 20:00:29 +02:00
|
|
|
#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)
|
2016-10-24 20:00:29 +02:00
|
|
|
{
|
|
|
|
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)
|
2016-10-24 20:00:29 +02:00
|
|
|
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;
|
2016-10-24 20:00:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-10-28 14:33:36 +02:00
|
|
|
bool KMLParser::lineCoordinates(TrackData &track)
|
2016-10-24 20:00:29 +02:00
|
|
|
{
|
|
|
|
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)
|
2016-10-24 20:00:29 +02:00
|
|
|
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)
|
2016-10-24 20:00:29 +02:00
|
|
|
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;
|
|
|
|
|
2016-10-28 01:33:44 +02:00
|
|
|
track.append(Trackpoint(Coordinates(val[0], val[1])));
|
2016-10-28 19:12:40 +02:00
|
|
|
if (!track.last().coordinates().isValid())
|
|
|
|
return false;
|
2016-10-25 22:50:11 +02:00
|
|
|
if (c == 2)
|
2016-10-28 01:33:44 +02:00
|
|
|
track.last().setElevation(val[2]);
|
2016-10-25 22:50:11 +02:00
|
|
|
|
2016-10-24 20:00:29 +02:00
|
|
|
while (cp->isSpace())
|
|
|
|
cp++;
|
|
|
|
c = 0;
|
2016-10-25 22:50:11 +02:00
|
|
|
vp = cp;
|
2016-10-24 20:00:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-25 22:50:11 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-10-28 14:33:36 +02:00
|
|
|
QDateTime KMLParser::timeStamp()
|
2016-10-25 22:50:11 +02:00
|
|
|
{
|
2016-10-28 14:33:36 +02:00
|
|
|
QDateTime ts;
|
|
|
|
|
2016-10-25 22:50:11 +02:00
|
|
|
while (_reader.readNextStartElement()) {
|
2016-10-27 22:33:35 +02:00
|
|
|
if (_reader.name() == "when")
|
2016-10-28 14:33:36 +02:00
|
|
|
ts = time();
|
2016-10-27 22:33:35 +02:00
|
|
|
else
|
2016-10-25 22:50:11 +02:00
|
|
|
_reader.skipCurrentElement();
|
|
|
|
}
|
2016-10-28 14:33:36 +02:00
|
|
|
|
|
|
|
return ts;
|
2016-10-24 20:00:29 +02:00
|
|
|
}
|
|
|
|
|
2016-10-28 14:33:36 +02:00
|
|
|
void KMLParser::lineString(TrackData &track)
|
2016-10-24 20:00:29 +02:00
|
|
|
{
|
|
|
|
while (_reader.readNextStartElement()) {
|
|
|
|
if (_reader.name() == "coordinates") {
|
2016-10-28 01:33:44 +02:00
|
|
|
if (!lineCoordinates(track))
|
2016-10-29 12:22:28 +02:00
|
|
|
_reader.raiseError("Invalid coordinates");
|
2016-10-24 20:00:29 +02:00
|
|
|
} else
|
|
|
|
_reader.skipCurrentElement();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-27 22:33:35 +02:00
|
|
|
void KMLParser::point(Waypoint &waypoint)
|
2016-10-24 20:00:29 +02:00
|
|
|
{
|
|
|
|
while (_reader.readNextStartElement()) {
|
|
|
|
if (_reader.name() == "coordinates") {
|
2016-10-27 22:33:35 +02:00
|
|
|
if (!pointCoordinates(waypoint))
|
2016-10-29 12:22:28 +02:00
|
|
|
_reader.raiseError("Invalid coordinates");
|
2016-10-24 20:00:29 +02:00
|
|
|
} 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");
|
2016-10-24 20:00:29 +02:00
|
|
|
}
|
|
|
|
|
2016-11-08 20:50:42 +01:00
|
|
|
void KMLParser::track(TrackData &track)
|
2016-10-28 19:12:40 +02:00
|
|
|
{
|
2016-10-29 12:22:28 +02:00
|
|
|
const char mismatchError[] = "gx:coord/when element count mismatch";
|
2016-10-28 19:12:40 +02:00
|
|
|
int i = track.size();
|
|
|
|
|
|
|
|
while (_reader.readNextStartElement()) {
|
|
|
|
if (_reader.name() == "when") {
|
|
|
|
track.append(Trackpoint());
|
|
|
|
track.last().setTimestamp(time());
|
|
|
|
} else if (_reader.name() == "coord") {
|
|
|
|
if (i == track.size()) {
|
|
|
|
_reader.raiseError(mismatchError);
|
|
|
|
return;
|
|
|
|
} else if (!coord(track[i])) {
|
2016-10-29 12:22:28 +02:00
|
|
|
_reader.raiseError("Invalid coordinates");
|
2016-10-28 19:12:40 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
} else
|
|
|
|
_reader.skipCurrentElement();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i != track.size())
|
|
|
|
_reader.raiseError(mismatchError);
|
|
|
|
}
|
|
|
|
|
2016-11-08 20:50:42 +01:00
|
|
|
void KMLParser::multiGeometry(const QString &name, const QString &desc,
|
|
|
|
const QDateTime timestamp)
|
|
|
|
{
|
|
|
|
while (_reader.readNextStartElement()) {
|
|
|
|
if (_reader.name() == "Point") {
|
|
|
|
_waypoints.append(Waypoint());
|
|
|
|
Waypoint &w = _waypoints.last();
|
|
|
|
w.setName(name);
|
|
|
|
w.setDescription(desc);
|
|
|
|
w.setTimestamp(timestamp);
|
|
|
|
point(w);
|
|
|
|
} else if (_reader.name() == "LineString") {
|
|
|
|
_tracks.append(TrackData());
|
|
|
|
TrackData &t = _tracks.last();
|
|
|
|
t.setName(name);
|
|
|
|
t.setDescription(desc);
|
|
|
|
lineString(t);
|
|
|
|
} else
|
|
|
|
_reader.skipCurrentElement();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-24 20:00:29 +02:00
|
|
|
void KMLParser::placemark()
|
|
|
|
{
|
2016-10-28 14:33:36 +02:00
|
|
|
QString name, desc;
|
|
|
|
QDateTime timestamp;
|
2016-10-25 22:50:11 +02:00
|
|
|
|
2016-10-24 20:00:29 +02:00
|
|
|
while (_reader.readNextStartElement()) {
|
2016-10-25 22:50:11 +02:00
|
|
|
if (_reader.name() == "name")
|
2016-10-28 14:33:36 +02:00
|
|
|
name = _reader.readElementText();
|
2016-10-25 22:50:11 +02:00
|
|
|
else if (_reader.name() == "description")
|
2016-10-28 14:33:36 +02:00
|
|
|
desc = _reader.readElementText();
|
2016-10-25 22:50:11 +02:00
|
|
|
else if (_reader.name() == "TimeStamp")
|
2016-10-28 14:33:36 +02:00
|
|
|
timestamp = timeStamp();
|
2016-11-08 20:50:42 +01:00
|
|
|
else if (_reader.name() == "MultiGeometry")
|
|
|
|
multiGeometry(name, desc, timestamp);
|
2016-10-27 22:33:35 +02:00
|
|
|
else if (_reader.name() == "Point") {
|
2016-10-28 14:33:36 +02:00
|
|
|
_waypoints.append(Waypoint());
|
2016-11-08 20:50:42 +01:00
|
|
|
Waypoint &w = _waypoints.last();
|
|
|
|
w.setName(name);
|
|
|
|
w.setDescription(desc);
|
|
|
|
w.setTimestamp(timestamp);
|
|
|
|
point(w);
|
2016-10-27 22:33:35 +02:00
|
|
|
} else if (_reader.name() == "LineString") {
|
2016-10-28 14:33:36 +02:00
|
|
|
_tracks.append(TrackData());
|
2016-11-08 20:50:42 +01:00
|
|
|
TrackData &t = _tracks.last();
|
|
|
|
t.setName(name);
|
|
|
|
t.setDescription(desc);
|
|
|
|
lineString(t);
|
2016-10-28 19:12:40 +02:00
|
|
|
} else if (_reader.name() == "Track") {
|
|
|
|
_tracks.append(TrackData());
|
2016-11-08 20:50:42 +01:00
|
|
|
TrackData &t = _tracks.last();
|
|
|
|
t.setName(name);
|
|
|
|
t.setDescription(desc);
|
|
|
|
track(t);
|
2016-10-27 22:33:35 +02:00
|
|
|
} else
|
2016-10-25 22:50:11 +02:00
|
|
|
_reader.skipCurrentElement();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMLParser::folder()
|
|
|
|
{
|
|
|
|
while (_reader.readNextStartElement()) {
|
|
|
|
if (_reader.name() == "Placemark")
|
|
|
|
placemark();
|
2016-10-26 08:23:18 +02:00
|
|
|
else if (_reader.name() == "Folder")
|
|
|
|
folder();
|
2016-10-24 20:00:29 +02:00
|
|
|
else
|
|
|
|
_reader.skipCurrentElement();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMLParser::document()
|
|
|
|
{
|
|
|
|
while (_reader.readNextStartElement()) {
|
|
|
|
if (_reader.name() == "Placemark")
|
|
|
|
placemark();
|
2016-10-25 22:50:11 +02:00
|
|
|
else if (_reader.name() == "Folder")
|
|
|
|
folder();
|
2016-10-24 20:00:29 +02:00
|
|
|
else
|
|
|
|
_reader.skipCurrentElement();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMLParser::kml()
|
|
|
|
{
|
|
|
|
while (_reader.readNextStartElement()) {
|
|
|
|
if (_reader.name() == "Document")
|
|
|
|
document();
|
2016-10-26 09:01:35 +02:00
|
|
|
else if (_reader.name() == "Placemark")
|
|
|
|
placemark();
|
2016-10-24 20:00:29 +02:00
|
|
|
else
|
|
|
|
_reader.skipCurrentElement();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KMLParser::parse()
|
|
|
|
{
|
|
|
|
if (_reader.readNextStartElement()) {
|
|
|
|
if (_reader.name() == "kml")
|
|
|
|
kml();
|
|
|
|
else
|
2016-10-29 12:22:28 +02:00
|
|
|
_reader.raiseError("Not a KML file");
|
2016-10-24 20:00:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return !_reader.error();
|
|
|
|
}
|
|
|
|
|
2016-10-29 10:40:30 +02:00
|
|
|
bool KMLParser::loadFile(QFile *file)
|
2016-10-24 20:00:29 +02:00
|
|
|
{
|
|
|
|
_reader.clear();
|
2016-10-29 10:40:30 +02:00
|
|
|
_reader.setDevice(file);
|
2016-10-24 20:00:29 +02:00
|
|
|
|
|
|
|
return parse();
|
|
|
|
}
|