diff --git a/src/plugins/runner/json/JsonParser.h b/src/plugins/runner/json/JsonParser.h --- a/src/plugins/runner/json/JsonParser.h +++ b/src/plugins/runner/json/JsonParser.h @@ -21,6 +21,10 @@ class GeoDataDocument; class GeoDataGeometry; +class GeoDataIconStyle; +class GeoDataLineStyle; +class GeoDataPolyStyle; +class GeoDataLabelStyle; class JsonParser { @@ -45,6 +49,12 @@ GeoDataDocument* m_document; + GeoDataIconStyle* m_iconStylePoints; + GeoDataIconStyle* m_iconStyleOther; + GeoDataLineStyle* m_lineStyle; + GeoDataPolyStyle* m_polyStyle; + GeoDataLabelStyle* m_labelStyle; + /** * @brief parse a top-level GeoJSON object (FeatureCollection or Feature) * @param jsonObject the object to parse @@ -56,9 +66,10 @@ * @brief parse a sub-level GeoJSON object * @param jsonObject the object to parse * @param geometryList a list of geometries pass back to the caller + * @param hasPoints a boolean passed back to the caller: true if Points exist in geometry * @return true if parsing of the object was successful */ - bool parseGeoJsonSubLevel(const QJsonObject&, QVector&); + bool parseGeoJsonSubLevel(const QJsonObject&, QVector&, bool&); }; } diff --git a/src/plugins/runner/json/JsonParser.cpp b/src/plugins/runner/json/JsonParser.cpp --- a/src/plugins/runner/json/JsonParser.cpp +++ b/src/plugins/runner/json/JsonParser.cpp @@ -7,6 +7,9 @@ ((https://github.com/mapbox/simplestyle-spec). Attributes are also stored as OSM tags as required. + TODO: Handle the Simplestyle "marker-size", "marker-symbol" and + "marker-color" correctly. + This program is free software licensed under the GNU LGPL. You can find a copy of this license in LICENSE.txt in the top directory of the source code. @@ -22,34 +25,74 @@ #include "GeoDataLinearRing.h" #include "GeoDataPoint.h" #include "GeoDataMultiGeometry.h" +#include "MarbleDirs.h" #include "MarbleDebug.h" #include "StyleBuilder.h" #include "osm/OsmPlacemarkData.h" #include #include #include #include -#include -#include #include #include "GeoDataStyle.h" #include "GeoDataIconStyle.h" -#include "GeoDataLabelStyle.h" #include "GeoDataLineStyle.h" #include "GeoDataPolyStyle.h" +#include "GeoDataLabelStyle.h" namespace Marble { JsonParser::JsonParser() : m_document( nullptr ) { + // Get the default styles set by Marble + + GeoDataPlacemark placemark; + GeoDataStyle::Ptr style(new GeoDataStyle(*(placemark.style()))); + m_iconStylePoints = new GeoDataIconStyle(style->iconStyle()); + m_iconStyleOther = new GeoDataIconStyle(style->iconStyle()); + m_lineStyle = new GeoDataLineStyle(style->lineStyle()); + m_polyStyle = new GeoDataPolyStyle(style->polyStyle()); + m_labelStyle = new GeoDataLabelStyle(style->labelStyle()); + + // Set default styles for GeoJSON objects using Simplestyle specification 1.1.0 + + // Set "marker-color": "#7e7e7e" and "marker-size": "medium" + m_iconStylePoints->setColor(QColor("#ff7e7e7e")); + m_iconStylePoints->setIconPath(MarbleDirs::path(QStringLiteral("svg/dot-circle-regular.svg"))); + m_iconStylePoints->setSize(QSize(22,22), Qt::KeepAspectRatio); + + m_iconStyleOther->setIconPath(nullptr); + m_iconStyleOther->setColor(QColor("#ff7e7e7e")); + + // Set "stroke": "#555555", "stroke-opacity": 1.0 and "stroke-width": 2 (increased to 2.5 due + // to problems with antialiased lines disappearing on drawn maps + m_lineStyle->setColor(QColor("#ff555555")); + m_lineStyle->setWidth(2.5); + + // Set "fill": "#555555" and "fill-opacity": 0.6 + m_polyStyle->setColor(QColor("#99555555")); + + // Set visual properties not part of the Simplestyle spec + + m_labelStyle->setColor(QColor("#ff000000")); + m_labelStyle->setGlow(true); + + m_polyStyle->setFill(true); + m_polyStyle->setOutline(true); } JsonParser::~JsonParser() { delete m_document; + + delete m_iconStylePoints; + delete m_iconStyleOther; + delete m_lineStyle; + delete m_polyStyle; + delete m_labelStyle; } GeoDataDocument *JsonParser::releaseDocument() @@ -125,9 +168,10 @@ // associated properties. Note that only Feature objects can have recognised properties. QVector geometryList; // Populated by parseGeoJsonSubLevel() + bool hasPoints = false; // Populated by parseGeoJsonSubLevel() if (! parseGeoJsonSubLevel( jsonObject.value(QStringLiteral("geometry")).toObject(), - geometryList )) { + geometryList, hasPoints )) { return false; } @@ -153,334 +197,331 @@ placemark->setGeometry(geom); } - // Set default style properties using the Simplestyle specification 1.1.0 + // Create copies of the default styles - GeoDataStyle::Ptr style(new GeoDataStyle(*(placemark->style()))); - GeoDataIconStyle iconStyle = style->iconStyle(); - GeoDataLabelStyle labelStyle = style->labelStyle(); - GeoDataLineStyle lineStyle = style->lineStyle(); - GeoDataPolyStyle polyStyle = style->polyStyle(); + GeoDataStyle::Ptr style(new GeoDataStyle(*(placemark->style()))); + GeoDataIconStyle iconStyle = hasPoints ? *m_iconStylePoints : *m_iconStyleOther; + GeoDataLineStyle lineStyle = *m_lineStyle; + GeoDataPolyStyle polyStyle = *m_polyStyle; - // TODO: Handle "marker-size": "medium" and "marker-symbol": "" - iconStyle.setColor(QColor("#ff7e7e7e")); // "marker-color": "#7e7e7e" + // Parse any associated properties + + const QJsonObject propertiesObject = jsonObject.value(QStringLiteral("properties")).toObject(); + QJsonObject::ConstIterator iter = propertiesObject.begin(); + const QJsonObject::ConstIterator end = propertiesObject.end(); + + OsmPlacemarkData osmData; - lineStyle.setColor(QColor("#ff555555")); // "stroke": "#555555" and "stroke-opacity": 1.0 - lineStyle.setWidth(2.5); // "stroke-width": 2 (increased to 2.5 due to - // problems with antialiased lines disappearing + for ( ; iter != end; ++iter) { + // Pass the value through QVariant to also get booleans and numbers + const QString propertyValue = iter.value().toVariant().toString(); + const QString propertyKey = iter.key(); - polyStyle.setColor(QColor("#99555555")); // "fill": "#555555" and "fill-opacity": 0.6 + if (iter.value().isObject() || iter.value().isArray()) { + qDebug() << "Skipping unsupported JSON property containing an object or array:" << propertyKey; + continue; + } - // Set visual properties not part of the Simplestyle spec + if (propertyKey == QStringLiteral("name")) { + // The "name" property is not defined in the Simplestyle specification, but is used + // extensively in the wild. Treat "name" and "title" essentially the same for the + // purposes of placemarks (although osmData tags will preserve the distinction). + + placemark->setName(propertyValue); + osmData.addTag(propertyKey, propertyValue); + + } else if (propertyKey == QStringLiteral("title")) { + placemark->setName(propertyValue); + osmData.addTag(propertyKey, propertyValue); + + } else if (propertyKey == QStringLiteral("description")) { + placemark->setDescription(propertyValue); + osmData.addTag(propertyKey, propertyValue); + + } else if (propertyKey == QStringLiteral("marker-size")) { + // TODO: Implement marker-size handling + if (propertyValue == QStringLiteral("")) { + // Use the default value + ; + } else { + //qDebug() << "Ignoring unimplemented marker-size property:" << propertyValue; + } + + } else if (propertyKey == QStringLiteral("marker-symbol")) { + // TODO: Implement marker-symbol handling + if (propertyValue == QStringLiteral("")) { + // Use the default value + ; + } else { + //qDebug() << "Ignoring unimplemented marker-symbol property:" << propertyValue; + } + + } else if (propertyKey == QStringLiteral("marker-color")) { + // Even though the Simplestyle spec allows colors to omit the leading "#", this + // implementation assumes it is always present, as this then allows named colors + // understood by QColor as an extension + QColor color = QColor(propertyValue); + if (color.isValid()) { + iconStyle.setColor(color); // Currently ignored by Marble + } else { + qDebug() << "Ignoring invalid marker-color property:" << propertyValue; + } + + } else if (propertyKey == QStringLiteral("stroke")) { + QColor color = QColor(propertyValue); // Assume leading "#" is present + if (color.isValid()) { + color.setAlpha(lineStyle.color().alpha()); + lineStyle.setColor(color); + } else { + qDebug() << "Ignoring invalid stroke property:" << propertyValue; + } + + } else if (propertyKey == QStringLiteral("stroke-opacity")) { + bool ok; + float opacity = propertyValue.toFloat(&ok); + if (ok && opacity >= 0.0 && opacity <= 1.0) { + QColor color = lineStyle.color(); + color.setAlphaF(opacity); + lineStyle.setColor(color); + } else { + qDebug() << "Ignoring invalid stroke-opacity property:" << propertyValue; + } + + } else if (propertyKey == QStringLiteral("stroke-width")) { + bool ok; + float width = propertyValue.toFloat(&ok); + if (ok && width >= 0.0) { + lineStyle.setWidth(width); + } else { + qDebug() << "Ignoring invalid stroke-width property:" << propertyValue; + } + + } else if (propertyKey == QStringLiteral("fill")) { + QColor color = QColor(propertyValue); // Assume leading "#" is present + if (color.isValid()) { + color.setAlpha(polyStyle.color().alpha()); + polyStyle.setColor(color); + } else { + qDebug() << "Ignoring invalid fill property:" << propertyValue; + } + + } else if (propertyKey == QStringLiteral("fill-opacity")) { + bool ok; + float opacity = propertyValue.toFloat(&ok); + if (ok && opacity >= 0.0 && opacity <= 1.0) { + QColor color = polyStyle.color(); + color.setAlphaF(opacity); + polyStyle.setColor(color); + } else { + qDebug() << "Ignoring invalid fill-opacity property:" << propertyValue; + } + + } else { + // Property is not defined by the Simplestyle spec + osmData.addTag(propertyKey, propertyValue); + } + } - labelStyle.setColor(QApplication::palette().brightText().color()); - labelStyle.setGlow(true); + style->setIconStyle(iconStyle); + style->setLineStyle(lineStyle); + style->setPolyStyle(polyStyle); + style->setLabelStyle(*m_labelStyle); + placemark->setStyle(style); - polyStyle.setFill(true); - polyStyle.setOutline(true); + placemark->setOsmData(osmData); + placemark->setVisible(true); - // Parse any associated properties + const GeoDataPlacemark::GeoDataVisualCategory category = + StyleBuilder::determineVisualCategory(osmData); + if (category != GeoDataPlacemark::None) { + placemark->setVisualCategory(category); + } - const QJsonObject propertiesObject = jsonObject.value(QStringLiteral("properties")).toObject(); - QJsonObject::ConstIterator iter = propertiesObject.begin(); - const QJsonObject::ConstIterator end = propertiesObject.end(); - - OsmPlacemarkData osmData; - - for ( ; iter != end; ++iter) { - // Pass the value through QVariant to also get booleans and numbers - const QString propertyValue = iter.value().toVariant().toString(); - const QString propertyKey = iter.key(); - - if (iter.value().isObject() || iter.value().isArray()) { - qDebug() << "Skipping unsupported JSON property containing an object or array:" << propertyKey; - continue; - } - - if (propertyKey == QStringLiteral("name")) { - // The "name" property is not defined in the Simplestyle specification, but is used - // extensively in the wild. Treat "name" and "title" essentially the same for the - // purposes of placemarks (although osmData tags will preserve the distinction). - - placemark->setName(propertyValue); - osmData.addTag(propertyKey, propertyValue); - - } else if (propertyKey == QStringLiteral("title")) { - placemark->setName(propertyValue); - osmData.addTag(propertyKey, propertyValue); - - } else if (propertyKey == QStringLiteral("description")) { - placemark->setDescription(propertyValue); - osmData.addTag(propertyKey, propertyValue); - - } else if (propertyKey == QStringLiteral("marker-size")) { - // TODO: Implement marker-size handling - - } else if (propertyKey == QStringLiteral("marker-symbol")) { - // TODO: Implement marker-symbol handling - - } else if (propertyKey == QStringLiteral("marker-color")) { - // Even though the Simplestyle spec allows colors to omit the leading "#", this - // implementation assumes it is always present, as this then allows named colors - // understood by QColor as an extension - QColor color = QColor(propertyValue); - if (color.isValid()) { - iconStyle.setColor(color); - } else { - qDebug() << "Ignoring invalid marker-color property:" << propertyValue; - } - - } else if (propertyKey == QStringLiteral("stroke")) { - QColor color = QColor(propertyValue); // Assume leading "#" is present - if (color.isValid()) { - color.setAlpha(lineStyle.color().alpha()); - lineStyle.setColor(color); - } else { - qDebug() << "Ignoring invalid stroke property:" << propertyValue; - } - - } else if (propertyKey == QStringLiteral("stroke-opacity")) { - bool ok; - float opacity = propertyValue.toFloat(&ok); - if (ok && opacity >= 0.0 && opacity <= 1.0) { - QColor color = lineStyle.color(); - color.setAlphaF(opacity); - lineStyle.setColor(color); - } else { - qDebug() << "Ignoring invalid stroke-opacity property:" << propertyValue; - } - - } else if (propertyKey == QStringLiteral("stroke-width")) { - bool ok; - float width = propertyValue.toFloat(&ok); - if (ok && width >= 0.0) { - lineStyle.setWidth(width); - } else { - qDebug() << "Ignoring invalid stroke-width property:" << propertyValue; - } - - } else if (propertyKey == QStringLiteral("fill")) { - QColor color = QColor(propertyValue); // Assume leading "#" is present - if (color.isValid()) { - color.setAlpha(polyStyle.color().alpha()); - polyStyle.setColor(color); - } else { - qDebug() << "Ignoring invalid fill property:" << propertyValue; - } - - } else if (propertyKey == QStringLiteral("fill-opacity")) { - bool ok; - float opacity = propertyValue.toFloat(&ok); - if (ok && opacity >= 0.0 && opacity <= 1.0) { - QColor color = polyStyle.color(); - color.setAlphaF(opacity); - polyStyle.setColor(color); - } else { - qDebug() << "Ignoring invalid fill-opacity property:" << propertyValue; - } - - } else { - // Property is not defined by the Simplestyle spec - osmData.addTag(propertyKey, propertyValue); - } - } - - style->setIconStyle(iconStyle); - style->setLineStyle(lineStyle); - style->setPolyStyle(polyStyle); - placemark->setStyle(style); - - placemark->setOsmData(osmData); - placemark->setVisible(true); - - const GeoDataPlacemark::GeoDataVisualCategory category = - StyleBuilder::determineVisualCategory(osmData); - if (category != GeoDataPlacemark::None) { - placemark->setVisualCategory(category); - } - - m_document->append(placemark); - return true; + m_document->append(placemark); + return true; } else { - qDebug() << "Missing FeatureCollection or Feature object in GeoJSON file"; - return false; + qDebug() << "Missing FeatureCollection or Feature object in GeoJSON file"; + return false; } } bool JsonParser::parseGeoJsonSubLevel( const QJsonObject& jsonObject, - QVector& geometryList ) + QVector& geometryList, bool& hasPoints ) { // The GeoJSON object type const QString jsonObjectType = jsonObject.value(QStringLiteral("type")).toString(); if (jsonObjectType == QStringLiteral("FeatureCollection") - || jsonObjectType == QStringLiteral("Feature")) { + || jsonObjectType == QStringLiteral("Feature")) { - qDebug() << "Cannot have FeatureCollection or Feature objects at this level of the GeoJSON file"; - return false; + qDebug() << "Cannot have FeatureCollection or Feature objects at this level of the GeoJSON file"; + return false; } else if (jsonObjectType == QStringLiteral("GeometryCollection")) { - // Handle the GeometryCollection object, which may contain multiple geometry objects + // Handle the GeometryCollection object, which may contain multiple geometry objects - const QJsonArray geometryArray = jsonObject.value(QStringLiteral("geometries")).toArray(); - for (int geometryIndex = 0; geometryIndex < geometryArray.size(); ++geometryIndex) { - if (! parseGeoJsonSubLevel( geometryArray[geometryIndex].toObject(), geometryList )) { - return false; - } - } + const QJsonArray geometryArray = jsonObject.value(QStringLiteral("geometries")).toArray(); + for (int geometryIndex = 0; geometryIndex < geometryArray.size(); ++geometryIndex) { + if (! parseGeoJsonSubLevel( geometryArray[geometryIndex].toObject(), geometryList, hasPoints )) { + return false; + } + } - return true; + return true; } // Handle remaining GeoJSON objects, which each have a "coordinates" member (an array) const QJsonArray coordinateArray = jsonObject.value(QStringLiteral("coordinates")).toArray(); if (jsonObjectType == QStringLiteral("Point")) { - // A Point object has a single GeoJSON position: an array of at least two values + // A Point object has a single GeoJSON position: an array of at least two values - GeoDataPoint* geom = new GeoDataPoint(); - const qreal lon = coordinateArray.at(0).toDouble(); - const qreal lat = coordinateArray.at(1).toDouble(); - const qreal alt = coordinateArray.at(2).toDouble(); // If missing, uses 0 as the default + GeoDataPoint* geom = new GeoDataPoint(); + const qreal lon = coordinateArray.at(0).toDouble(); + const qreal lat = coordinateArray.at(1).toDouble(); + const qreal alt = coordinateArray.at(2).toDouble(); // If missing, uses 0 as the default - geom->setCoordinates( GeoDataCoordinates( lon, lat, alt, GeoDataCoordinates::Degree )); - geometryList.append(geom); + geom->setCoordinates( GeoDataCoordinates( lon, lat, alt, GeoDataCoordinates::Degree )); + geometryList.append(geom); - return true; + hasPoints = true; + return true; } else if (jsonObjectType == QStringLiteral("MultiPoint")) { - // A MultiPoint object has an array of GeoJSON positions (ie, a two-level array) + // A MultiPoint object has an array of GeoJSON positions (ie, a two-level array) - for (int positionIndex = 0; positionIndex < coordinateArray.size(); ++positionIndex) { - const QJsonArray positionArray = coordinateArray[positionIndex].toArray(); + for (int positionIndex = 0; positionIndex < coordinateArray.size(); ++positionIndex) { + const QJsonArray positionArray = coordinateArray[positionIndex].toArray(); - GeoDataPoint* geom = new GeoDataPoint(); - const qreal lon = positionArray.at(0).toDouble(); - const qreal lat = positionArray.at(1).toDouble(); - const qreal alt = positionArray.at(2).toDouble(); + GeoDataPoint* geom = new GeoDataPoint(); + const qreal lon = positionArray.at(0).toDouble(); + const qreal lat = positionArray.at(1).toDouble(); + const qreal alt = positionArray.at(2).toDouble(); - geom->setCoordinates( GeoDataCoordinates( lon, lat, alt, GeoDataCoordinates::Degree )); - geometryList.append(geom); - } + geom->setCoordinates( GeoDataCoordinates( lon, lat, alt, GeoDataCoordinates::Degree )); + geometryList.append(geom); + } - return true; + hasPoints = true; + return true; } else if (jsonObjectType == QStringLiteral("LineString")) { - // A LineString object has an array of GeoJSON positions (ie, a two-level array) + // A LineString object has an array of GeoJSON positions (ie, a two-level array) - GeoDataLineString* geom = new GeoDataLineString( RespectLatitudeCircle | Tessellate ); + GeoDataLineString* geom = new GeoDataLineString( RespectLatitudeCircle | Tessellate ); - for (int positionIndex = 0; positionIndex < coordinateArray.size(); ++positionIndex) { - const QJsonArray positionArray = coordinateArray[positionIndex].toArray(); + for (int positionIndex = 0; positionIndex < coordinateArray.size(); ++positionIndex) { + const QJsonArray positionArray = coordinateArray[positionIndex].toArray(); - const qreal lon = positionArray.at(0).toDouble(); - const qreal lat = positionArray.at(1).toDouble(); - const qreal alt = positionArray.at(2).toDouble(); + const qreal lon = positionArray.at(0).toDouble(); + const qreal lat = positionArray.at(1).toDouble(); + const qreal alt = positionArray.at(2).toDouble(); - geom->append( GeoDataCoordinates( lon, lat, alt, GeoDataCoordinates::Degree )); - } - geometryList.append(geom); + geom->append( GeoDataCoordinates( lon, lat, alt, GeoDataCoordinates::Degree )); + } + geometryList.append(geom); - return true; + return true; } else if (jsonObjectType == QStringLiteral("MultiLineString")) { - // A MultiLineString object has an array of arrays of GeoJSON positions (three-level) + // A MultiLineString object has an array of arrays of GeoJSON positions (three-level) - for (int lineStringIndex = 0; lineStringIndex < coordinateArray.size(); ++lineStringIndex) { - const QJsonArray lineStringArray = coordinateArray[lineStringIndex].toArray(); + for (int lineStringIndex = 0; lineStringIndex < coordinateArray.size(); ++lineStringIndex) { + const QJsonArray lineStringArray = coordinateArray[lineStringIndex].toArray(); - GeoDataLineString* geom = new GeoDataLineString( RespectLatitudeCircle | Tessellate ); + GeoDataLineString* geom = new GeoDataLineString( RespectLatitudeCircle | Tessellate ); - for (int positionIndex = 0; positionIndex < lineStringArray.size(); ++positionIndex) { - const QJsonArray positionArray = lineStringArray[positionIndex].toArray(); + for (int positionIndex = 0; positionIndex < lineStringArray.size(); ++positionIndex) { + const QJsonArray positionArray = lineStringArray[positionIndex].toArray(); - const qreal lon = positionArray.at(0).toDouble(); - const qreal lat = positionArray.at(1).toDouble(); - const qreal alt = positionArray.at(2).toDouble(); + const qreal lon = positionArray.at(0).toDouble(); + const qreal lat = positionArray.at(1).toDouble(); + const qreal alt = positionArray.at(2).toDouble(); - geom->append( GeoDataCoordinates( lon, lat, alt, GeoDataCoordinates::Degree )); - } - geometryList.append(geom); - } + geom->append( GeoDataCoordinates( lon, lat, alt, GeoDataCoordinates::Degree )); + } + geometryList.append(geom); + } - return true; + return true; } else if (jsonObjectType == QStringLiteral("Polygon")) { - // A Polygon object has an array of arrays of GeoJSON positions: the first array within the - // top-level Polygon coordinates array is the outer boundary, following arrays are inner - // holes (if any) + // A Polygon object has an array of arrays of GeoJSON positions: the first array within the + // top-level Polygon coordinates array is the outer boundary, following arrays are inner + // holes (if any) - GeoDataPolygon* geom = new GeoDataPolygon( RespectLatitudeCircle | Tessellate ); + GeoDataPolygon* geom = new GeoDataPolygon( RespectLatitudeCircle | Tessellate ); - for (int ringIndex = 0; ringIndex < coordinateArray.size(); ++ringIndex) { - const QJsonArray ringArray = coordinateArray[ringIndex].toArray(); + for (int ringIndex = 0; ringIndex < coordinateArray.size(); ++ringIndex) { + const QJsonArray ringArray = coordinateArray[ringIndex].toArray(); - GeoDataLinearRing linearRing; + GeoDataLinearRing linearRing; - for (int positionIndex = 0; positionIndex < ringArray.size(); ++positionIndex) { - const QJsonArray positionArray = ringArray[positionIndex].toArray(); + for (int positionIndex = 0; positionIndex < ringArray.size(); ++positionIndex) { + const QJsonArray positionArray = ringArray[positionIndex].toArray(); - const qreal lon = positionArray.at(0).toDouble(); - const qreal lat = positionArray.at(1).toDouble(); - const qreal alt = positionArray.at(2).toDouble(); + const qreal lon = positionArray.at(0).toDouble(); + const qreal lat = positionArray.at(1).toDouble(); + const qreal alt = positionArray.at(2).toDouble(); - linearRing.append( GeoDataCoordinates( lon, lat, alt, GeoDataCoordinates::Degree )); - } + linearRing.append( GeoDataCoordinates( lon, lat, alt, GeoDataCoordinates::Degree )); + } - if (ringIndex == 0) { - // Outer boundary of the polygon - geom->setOuterBoundary(linearRing); - } else { - geom->appendInnerBoundary(linearRing); - } - } - geometryList.append(geom); + if (ringIndex == 0) { + // Outer boundary of the polygon + geom->setOuterBoundary(linearRing); + } else { + geom->appendInnerBoundary(linearRing); + } + } + geometryList.append(geom); - return true; + return true; } else if (jsonObjectType == QStringLiteral("MultiPolygon")) { - // A MultiPolygon object has an array of Polygon arrays (ie, a four-level array) + // A MultiPolygon object has an array of Polygon arrays (ie, a four-level array) - for (int polygonIndex = 0; polygonIndex < coordinateArray.size(); ++polygonIndex) { - const QJsonArray polygonArray = coordinateArray[polygonIndex].toArray(); + for (int polygonIndex = 0; polygonIndex < coordinateArray.size(); ++polygonIndex) { + const QJsonArray polygonArray = coordinateArray[polygonIndex].toArray(); - GeoDataPolygon* geom = new GeoDataPolygon( RespectLatitudeCircle | Tessellate ); + GeoDataPolygon* geom = new GeoDataPolygon( RespectLatitudeCircle | Tessellate ); - for (int ringIndex = 0; ringIndex < polygonArray.size(); ++ringIndex) { - const QJsonArray ringArray = polygonArray[ringIndex].toArray(); + for (int ringIndex = 0; ringIndex < polygonArray.size(); ++ringIndex) { + const QJsonArray ringArray = polygonArray[ringIndex].toArray(); - GeoDataLinearRing linearRing; + GeoDataLinearRing linearRing; - for (int positionIndex = 0; positionIndex < ringArray.size(); ++positionIndex) { - const QJsonArray positionArray = ringArray[positionIndex].toArray(); + for (int positionIndex = 0; positionIndex < ringArray.size(); ++positionIndex) { + const QJsonArray positionArray = ringArray[positionIndex].toArray(); - const qreal lon = positionArray.at(0).toDouble(); - const qreal lat = positionArray.at(1).toDouble(); - const qreal alt = positionArray.at(2).toDouble(); + const qreal lon = positionArray.at(0).toDouble(); + const qreal lat = positionArray.at(1).toDouble(); + const qreal alt = positionArray.at(2).toDouble(); - linearRing.append( GeoDataCoordinates( lon, lat, alt, GeoDataCoordinates::Degree )); - } + linearRing.append( GeoDataCoordinates( lon, lat, alt, GeoDataCoordinates::Degree )); + } - if (ringIndex == 0) { - // Outer boundary of the polygon - geom->setOuterBoundary(linearRing); - } else { - geom->appendInnerBoundary(linearRing); - } - } - geometryList.append(geom); - } + if (ringIndex == 0) { + // Outer boundary of the polygon + geom->setOuterBoundary(linearRing); + } else { + geom->appendInnerBoundary(linearRing); + } + } + geometryList.append(geom); + } - return true; + return true; } else if (jsonObjectType == QStringLiteral("")) { - // Unlocated Feature objects have a null value for "geometry" (RFC7946 section 3.2) - return true; + // Unlocated Feature objects have a null value for "geometry" (RFC7946 section 3.2) + return true; } else { - qDebug() << "Unknown GeoJSON object type" << jsonObjectType; - return false; + qDebug() << "Unknown GeoJSON object type" << jsonObjectType; + return false; } }