Revision control

++ // Copyright (C) 2020 The Qt Company Ltd.
++ // Copyright (C) 2018 Julian Sherollari <jdotsh@gmail.com>
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++ #include "qgeojson_p.h"
++ #include <qvariant.h>
++ #include <qjsondocument.h>
++ #include <qjsonobject.h>
++ #include <qjsonvalue.h>
++ #include <qjsonarray.h>
++ #include <qgeocoordinate.h>
++ #include <qgeocircle.h>
++ #include <qgeopath.h>
++ #include <qgeopolygon.h>
++ #include <qtextstream.h>
++
++ QT_BEGIN_NAMESPACE
++
++ /*!
++ \namespace QGeoJson
++ \inmodule QtLocation
++ \internal
++
++ From Qt 6.7, QGeoJson is a private API. The replacement API is the GeoJsonData QML type.
++ */
++
++ static QGeoCoordinate importPosition(const QVariant &position)
++ {
++ QGeoCoordinate returnedCoordinates;
++ const QVariantList positionList = position.value<QVariantList>();
++ for (qsizetype i = 0; i < positionList.size(); ++i) { // Iterating Point coordinates arrays
++ switch (i) {
++ case 0:
++ returnedCoordinates.setLongitude(positionList.at(i).toDouble());
++ break;
++ case 1:
++ returnedCoordinates.setLatitude(positionList.at(i).toDouble());
++ break;
++ case 2:
++ returnedCoordinates.setAltitude(positionList.at(i).toDouble());
++ break;
++ default:
++ break;
++ }
++ }
++ return returnedCoordinates;
++ }
++
++ static QList<QGeoCoordinate> importArrayOfPositions(const QVariant &arrayOfPositions)
++ {
++ QList<QGeoCoordinate> returnedCoordinates;
++ const QVariantList positionsList = arrayOfPositions.value<QVariantList>();
++ for (const auto &position : positionsList) // Iterating the LineString coordinates nested arrays
++ returnedCoordinates.append(importPosition(position)); // Populating the QList of coordinates
++ return returnedCoordinates;
++ }
++
++ static QList<QList<QGeoCoordinate>> importArrayOfArrayOfPositions(const QVariant &arrayOfArrayofPositions)
++ {
++ QList<QList<QGeoCoordinate>> returnedCoordinates;
++ const QVariantList positionsList = arrayOfArrayofPositions.value<QVariantList>();
++ for (const auto &position : positionsList) // Iterating the Polygon coordinates nested arrays
++ returnedCoordinates << importArrayOfPositions(position);
++ return returnedCoordinates;
++ }
++
++ static QGeoCircle importPoint(const QVariantMap &inputMap)
++ {
++ QGeoCircle returnedObject;
++ QGeoCoordinate center;
++ QVariant valueCoords = inputMap.value(QStringLiteral("coordinates"));
++ center = importPosition(valueCoords);
++ returnedObject.setCenter(center);
++ return returnedObject;
++ }
++
++ static QGeoPath importLineString(const QVariantMap &inputMap)
++ {
++ QGeoPath returnedObject;
++ QList <QGeoCoordinate> coordinatesList;
++ const QVariant valueCoordinates = inputMap.value(QStringLiteral("coordinates"));
++ coordinatesList = importArrayOfPositions(valueCoordinates);
++ returnedObject.setPath(coordinatesList);
++ return returnedObject;
++ }
++
++ static QGeoPolygon importPolygon(const QVariantMap &inputMap)
++ {
++ QGeoPolygon returnedObject;
++ const QVariant valueCoordinates = inputMap.value(QStringLiteral("coordinates"));
++ const QList<QList<QGeoCoordinate>> perimeters = importArrayOfArrayOfPositions(valueCoordinates);
++ for (qsizetype i = 0; i < perimeters.size(); ++i) { // Import an array of QList<QGeocoordinates>
++ if (i == 0)
++ returnedObject.setPerimeter(perimeters.at(i)); // External perimeter
++ else
++ returnedObject.addHole(perimeters.at(i)); // Inner perimeters
++ }
++ return returnedObject;
++ }
++
++ static QVariantList importMultiPoint(const QVariantMap &inputMap)
++ {
++ QVariantList returnedObject;
++ const QVariantList coordinatesList = inputMap.value(QStringLiteral("coordinates")).value<QVariantList>();
++ QVariantMap singlePointMap;
++ QGeoCircle parsedPoint;
++ for (const auto &coordinate : coordinatesList) { // Iterating MultiPoint coordinates nasted arrays
++ parsedPoint.setCenter(importPosition(coordinate));
++ singlePointMap.insert(QStringLiteral("type"), QStringLiteral("Point"));
++ singlePointMap.insert(QStringLiteral("data"), QVariant::fromValue(parsedPoint));
++ returnedObject.append(QVariant::fromValue(singlePointMap));
++ }
++ return returnedObject;
++ }
++
++ static QVariantList importMultiLineString(const QVariantMap &inputMap)
++ {
++ QVariantList returnedObject;
++ QGeoPath parsedLineString;
++ const QVariant listCoords = inputMap.value(QStringLiteral("coordinates"));
++ const QVariantList list = listCoords.value<QVariantList>();
++ QVariantMap singleLinestringMap;
++ for (int i = 0; i < list.size(); ++i) { // Iterating the MultiLineString coordinates nasted arrays using importArrayOfPositions
++ singleLinestringMap.clear();
++ const QList <QGeoCoordinate> coordinatesList = importArrayOfPositions(list.at(i));
++ singleLinestringMap.insert(QStringLiteral("type"), QStringLiteral("LineString"));
++ parsedLineString.setPath(coordinatesList);
++ singleLinestringMap.insert(QStringLiteral("data"), QVariant::fromValue(parsedLineString));
++ returnedObject.append(QVariant::fromValue(singleLinestringMap));
++ }
++ return returnedObject;
++ }
++
++ static QVariantList importMultiPolygon(const QVariantMap &inputMap)
++ {
++ QVariantList returnedObject;
++ QGeoPolygon singlePoly;
++ QVariantMap singlePolygonMap;
++ const QVariant valueCoordinates = inputMap.value(QStringLiteral("coordinates"));
++ const QVariantList list = valueCoordinates.value<QVariantList>();
++ for (int i = 0; i < list.size(); ++i) { // Iterating the MultiPolygon coordinates nasted arrays
++ singlePolygonMap.clear();
++ const QList<QList<QGeoCoordinate>> coordinatesList = importArrayOfArrayOfPositions(list.at(i));
++
++ for (int j = 0; j < coordinatesList.size(); ++j) {
++ if (j == 0)
++ singlePoly.setPerimeter(coordinatesList.at(j));
++ else
++ singlePoly.addHole(coordinatesList.at(j));
++ }
++ singlePolygonMap.insert(QStringLiteral("type"), QStringLiteral("Polygon"));
++ singlePolygonMap.insert(QStringLiteral("data"), QVariant::fromValue(singlePoly));
++ returnedObject.append(QVariant::fromValue(singlePolygonMap));
++ }
++ return returnedObject;
++ }
++
++ static QVariantMap importGeometry(const QVariantMap &inputMap); // Function prototype for a tail recursion
++
++ static QVariantList importGeometryCollection(const QVariantMap &inputMap)
++ {
++ QVariantList returnedObject;
++ const QVariant listGeometries = inputMap.value(QStringLiteral("geometries"));
++ const QVariantList list = listGeometries.value<QVariantList>(); // QVariantList of heterogeneous composition of the other geometry types
++ for (int i = 0; i < list.size(); ++i) {
++ QVariantMap geometryMap = list.at(i).value<QVariantMap>();
++ QVariantMap geoMap = importGeometry(geometryMap);
++ returnedObject.append(geoMap);
++ }
++ return returnedObject;
++ }
++
++ static QVariantMap importGeometry(const QVariantMap &inputMap)
++ {
++ QVariantMap returnedObject;
++ QString geometryTypes[] = {
++ QStringLiteral("Point"),
++ QStringLiteral("MultiPoint"),
++ QStringLiteral("LineString"),
++ QStringLiteral("MultiLineString"),
++ QStringLiteral("Polygon"),
++ QStringLiteral("MultiPolygon"),
++ QStringLiteral("GeometryCollection")
++ };
++ enum geoTypeSwitch {
++ Point,
++ MultiPoint,
++ LineString,
++ MultiLineString,
++ Polygon,
++ MultiPolygon,
++ GeometryCollection
++ };
++ for (int i = 0; i<7; ++i) {
++ if (inputMap.value(QStringLiteral("type")).value<QString>() == geometryTypes[i]) {
++ switch (i) {
++ case Point: {
++ returnedObject.insert(QStringLiteral("type"), QStringLiteral("Point"));
++ returnedObject.insert(QStringLiteral("data"), QVariant::fromValue(importPoint(inputMap)));
++ break;
++ }
++ case MultiPoint: {
++ returnedObject.insert(QStringLiteral("type"), QStringLiteral("MultiPoint"));
++ returnedObject.insert(QStringLiteral("data"), QVariant::fromValue(importMultiPoint(inputMap)));
++ break;
++ }
++ case LineString: {
++ returnedObject.insert(QStringLiteral("type"), QStringLiteral("LineString"));
++ returnedObject.insert(QStringLiteral("data"), QVariant::fromValue(importLineString(inputMap)));
++ break;
++ }
++ case MultiLineString: {
++ returnedObject.insert(QStringLiteral("type"), QStringLiteral("MultiLineString"));
++ returnedObject.insert(QStringLiteral("data"), QVariant::fromValue(importMultiLineString(inputMap)));
++ break;
++ }
++ case Polygon: {
++ returnedObject.insert(QStringLiteral("type"), QStringLiteral("Polygon"));
++ returnedObject.insert(QStringLiteral("data"), QVariant::fromValue(importPolygon(inputMap)));
++ break;
++ }
++ case MultiPolygon: {
++ returnedObject.insert(QStringLiteral("type"), QStringLiteral("MultiPolygon"));
++ returnedObject.insert(QStringLiteral("data"), QVariant::fromValue(importMultiPolygon(inputMap)));
++ break;
++ }
++ case GeometryCollection: {
++ returnedObject.insert(QStringLiteral("type"), QStringLiteral("GeometryCollection"));
++ returnedObject.insert(QStringLiteral("data"), QVariant::fromValue(importGeometryCollection(inputMap)));
++ break;
++ }
++ default:
++ break;
++ }
++ }
++ }
++ return returnedObject;
++ }
++
++ static QVariantList importFeatureCollection(const QVariantMap &inputMap)
++ {
++ QVariantList returnedObject;
++ const QVariantList featuresList = inputMap.value(QStringLiteral("features")).value<QVariantList>();
++ for (int i = 0; i < featuresList.size(); ++i) {
++ QVariantMap inputFeatureMap = featuresList.at(i).value<QVariantMap>();
++ QVariantMap singleFeatureMap = importGeometry(inputFeatureMap.value(QStringLiteral("geometry")).value<QVariantMap>());
++ const QVariantMap importedProperties = inputFeatureMap.value(QStringLiteral("properties")).value<QVariantMap>();
++ singleFeatureMap.insert(QStringLiteral("properties"), importedProperties);
++ if (inputFeatureMap.contains(QStringLiteral("id"))) {
++ QVariant importedId = inputFeatureMap.value(QStringLiteral("id")).value<QVariant>();
++ singleFeatureMap.insert(QStringLiteral("id"), importedId);
++ }
++ returnedObject.append(singleFeatureMap);
++ }
++ return returnedObject;
++ }
++
++ static QJsonValue exportPosition(const QGeoCoordinate &obtainedCoordinates)
++ {
++ QJsonValue geoLat = obtainedCoordinates.latitude();
++ QJsonValue geoLong = obtainedCoordinates.longitude();
++ QJsonArray array = {geoLong, geoLat};
++ QJsonValue geoAlt;
++ if (!qIsNaN(obtainedCoordinates.altitude())) {
++ geoAlt = obtainedCoordinates.altitude();
++ array.append(geoAlt);
++ }
++ QJsonValue geoArray = array;
++ return geoArray;
++ }
++
++ static QJsonValue exportArrayOfPositions(const QList<QGeoCoordinate> &obtainedCoordinatesList)
++ {
++ QJsonValue lineCoordinates;
++ QJsonValue multiPosition;
++ QJsonArray arrayPosition;
++ for (int i = 0; i < obtainedCoordinatesList.size(); ++i) {
++ multiPosition = exportPosition(obtainedCoordinatesList.at(i));
++ arrayPosition.append(multiPosition);
++ }
++ lineCoordinates = arrayPosition;
++ return lineCoordinates;
++ }
++
++ static QJsonValue exportArrayOfArrayOfPositions(const QList<QList<QGeoCoordinate>> &obtainedCoordinates)
++ {
++ QJsonValue lineCoordinates;
++ QJsonValue polyCoordinates;
++ QJsonArray arrayPath;
++ for (int i = 0; i < obtainedCoordinates.size(); ++i) {
++ lineCoordinates = exportArrayOfPositions(obtainedCoordinates.at(i));
++ arrayPath.append(lineCoordinates);
++ }
++ polyCoordinates = arrayPath;
++ return polyCoordinates;
++ }
++
++ static QJsonObject exportPoint(const QVariantMap &pointMap)
++ {
++ QJsonObject parsedPoint;
++ QGeoCircle circle = pointMap.value(QStringLiteral("data")).value<QGeoCircle>();
++ parsedPoint.insert(QStringLiteral("type"), QJsonValue(QStringLiteral("Point")));
++ parsedPoint.insert(QStringLiteral("coordinates"), exportPosition(circle.center()));
++ return parsedPoint;
++ }
++
++ static QJsonObject exportLineString(const QVariantMap &lineStringMap)
++ {
++ QJsonObject parsedLineString;
++ QList <QGeoCoordinate> linestringPath = lineStringMap.value(QStringLiteral("data")).value<QGeoPath>().path();
++ parsedLineString.insert(QStringLiteral("type"), QJsonValue(QStringLiteral("LineString")));
++ parsedLineString.insert(QStringLiteral("coordinates"), exportArrayOfPositions(linestringPath));
++ return parsedLineString;
++ }
++
++ static QJsonObject exportPolygon(const QVariantMap &polygonMap)
++ {
++ QVariant polygonVariant = polygonMap.value(QStringLiteral("data"));
++ QJsonObject parsedPolygon;
++ QJsonValue polyCoordinates;
++ QList<QList<QGeoCoordinate>> obtainedCoordinatesPoly;
++ QGeoPolygon parsedPoly = polygonVariant.value<QGeoPolygon>();
++ obtainedCoordinatesPoly << parsedPoly.perimeter();
++ if (parsedPoly.holesCount()!=0)
++ for (int i = 0; i < parsedPoly.holesCount(); ++i) {
++ obtainedCoordinatesPoly << parsedPoly.holePath(i);
++ }
++ polyCoordinates = exportArrayOfArrayOfPositions(obtainedCoordinatesPoly);
++ parsedPolygon.insert(QStringLiteral("type"), QJsonValue(QStringLiteral("Polygon")));
++ parsedPolygon.insert(QStringLiteral("coordinates"), polyCoordinates);
++ return parsedPolygon;
++ }
++
++ static QJsonObject exportMultiPoint(const QVariantMap &multiPointMap)
++ {
++ QJsonObject parsedMultiPoint;
++ QList <QGeoCoordinate> obtainedCoordinatesMP;
++ QVariantList multiCircleVariantList = multiPointMap.value(QStringLiteral("data")).value<QVariantList>();
++ for (const QVariant &exCircleVariantMap: multiCircleVariantList) {
++ obtainedCoordinatesMP << exCircleVariantMap.value<QVariantMap>().value(QStringLiteral("data")).value<QGeoCircle>().center();
++ }
++ QJsonValue multiPosition = exportArrayOfPositions(obtainedCoordinatesMP);
++ parsedMultiPoint.insert(QStringLiteral("type"), QJsonValue(QStringLiteral("MultiPoint")));
++ parsedMultiPoint.insert(QStringLiteral("coordinates"), multiPosition);
++ return parsedMultiPoint;
++ }
++
++ static QJsonObject exportMultiLineString(const QVariantMap &multiLineStringMap)
++ {
++ QJsonObject parsedMultiLineString;
++ QList<QList<QGeoCoordinate>> extractedCoordinatesValue;
++ QVariant multiPathVariant = multiLineStringMap.value(QStringLiteral("data"));
++ QVariantList multiPathList = multiPathVariant.value<QVariantList>();
++ for (int i = 0; i < multiPathList.size(); ++i) {
++ extractedCoordinatesValue << multiPathList.at(i).value<QVariantMap>().value(QStringLiteral("data")).value<QGeoPath>().path();
++ }
++ QJsonValue exportedCoordinatesValue = exportArrayOfArrayOfPositions(extractedCoordinatesValue);
++ parsedMultiLineString.insert(QStringLiteral("type"), QJsonValue(QStringLiteral("MultiLineString")));
++ parsedMultiLineString.insert(QStringLiteral("coordinates"), exportedCoordinatesValue);
++ return parsedMultiLineString;
++ }
++
++ static QJsonObject exportMultiPolygon(const QVariantMap &multiPolygonMap)
++ {
++ QJsonObject parsedMultiPolygon;
++ QJsonValue polyCoordinates;
++ QJsonArray parsedArrayPolygon;
++ QList<QList<QGeoCoordinate>> extractedCoordinatesValue;
++ QVariant multiPolygonVariant = multiPolygonMap.value(QStringLiteral("data"));
++ QVariantList multiPolygonList = multiPolygonVariant.value<QVariantList>();
++ int polyHoles = 0;
++ int currentHole;
++ for (int i = 0; i < multiPolygonList.size(); ++i) { // Start parsing Polygon list
++ extractedCoordinatesValue << multiPolygonList.at(i).value<QVariantMap>().value(QStringLiteral("data")).value<QGeoPolygon>().perimeter(); // Extract external polygon path
++ polyHoles = multiPolygonList.at(i).value<QVariantMap>().value(QStringLiteral("data")).value<QGeoPolygon>().holesCount();
++ if (polyHoles) // Check if the polygon has holes
++ for (currentHole = 0 ; currentHole < polyHoles; currentHole++)
++ extractedCoordinatesValue << multiPolygonList.at(i).value<QVariantMap>().value(QStringLiteral("data")).value<QGeoPolygon>().holePath(currentHole);
++ polyCoordinates = exportArrayOfArrayOfPositions(extractedCoordinatesValue); // Generates QJsonDocument compatible value
++ parsedArrayPolygon.append(polyCoordinates); // Adds one level of nesting in coordinates
++ extractedCoordinatesValue.clear(); // Clears the temporary polygon linear ring storage
++ }
++ QJsonValue exportedCoordinatesNodeValue = parsedArrayPolygon;
++ parsedMultiPolygon.insert(QStringLiteral("type"), QJsonValue(QStringLiteral("MultiPolygon")));
++ parsedMultiPolygon.insert(QStringLiteral("coordinates"), exportedCoordinatesNodeValue);
++ return parsedMultiPolygon;
++ }
++
++ static QJsonObject exportGeometry(const QVariantMap &geometryMap); // Function prototype
++
++ static QJsonObject exportGeometryCollection(const QVariantMap &geometryCollection)
++ {
++ QJsonObject parsed;
++ QJsonObject parsedGeometry;
++ QJsonValue valueGeometries;
++ QJsonArray parsedGeometries;
++ QVariantList geometriesList = geometryCollection.value(QStringLiteral("data")).value<QVariantList>();
++ for (int i = 0; i < geometriesList.size(); ++i) {
++ parsedGeometry = exportGeometry(geometriesList.at(i).value<QVariantMap>());
++ valueGeometries = parsedGeometry;
++ parsedGeometries.append(valueGeometries);
++ }
++ QJsonValue exportedGeometriesValue = parsedGeometries;
++ parsed.insert(QStringLiteral("type"), QJsonValue(QStringLiteral("GeometryCollection")));
++ parsed.insert(QStringLiteral("geometries"), exportedGeometriesValue);
++ return parsed;
++ }
++
++ static QJsonObject exportGeometry(const QVariantMap &geometryMap)
++ {
++ QJsonObject exportedGeometry;
++ if (geometryMap.value(QStringLiteral("type")) == QStringLiteral("Point"))
++ exportedGeometry = exportPoint(geometryMap);
++ if (geometryMap.value(QStringLiteral("type")) == QStringLiteral("MultiPoint"))
++ exportedGeometry = exportMultiPoint(geometryMap);
++ if (geometryMap.value(QStringLiteral("type")) == QStringLiteral("LineString"))
++ exportedGeometry = exportLineString(geometryMap);
++ if (geometryMap.value(QStringLiteral("type")) == QStringLiteral("MultiLineString"))
++ exportedGeometry = exportMultiLineString(geometryMap);
++ if (geometryMap.value(QStringLiteral("type")) == QStringLiteral("Polygon"))
++ exportedGeometry = exportPolygon(geometryMap);
++ if (geometryMap.value(QStringLiteral("type")) == QStringLiteral("MultiPolygon"))
++ exportedGeometry = exportMultiPolygon(geometryMap);
++ if (geometryMap.value(QStringLiteral("type")) == QStringLiteral("GeometryCollection"))
++ exportedGeometry = exportGeometryCollection(geometryMap);
++ return exportedGeometry;
++ }
++
++ static QJsonObject exportFeature(const QVariantMap &featureMap)
++ {
++ QJsonObject exportedFeature;
++ QJsonValue geometryNodeValue = QJsonValue(exportGeometry(featureMap));
++ QJsonValue propertiesNodeValue = featureMap.value(QStringLiteral("properties")).value<QVariant>().toJsonValue();
++ QJsonValue idNodeValue = featureMap.value(QStringLiteral("id")).value<QVariant>().toJsonValue();
++ exportedFeature.insert(QStringLiteral("type"), QJsonValue(QStringLiteral("Feature")));
++ exportedFeature.insert(QStringLiteral("geometry"), geometryNodeValue);
++ exportedFeature.insert(QStringLiteral("properties"), propertiesNodeValue);
++ if (!idNodeValue.isNull()) // this value is optional
++ exportedFeature.insert(QStringLiteral("id"), idNodeValue);
++ return exportedFeature;
++ }
++
++ static QJsonObject exportFeatureCollection(const QVariantMap &featureCollection)
++ {
++ QJsonObject exportedFeatureCollection;
++ QJsonArray featureArray;
++ QVariantList featureList = featureCollection.value(QStringLiteral("data")).value<QVariantList>();
++ for (int i = 0; i < featureList.size(); ++i) {
++ featureArray.append(QJsonValue(exportFeature(featureList.at(i).value<QVariantMap>())));
++ }
++ exportedFeatureCollection.insert(QStringLiteral("type"), QJsonValue(QStringLiteral("FeatureCollection")));
++ exportedFeatureCollection.insert(QStringLiteral("features"), QJsonValue(featureArray) );
++ return exportedFeatureCollection;
++ }
++
++ namespace QGeoJson
++ {
++
++ /*!
++ This method imports the \a geoJson document, expected to contain valid GeoJSON
++ data, into a QVariantList structured like described in the section \l
++ {Importing GeoJSON}.
++
++ \note This method performs no validation on the input.
++
++ \sa exportGeoJson
++ */
++ QVariantList importGeoJson(const QJsonDocument &geoJson)
++ {
++ QVariantList returnedList;
++ QJsonObject object = geoJson.object(); // Read json object from imported doc
++ QVariantMap rootGeoJsonObject = object.toVariantMap(); // Extraced map using Qt's API
++ QString geoType[] = {
++ QStringLiteral("Point"),
++ QStringLiteral("MultiPoint"),
++ QStringLiteral("LineString"),
++ QStringLiteral("MultiLineString"),
++ QStringLiteral("Polygon"),
++ QStringLiteral("MultiPolygon"),
++ QStringLiteral("GeometryCollection"),
++ QStringLiteral("Feature"),
++ QStringLiteral("FeatureCollection")
++ };
++ enum geoTypeSwitch {
++ Point,
++ MultiPoint,
++ LineString,
++ MultiLineString,
++ Polygon,
++ MultiPolygon,
++ GeometryCollection,
++ Feature,
++ FeatureCollection
++ };
++ QVariantMap parsedGeoJsonMap;
++
++ // Checking whether the JSON object has a "type" member
++ const QVariant keyVariant = rootGeoJsonObject.value(QStringLiteral("type"));
++ if (!keyVariant.isValid()) {
++ // Type check failed
++ }
++ QString valueType = keyVariant.value<QString>();
++
++ // Checking whether the "type" member has a GeoJSON admitted value
++ for (int i = 0; i < 9; ++i) {
++ if (valueType == geoType[i]) {
++ switch (i) {
++ case Point: {
++ QGeoCircle circle = importPoint(rootGeoJsonObject);
++ QVariant dataNodeValue = QVariant::fromValue(circle);
++ parsedGeoJsonMap.insert(QStringLiteral("type"), QStringLiteral("Point"));
++ parsedGeoJsonMap.insert(QStringLiteral("data"), dataNodeValue);
++ break;
++ }
++ case MultiPoint: {
++ QVariantList multiCircle = importMultiPoint(rootGeoJsonObject);
++ QVariant dataNodeValue = QVariant::fromValue(multiCircle);
++ QList <QGeoCircle> testlist;
++ parsedGeoJsonMap.insert(QStringLiteral("type"), QStringLiteral("MultiPoint"));
++ parsedGeoJsonMap.insert(QStringLiteral("data"), dataNodeValue);
++ break;
++ }
++ case LineString: {
++ QGeoPath lineString = importLineString(rootGeoJsonObject);
++ QVariant dataNodeValue = QVariant::fromValue(lineString);
++ parsedGeoJsonMap.insert(QStringLiteral("type"), QStringLiteral("LineString"));
++ parsedGeoJsonMap.insert(QStringLiteral("data"), dataNodeValue);
++ break;
++ }
++ case MultiLineString: {
++ QVariantList multiLineString = importMultiLineString(rootGeoJsonObject);
++ QVariant dataNodeValue = QVariant::fromValue(multiLineString);
++ parsedGeoJsonMap.insert(QStringLiteral("type"), QStringLiteral("MultiLineString"));
++ parsedGeoJsonMap.insert(QStringLiteral("data"), dataNodeValue);
++ break;
++ }
++ case Polygon: {
++ QGeoPolygon poly = importPolygon(rootGeoJsonObject);
++ QVariant dataNodeValue = QVariant::fromValue(poly);
++ parsedGeoJsonMap.insert(QStringLiteral("type"), QStringLiteral("Polygon"));
++ parsedGeoJsonMap.insert(QStringLiteral("data"), dataNodeValue);
++ break;
++ }
++ case MultiPolygon: {
++ QVariantList multiPoly = importMultiPolygon(rootGeoJsonObject);
++ QVariant dataNodeValue = QVariant::fromValue(multiPoly);
++ parsedGeoJsonMap.insert(QStringLiteral("type"), QStringLiteral("MultiPolygon"));
++ parsedGeoJsonMap.insert(QStringLiteral("data"), dataNodeValue);
++ break;
++ }
++ // List of GeoJson geometry objects
++ case GeometryCollection: {
++ QVariantList multiGeo = importGeometryCollection(rootGeoJsonObject);
++ QVariant dataNodeValue = QVariant::fromValue(multiGeo);
++ parsedGeoJsonMap.insert(QStringLiteral("type"), QStringLiteral("GeometryCollection"));
++ parsedGeoJsonMap.insert(QStringLiteral("data"), dataNodeValue);
++ break;
++ }
++ // Single GeoJson geometry object with properties
++ case Feature: {
++ parsedGeoJsonMap = importGeometry(rootGeoJsonObject.value(QStringLiteral("geometry")).value<QVariantMap>());
++ QVariantMap importedProperties = rootGeoJsonObject.value(QStringLiteral("properties")).value<QVariantMap>();
++ parsedGeoJsonMap.insert(QStringLiteral("properties"), importedProperties);
++ if (rootGeoJsonObject.contains(QStringLiteral("id"))){
++ QVariant importedId = rootGeoJsonObject.value(QStringLiteral("id")).value<QVariant>();
++ parsedGeoJsonMap.insert(QStringLiteral("id"), importedId);
++ }
++ break;
++ }
++ // Heterogeneous list of GeoJSON geometries with properties
++ case FeatureCollection: {
++ QVariantList featCollection = importFeatureCollection(rootGeoJsonObject);
++ QVariant dataNodeValue = QVariant::fromValue(featCollection);
++ parsedGeoJsonMap.insert(QStringLiteral("type"), QStringLiteral("FeatureCollection"));
++ parsedGeoJsonMap.insert(QStringLiteral("data"), dataNodeValue);
++ break;
++ }
++ default:
++ break;
++ }
++ QVariant bboxNodeValue = rootGeoJsonObject.value(QStringLiteral("bbox"));
++ if (bboxNodeValue.isValid()) {
++ parsedGeoJsonMap.insert(QStringLiteral("bbox"), bboxNodeValue);
++ }
++ returnedList.append(parsedGeoJsonMap);
++ } else if (i >= 9) {
++ // Error
++ break;
++ }
++ }
++ return returnedList;
++ }
++
++ /*!
++ This method exports the QVariantList \a geoData, expected to be structured like
++ described in the section \l {Importing GeoJSON}, to a QJsonDocument containing
++ the data converted to GeoJSON.
++
++ \note This method performs no validation on the input.
++
++ \sa importGeoJson
++ */
++ QJsonDocument exportGeoJson(const QVariantList &geoData)
++ {
++ if (geoData.isEmpty())
++ return QJsonDocument();
++ QVariantMap exportMap = geoData.at(0).value<QVariantMap>(); // Extracting the QVMap
++ QJsonObject newObject;
++ QJsonDocument newDocument;
++ if (exportMap.contains(QStringLiteral("properties"))) {
++ newObject = exportFeature(exportMap);
++ } else {
++ if (exportMap.value(QStringLiteral("type")) == QStringLiteral("Point")) // Check the value corresponding to the key "Point"
++ newObject = exportPoint(exportMap);
++ if (exportMap.value(QStringLiteral("type")) == QStringLiteral("MultiPoint"))
++ newObject = exportMultiPoint(exportMap);
++ if (exportMap.value(QStringLiteral("type")) == QStringLiteral("LineString"))
++ newObject = exportLineString(exportMap);
++ if (exportMap.value(QStringLiteral("type")) == QStringLiteral("MultiLineString"))
++ newObject = exportMultiLineString(exportMap);
++ if (exportMap.value(QStringLiteral("type")) == QStringLiteral("Polygon"))
++ newObject = exportPolygon(exportMap);
++ if (exportMap.value(QStringLiteral("type")) == QStringLiteral("MultiPolygon"))
++ newObject = exportMultiPolygon(exportMap);
++ if (exportMap.value(QStringLiteral("type")) == QStringLiteral("GeometryCollection"))
++ newObject = exportGeometryCollection(exportMap);
++ if (exportMap.value(QStringLiteral("type")) == QStringLiteral("FeatureCollection"))
++ newObject = exportFeatureCollection(exportMap);
++ }
++ if (exportMap.contains((QStringLiteral("bbox")))) {
++ QJsonArray bboxArray;
++ QVariantList bboxList = exportMap.value(QStringLiteral("bbox")).value<QVariantList>();
++ for (int i = 0; i < bboxList.size(); ++i) {
++ bboxArray.append(QJsonValue(bboxList.at(i).value<double>()));
++ }
++ newObject.insert(QStringLiteral("bbox"), QJsonValue(bboxArray));
++ }
++ newDocument.setObject(newObject);
++ return newDocument;
++ }
++
++ // Functions for toString
++ QTextStream &operator<<(QTextStream &stream, const QGeoCoordinate &crd)
++ {
++ stream << "{ " << QString::number(crd.latitude(), 'f', 3) << ", "
++ << QString::number(crd.longitude(), 'f', 3) << ", "
++ << QString::number(crd.altitude(), 'f', 3) << " }";
++ return stream;
++ }
++
++ QTextStream &operator<<(QTextStream &stream, const QGeoShape &shape)
++ {
++ switch (shape.type()) {
++ case QGeoShape::CircleType: {
++ QGeoCircle circle(shape);
++ stream << "QGeoCircle(" <<circle.center() << ", "<< QString::number(circle.radius()) << ")";
++ break;
++ }
++ case QGeoShape::PathType: {
++ QGeoPath path(shape);
++ stream << "QGeoPath(";
++ for (auto c: path.path())
++ stream << c << ", ";
++ stream << ")";
++ break;
++ }
++ case QGeoShape::PolygonType: {
++ QGeoPolygon poly(shape);
++ stream << "QGeoPolygon(";
++ for (auto c: poly.perimeter())
++ stream << c << ", ";
++ stream << ")";
++ break;
++ }
++ default:
++ stream << "QGeoShape(Unknown)";
++ break;
++ }
++ return stream;
++ }
++
++
++ static QString printQvariant(const QVariant v, int tabs = 0) {
++ static constexpr QStringView sTab(u" ");
++ QString sTabs;
++ QString res;
++ QTextStream stream(&res);
++ for (int i = 0; i< tabs; i++) {
++ sTabs += sTab;
++ }
++ if (v.typeId() == QMetaType::QVariantList) {
++ stream << sTabs << "[\n";
++ const QVariantList &l = v.toList();
++ for (int i = 0; i < l.size(); ++i)
++ stream << printQvariant(l.at(i), tabs + 1);
++ stream << sTabs << "]\n";
++ } else if (v.typeId() == QMetaType::QVariantMap) {
++ stream << sTabs << "{\n";
++ const QVariantList &l = v.toList();
++ const QVariantMap &map = v.toMap();
++
++ // Either one or the other are valid
++ if (!map.keys().isEmpty()) {
++ // Handle type first, to easy reading
++ if (map.contains(QStringLiteral("type"))) {
++ stream << sTabs << sTab << QStringLiteral("type") << " : "
++ << printQvariant(map[QStringLiteral("type")], tabs + 1).remove(QRegularExpression(QStringLiteral("^[ ]*")));
++ }
++ for (QVariantMap::const_iterator iter = map.begin(); iter != map.end(); ++iter) {
++ if (iter.key() == QStringLiteral("type"))
++ continue;
++ stream << sTabs << sTab << iter.key() << " : " << printQvariant(iter.value(), tabs + 1).remove(QRegularExpression(QStringLiteral("^[ ]*")));
++ }
++ }
++ for (int i = 0; i < l.size(); ++i)
++ stream << printQvariant(l.at(i), tabs + 1);
++ stream << sTabs << "}\n";
++ } else {
++ stream << sTabs;
++ QGeoShape workigGeometry;
++ if ( v.canConvert<QGeoShape>()) {
++ workigGeometry = v.value<QGeoShape>();
++ if (workigGeometry.type() == QGeoShape::CircleType) {
++ QGeoCircle circle = v.value<QGeoCircle>();
++ stream << circle<< "\n";
++ } else if (workigGeometry.type() == QGeoShape::PathType) {
++ QGeoPath path = v.value<QGeoPath>();
++ stream << path<< "\n";
++ } else if (workigGeometry.type() == QGeoShape::PolygonType) {
++ QGeoPolygon polygon = v.value<QGeoPolygon>();
++ stream << polygon<< "\n";
++ }
++ } else {
++ if (v.isNull())
++ stream << "null\n";
++ else
++ stream << v.toString() << "\n";
++ }
++ }
++ return res;
++ }
++
++ /*!
++ This method accepts the QVariantList \a geoData, structured as described in
++ \l {Importing GeoJSON}, and returns a string containing the same data in a
++ readable form.
++ */
++ QString toString(const QVariantList &geoData) {
++ if (geoData.isEmpty())
++ return QString();
++ return printQvariant(geoData.first(), 0);
++ }
++
++ } // namespace QGeoJson
++
++ QT_END_NAMESPACE