1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-27 21:24:47 +01:00

Added support for GeoJSON data files

This commit is contained in:
Martin Tůma 2019-01-25 22:18:21 +01:00
parent dcd4666f59
commit 73ccb427db
4 changed files with 343 additions and 2 deletions

View File

@ -261,6 +261,12 @@ SOURCES += src/main.cpp \
src/data/dem.cpp \
src/map/polarstereographic.cpp \
src/map/rectd.cpp
greaterThan(QT_MAJOR_VERSION, 4) {
HEADERS += src/data/geojsonparser.h
SOURCES += src/data/geojsonparser.cpp
}
RESOURCES += gpxsee.qrc
TRANSLATIONS = lang/gpxsee_en.ts \
lang/gpxsee_cs.ts \

View File

@ -12,6 +12,9 @@
#include "oziparsers.h"
#include "locparser.h"
#include "slfparser.h"
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
#include "geojsonparser.h"
#endif // QT 5
#include "dem.h"
#include "data.h"
@ -28,6 +31,9 @@ static WPTParser wpt;
static RTEParser rte;
static LOCParser loc;
static SLFParser slf;
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
static GeoJSONParser geojson;
#endif // QT 5
static QHash<QString, Parser*> parsers()
{
@ -45,6 +51,10 @@ static QHash<QString, Parser*> parsers()
hash.insert("rte", &rte);
hash.insert("loc", &loc);
hash.insert("slf", &slf);
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
hash.insert("json", &geojson);
hash.insert("geojson", &geojson);
#endif // QT 5
return hash;
}
@ -123,11 +133,22 @@ Data::Data(const QString &fileName, bool poi)
QString Data::formats()
{
QStringList l(filter());
qSort(l);
QString supported;
for (int i = 0; i < l.size(); i++) {
supported += l.at(i);
if (i != l.size() - 1)
supported += " ";
}
return
qApp->translate("Data", "Supported files")
+ " (*.csv *.fit *.gpx *.igc *.kml *.loc *.nmea *.plt *.rte *.slf *.tcx *.wpt);;"
qApp->translate("Data", "Supported files") + " (" + supported + ");;"
+ qApp->translate("Data", "CSV files") + " (*.csv);;"
+ qApp->translate("Data", "FIT files") + " (*.fit);;"
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ qApp->translate("Data", "GeoJSON files") + " (*.geojson *.json);;"
#endif // QT5
+ qApp->translate("Data", "GPX files") + " (*.gpx);;"
+ qApp->translate("Data", "IGC files") + " (*.igc);;"
+ qApp->translate("Data", "KML files") + " (*.kml);;"

277
src/data/geojsonparser.cpp Normal file
View File

@ -0,0 +1,277 @@
#include <QJsonDocument>
#include <QJsonArray>
#include "geojsonparser.h"
enum Type {
Unknown,
Point,
LineString,
MultiPoint,
Polygon,
MultiLineString,
MultiPolygon,
GeometryCollection,
Feature,
FeatureCollection
};
static Type type(const QJsonObject &json)
{
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());
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()) {
_errorString = "Invalid MultiPoint Coordinates";
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());
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()) {
_errorString = "Invalid LineString Coordinates";
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()) {
_errorString = "Invalid MultiLineString Coordinates";
return false;
} else {
tracks.append(TrackData());
if (!lineString(coordinates.at(i).toArray(), tracks.last(),
properties))
return false;
}
}
return true;
}
bool GeoJSONParser::geometryCollection(const QJsonObject &json,
QList<TrackData> &tracks, QVector<Waypoint> &waypoints,
const QJsonObject &properties)
{
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:
case MultiPolygon:
break;
case GeometryCollection:
if (!geometryCollection(geometry, tracks, waypoints,
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,
QVector<Waypoint> &waypoints)
{
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:
return geometryCollection(geometry, tracks, waypoints);
case Polygon:
case MultiPolygon:
return true;
default:
_errorString = geometry["type"].toString()
+ ": invalid/missing Feature geometry";
return false;
}
}
bool GeoJSONParser::featureCollection(const QJsonObject &json,
QList<TrackData> &tracks, QVector<Waypoint> &waypoints)
{
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++)
if (!feature(features.at(i).toObject(), tracks, waypoints))
return false;
return true;
}
bool GeoJSONParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints)
{
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:
return geometryCollection(json, tracks, waypoints);
case Feature:
return feature(json, tracks, waypoints);
case FeatureCollection:
return featureCollection(json, tracks, waypoints);
case Polygon:
case MultiPolygon:
return true;
case Unknown:
if (json["type"].toString().isNull())
_errorString = "Not a GeoJSON file";
else
_errorString = json["type"].toString()
+ ": unknown GeoJSON object";
return false;
}
return true;
}

37
src/data/geojsonparser.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef GEOJSONPARSER_H
#define GEOJSONPARSER_H
#include <QJsonObject>
#include "parser.h"
class QJsonObject;
class QJsonArray;
class GeoJSONParser : public Parser
{
public:
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
QVector<Waypoint> &waypoints);
QString errorString() const {return _errorString;}
int errorLine() const {return 0;}
private:
bool point(const QJsonArray &coordinates, Waypoint &waypoint,
const QJsonObject &properties = QJsonObject());
bool multiPoint(const QJsonArray &coordinates,
QVector<Waypoint> &waypoints, const QJsonObject &properties = QJsonObject());
bool lineString(const QJsonArray &coordinates, TrackData &track,
const QJsonObject &properties = QJsonObject());
bool multiLineString(const QJsonArray &coordinates,
QList<TrackData> &tracks, const QJsonObject &properties = QJsonObject());
bool geometryCollection(const QJsonObject &json, QList<TrackData> &tracks,
QVector<Waypoint> &waypoints, const QJsonObject &properties = QJsonObject());
bool feature(const QJsonObject &json, QList<TrackData> &tracks,
QVector<Waypoint> &waypoints);
bool featureCollection(const QJsonObject &json, QList<TrackData> &tracks,
QVector<Waypoint> &waypoints);
QString _errorString;
};
#endif // GEOJSONPARSER_H