1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-12-01 07:01:16 +01:00
GPXSee/src/data/geojsonparser.cpp

354 lines
10 KiB
C++
Raw Normal View History

2019-01-25 22:18:21 +01:00
#include <QJsonDocument>
#include <QJsonArray>
#include "geojsonparser.h"
2019-01-31 01:46:53 +01:00
GeoJSONParser::Type GeoJSONParser::type(const QJsonObject &json)
2019-01-25 22:18:21 +01:00
{
QString str(json["type"].toString());
if (str == "Point")
return Point;
else if (str == "MultiPoint")
return MultiPoint;
else if (str == "LineString")
return LineString;
else if (str == "MultiLineString")
return MultiLineString;
else if (str == "Polygon")
return Polygon;
else if (str == "MultiPolygon")
return MultiPolygon;
else if (str == "GeometryCollection")
return GeometryCollection;
else if (str == "Feature")
return Feature;
else if (str == "FeatureCollection")
return FeatureCollection;
else
return Unknown;
}
bool GeoJSONParser::point(const QJsonArray &coordinates, Waypoint &waypoint,
const QJsonObject &properties)
{
if (coordinates.count() < 2 || !coordinates.at(0).isDouble()
|| !coordinates.at(1).isDouble()) {
_errorString = "Invalid Point Coordinates";
return false;
}
waypoint.setCoordinates(Coordinates(coordinates.at(0).toDouble(),
coordinates.at(1).toDouble()));
if (coordinates.count() == 3 && coordinates.at(2).isDouble())
waypoint.setElevation(coordinates.at(2).toDouble());
if (properties.contains("title") && properties["title"].isString())
waypoint.setName(properties["title"].toString());
2019-01-31 01:46:53 +01:00
if (properties.contains("name") && properties["name"].isString())
waypoint.setName(properties["name"].toString());
2019-01-25 22:18:21 +01:00
if (properties.contains("description")
&& properties["description"].isString())
waypoint.setDescription(properties["description"].toString());
return true;
}
bool GeoJSONParser::multiPoint(const QJsonArray &coordinates,
QVector<Waypoint> &waypoints, const QJsonObject &properties)
{
for (int i = 0; i < coordinates.size(); i++) {
if (!coordinates.at(i).isArray()) {
2019-01-31 01:46:53 +01:00
_errorString = "Invalid MultiPoint coordinates";
2019-01-25 22:18:21 +01:00
return false;
} else {
waypoints.resize(waypoints.size() + 1);
if (!point(coordinates.at(i).toArray(), waypoints.last(), properties))
return false;
}
}
return true;
}
bool GeoJSONParser::lineString(const QJsonArray &coordinates, TrackData &track,
const QJsonObject &properties)
{
if (properties.contains("title") && properties["title"].isString())
track.setName(properties["title"].toString());
2019-01-31 01:46:53 +01:00
if (properties.contains("name") && properties["name"].isString())
track.setName(properties["name"].toString());
2019-01-25 22:18:21 +01:00
if (properties.contains("description")
&& properties["description"].isString())
track.setDescription(properties["description"].toString());
for (int i = 0; i < coordinates.size(); i++) {
QJsonArray point(coordinates.at(i).toArray());
if (point.count() < 2 || !point.at(0).isDouble()
|| !point.at(1).isDouble()) {
2019-01-31 01:46:53 +01:00
_errorString = "Invalid LineString coordinates";
2019-01-25 22:18:21 +01:00
return false;
}
Trackpoint t(Coordinates(point.at(0).toDouble(),
point.at(1).toDouble()));
if (point.count() == 3 && point.at(2).isDouble())
t.setElevation(point.at(2).toDouble());
track.append(t);
}
return true;
}
bool GeoJSONParser::multiLineString(const QJsonArray &coordinates,
QList<TrackData> &tracks, const QJsonObject &properties)
{
for (int i = 0; i < coordinates.size(); i++) {
if (!coordinates.at(i).isArray()) {
2019-01-31 01:46:53 +01:00
_errorString = "Invalid MultiLineString coordinates";
2019-01-25 22:18:21 +01:00
return false;
} else {
tracks.append(TrackData());
if (!lineString(coordinates.at(i).toArray(), tracks.last(),
properties))
return false;
}
}
return true;
}
2019-01-31 01:46:53 +01:00
bool GeoJSONParser::polygon(const QJsonArray &coordinates, ::Polygon &pg)
{
for (int i = 0; i < coordinates.size(); i++) {
if (!coordinates.at(i).isArray()) {
_errorString = "Invalid Polygon linear ring";
return false;
}
const QJsonArray lr(coordinates.at(i).toArray());
pg.append(QVector<Coordinates>());
QVector<Coordinates> &data = pg.last();
for (int j = 0; j < lr.size(); j++) {
QJsonArray point(lr.at(j).toArray());
if (point.count() < 2 || !point.at(0).isDouble()
|| !point.at(1).isDouble()) {
_errorString = "Invalid Polygon linear ring coordinates";
return false;
}
data.append(Coordinates(point.at(0).toDouble(),
point.at(1).toDouble()));
}
}
return true;
}
bool GeoJSONParser::polygon(const QJsonArray &coordinates, Area &area,
2019-01-25 22:18:21 +01:00
const QJsonObject &properties)
2019-01-31 01:46:53 +01:00
{
if (properties.contains("title") && properties["title"].isString())
area.setName(properties["title"].toString());
if (properties.contains("name") && properties["name"].isString())
area.setName(properties["name"].toString());
if (properties.contains("description")
&& properties["description"].isString())
area.setDescription(properties["description"].toString());
area.append(::Polygon());
return polygon(coordinates, area.last());
}
bool GeoJSONParser::multiPolygon(const QJsonArray &coordinates,
Area &area, const QJsonObject &properties)
{
if (properties.contains("title") && properties["title"].isString())
area.setName(properties["title"].toString());
if (properties.contains("name") && properties["name"].isString())
area.setName(properties["name"].toString());
if (properties.contains("description")
&& properties["description"].isString())
area.setDescription(properties["description"].toString());
for (int i = 0; i < coordinates.size(); i++) {
if (!coordinates.at(i).isArray()) {
_errorString = "Invalid MultiPolygon coordinates";
return false;
} else {
area.append(::Polygon());
if (!polygon(coordinates.at(i).toArray(), area.last()))
return false;
}
}
return true;
}
bool GeoJSONParser::geometryCollection(const QJsonObject &json,
QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints, const QJsonObject &properties)
2019-01-25 22:18:21 +01:00
{
if (!json.contains("geometries") || !json["geometries"].isArray()) {
_errorString = "Invalid/missing GeometryCollection geometries array";
return false;
}
QJsonArray geometries(json["geometries"].toArray());
for (int i = 0; i < geometries.size(); i++) {
QJsonObject geometry(geometries.at(i).toObject());
switch (type(geometry)) {
case Point:
waypoints.resize(waypoints.size() + 1);
if (!point(geometry["coordinates"].toArray(), waypoints.last(),
properties))
return false;
break;
case MultiPoint:
if (!multiPoint(geometry["coordinates"].toArray(), waypoints,
properties))
return false;
break;
case LineString:
tracks.append(TrackData());
if (!lineString(geometry["coordinates"].toArray(),
tracks.last(), properties))
return false;
break;
case MultiLineString:
if (!multiLineString(geometry["coordinates"].toArray(), tracks,
properties))
return false;
break;
case Polygon:
2019-01-31 01:46:53 +01:00
areas.append(Area());
if (!polygon(geometry["coordinates"].toArray(), areas.last(),
properties))
return false;
break;
2019-01-25 22:18:21 +01:00
case MultiPolygon:
2019-01-31 01:46:53 +01:00
areas.append(Area());
if (!multiPolygon(geometry["coordinates"].toArray(),
areas.last(), properties))
return false;
2019-01-25 22:18:21 +01:00
break;
case GeometryCollection:
2019-01-31 01:46:53 +01:00
if (!geometryCollection(geometry, tracks, areas, waypoints,
2019-01-25 22:18:21 +01:00
properties))
return false;
break;
default:
_errorString = geometry["type"].toString()
+ ": invalid/missing geometry type";
return false;
}
}
return true;
}
bool GeoJSONParser::feature(const QJsonObject &json, QList<TrackData> &tracks,
2019-01-31 01:46:53 +01:00
QList<Area> &areas, QVector<Waypoint> &waypoints)
2019-01-25 22:18:21 +01:00
{
QJsonObject properties(json["properties"].toObject());
QJsonObject geometry(json["geometry"].toObject());
switch (type(geometry)) {
case Point:
waypoints.resize(waypoints.size() + 1);
return point(geometry["coordinates"].toArray(), waypoints.last(),
properties);
case MultiPoint:
return multiPoint(geometry["coordinates"].toArray(), waypoints,
properties);
case LineString:
tracks.append(TrackData());
return lineString(geometry["coordinates"].toArray(), tracks.last(),
properties);
case MultiLineString:
return multiLineString(geometry["coordinates"].toArray(), tracks,
properties);
case GeometryCollection:
2019-01-31 01:46:53 +01:00
return geometryCollection(geometry, tracks, areas, waypoints);
2019-01-25 22:18:21 +01:00
case Polygon:
2019-01-31 01:46:53 +01:00
areas.append(Area());
return polygon(geometry["coordinates"].toArray(), areas.last(),
properties);
2019-01-25 22:18:21 +01:00
case MultiPolygon:
2019-01-31 01:46:53 +01:00
areas.append(Area());
return multiPolygon(geometry["coordinates"].toArray(), areas.last(),
properties);
2019-01-25 22:18:21 +01:00
default:
_errorString = geometry["type"].toString()
+ ": invalid/missing Feature geometry";
return false;
}
}
bool GeoJSONParser::featureCollection(const QJsonObject &json,
2019-01-31 01:46:53 +01:00
QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints)
2019-01-25 22:18:21 +01:00
{
if (!json.contains("features") || !json["features"].isArray()) {
_errorString = "Invalid/missing FeatureCollection features array";
return false;
}
QJsonArray features(json["features"].toArray());
for (int i = 0; i < features.size(); i++)
2019-01-31 01:46:53 +01:00
if (!feature(features.at(i).toObject(), tracks, areas, waypoints))
2019-01-25 22:18:21 +01:00
return false;
return true;
}
bool GeoJSONParser::parse(QFile *file, QList<TrackData> &tracks,
2019-01-31 01:46:53 +01:00
QList<RouteData> &routes, QList<Area> &areas, QVector<Waypoint> &waypoints)
2019-01-25 22:18:21 +01:00
{
Q_UNUSED(routes);
QJsonParseError error;
QJsonDocument doc(QJsonDocument::fromJson(file->readAll(), &error));
if (doc.isNull()) {
_errorString = "JSON parse error: " + error.errorString() + " ["
+ QString::number(error.offset) + "]";
return false;
}
QJsonObject json(doc.object());
switch (type(json)) {
case Point:
waypoints.resize(waypoints.size() + 1);
return point(json["coordinates"].toArray(), waypoints.last());
case MultiPoint:
return multiPoint(json["coordinates"].toArray(), waypoints);
case LineString:
tracks.append(TrackData());
return lineString(json["coordinates"].toArray(), tracks.last());
case MultiLineString:
return multiLineString(json["coordinates"].toArray(), tracks);
case GeometryCollection:
2019-01-31 01:46:53 +01:00
return geometryCollection(json, tracks, areas, waypoints);
2019-01-25 22:18:21 +01:00
case Feature:
2019-01-31 01:46:53 +01:00
return feature(json, tracks, areas, waypoints);
2019-01-25 22:18:21 +01:00
case FeatureCollection:
2019-01-31 01:46:53 +01:00
return featureCollection(json, tracks, areas, waypoints);
2019-01-25 22:18:21 +01:00
case Polygon:
2019-01-31 01:46:53 +01:00
areas.append(Area());
return polygon(json["coordinates"].toArray(), areas.last());
2019-01-25 22:18:21 +01:00
case MultiPolygon:
2019-01-31 01:46:53 +01:00
areas.append(Area());
return multiPolygon(json["coordinates"].toArray(), areas.last());
2019-01-25 22:18:21 +01:00
case Unknown:
if (json["type"].toString().isNull())
_errorString = "Not a GeoJSON file";
else
_errorString = json["type"].toString()
+ ": unknown GeoJSON object";
return false;
}
return true;
}