Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fix GeoJSON output of MultiPolygon/MultiSurface
There was a lack of a JSon array around rings of a polygon.
This issue is not present in 3.4

Also fixes an issue with gcc 5.5 of Ubuntu 16.04 that doesn't behave
properly with C++11 brace syntax with code from nlohmann/json.hpp.
The code compiles but the result is invalid: `json foo{ json::array{} }`
is serialized as [[]] instead of []. So use old-style constructor
instead: `json foo( json::array() )`

This PR is on top of #30010
  • Loading branch information
rouault authored and nyalldawson committed May 30, 2019
1 parent 5d6917e commit e4582c9
Show file tree
Hide file tree
Showing 10 changed files with 21 additions and 19 deletions.
2 changes: 1 addition & 1 deletion src/core/geometry/qgscurvepolygon.cpp
Expand Up @@ -403,7 +403,7 @@ QDomElement QgsCurvePolygon::asGml3( QDomDocument &doc, int precision, const QSt

json QgsCurvePolygon::asJsonObject( int precision ) const
{
json coordinates { json::array( )};
json coordinates( json::array( ) );
if ( exteriorRing() )
{
std::unique_ptr< QgsLineString > exteriorLineString( exteriorRing()->curveToLine() );
Expand Down
2 changes: 1 addition & 1 deletion src/core/geometry/qgsgeometrycollection.cpp
Expand Up @@ -420,7 +420,7 @@ QDomElement QgsGeometryCollection::asGml3( QDomDocument &doc, int precision, con

json QgsGeometryCollection::asJsonObject( int precision ) const
{
json coordinates { json::array( ) };
json coordinates( json::array( ) );
for ( const QgsAbstractGeometry *geom : qgis::as_const( mGeometries ) )
{
coordinates.push_back( geom->asJsonObject( precision ) );
Expand Down
2 changes: 1 addition & 1 deletion src/core/geometry/qgsgeometryutils.cpp
Expand Up @@ -1200,7 +1200,7 @@ QString QgsGeometryUtils::pointsToJSON( const QgsPointSequence &points, int prec

json QgsGeometryUtils::pointsToJson( const QgsPointSequence &points, int precision )
{
json coordinates { json::array() };
json coordinates( json::array() );
for ( const QgsPoint &p : points )
{
if ( p.is3D() )
Expand Down
2 changes: 1 addition & 1 deletion src/core/geometry/qgsmulticurve.cpp
Expand Up @@ -113,7 +113,7 @@ QDomElement QgsMultiCurve::asGml3( QDomDocument &doc, int precision, const QStri

json QgsMultiCurve::asJsonObject( int precision ) const
{
json coordinates { json::array( ) };
json coordinates( json::array( ) );
for ( const QgsAbstractGeometry *geom : qgis::as_const( mGeometries ) )
{
if ( qgsgeometry_cast<const QgsCurve *>( geom ) )
Expand Down
2 changes: 1 addition & 1 deletion src/core/geometry/qgsmultilinestring.cpp
Expand Up @@ -100,7 +100,7 @@ QDomElement QgsMultiLineString::asGml3( QDomDocument &doc, int precision, const

json QgsMultiLineString::asJsonObject( int precision ) const
{
json coordinates { json::array( ) };
json coordinates( json::array( ) );
for ( const QgsAbstractGeometry *geom : mGeometries )
{
if ( qgsgeometry_cast<const QgsCurve *>( geom ) )
Expand Down
6 changes: 3 additions & 3 deletions src/core/geometry/qgsmultipolygon.cpp
Expand Up @@ -101,12 +101,12 @@ QDomElement QgsMultiPolygon::asGml3( QDomDocument &doc, int precision, const QSt

json QgsMultiPolygon::asJsonObject( int precision ) const
{
json polygons { json::array( ) };
json polygons( json::array( ) );
for ( const QgsAbstractGeometry *geom : qgis::as_const( mGeometries ) )
{
json coordinates { json::array( ) };
if ( qgsgeometry_cast<const QgsPolygon *>( geom ) )
{
json coordinates( json::array( ) );
const QgsPolygon *polygon = static_cast<const QgsPolygon *>( geom );

std::unique_ptr< QgsLineString > exteriorLineString( polygon->exteriorRing()->curveToLine() );
Expand All @@ -122,8 +122,8 @@ json QgsMultiPolygon::asJsonObject( int precision ) const
interiorLineString->points( interiorPts );
coordinates.push_back( QgsGeometryUtils::pointsToJson( interiorPts, precision ) );
}
polygons.push_back( coordinates );
}
polygons.push_back( coordinates );
}
return
{
Expand Down
6 changes: 4 additions & 2 deletions src/core/geometry/qgsmultisurface.cpp
Expand Up @@ -112,11 +112,12 @@ QDomElement QgsMultiSurface::asGml3( QDomDocument &doc, int precision, const QSt

json QgsMultiSurface::asJsonObject( int precision ) const
{
json coordinates { json::array( ) };
json polygons( json::array( ) );
for ( const QgsAbstractGeometry *geom : qgis::as_const( mGeometries ) )
{
if ( qgsgeometry_cast<const QgsSurface *>( geom ) )
{
json coordinates( json::array( ) );
std::unique_ptr< QgsPolygon >polygon( static_cast<const QgsSurface *>( geom )->surfaceToPolygon() );
std::unique_ptr< QgsLineString > exteriorLineString( polygon->exteriorRing()->curveToLine() );
QgsPointSequence exteriorPts;
Expand All @@ -131,12 +132,13 @@ json QgsMultiSurface::asJsonObject( int precision ) const
interiorLineString->points( interiorPts );
coordinates.push_back( QgsGeometryUtils::pointsToJson( interiorPts, precision ) );
}
polygons.push_back( coordinates );
}
}
return
{
{ "type", "MultiPolygon" },
{ "coordinates", coordinates }
{ "coordinates", polygons }
};
}

Expand Down
2 changes: 1 addition & 1 deletion src/core/qgsjsonutils.cpp
Expand Up @@ -319,7 +319,7 @@ QVariantList QgsJsonUtils::parseArray( const QString &json, QVariant::Type type
QVariantList result;
try
{
const auto jObj { json::parse( json.toStdString() ) };
const auto jObj( json::parse( json.toStdString() ) );
if ( ! jObj.is_array() )
{
throw json::parse_error::create( 0, 0, QStringLiteral( "JSON value must be an array" ).toStdString() );
Expand Down
6 changes: 3 additions & 3 deletions tests/src/core/testqgsgeometry.cpp
Expand Up @@ -13956,15 +13956,15 @@ void TestQgsGeometry::multiSurface()
QGSCOMPAREGML( elemToString( QgsMultiSurface().asGml3( doc ) ), expectedGML3empty );

// as JSON
QString expectedSimpleJson( "{\"coordinates\":[[[7.0,17.0],[7.0,13.0],[3.0,13.0],[7.0,17.0]],[[27.0,37.0],[27.0,43.0],[43.0,43.0],[27.0,37.0]]],\"type\":\"MultiPolygon\"}" );
QString expectedSimpleJson( "{\"coordinates\":[[[[7.0,17.0],[7.0,13.0],[3.0,13.0],[7.0,17.0]]],[[[27.0,37.0],[27.0,43.0],[43.0,43.0],[27.0,37.0]]]],\"type\":\"MultiPolygon\"}" );
res = exportC.asJson( 1 );
QCOMPARE( res, expectedSimpleJson );

lineRing.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 17, 27 ) << QgsPoint( QgsWkbTypes::Point, 17, 28 ) << QgsPoint( QgsWkbTypes::Point, 18, 28 ) << QgsPoint( QgsWkbTypes::Point, 17, 27 ) ) ;
part.addInteriorRing( lineRing.clone() );
exportC.addGeometry( part.clone() );

QString expectedJsonWithRings( "{\"coordinates\":[[[7.0,17.0],[7.0,13.0],[3.0,13.0],[7.0,17.0]],[[27.0,37.0],[27.0,43.0],[43.0,43.0],[27.0,37.0]],[[27.0,37.0],[27.0,43.0],[43.0,43.0],[27.0,37.0]],[[17.0,27.0],[17.0,28.0],[18.0,28.0],[17.0,27.0]]],\"type\":\"MultiPolygon\"}" );
QString expectedJsonWithRings( "{\"coordinates\":[[[[7.0,17.0],[7.0,13.0],[3.0,13.0],[7.0,17.0]]],[[[27.0,37.0],[27.0,43.0],[43.0,43.0],[27.0,37.0]]],[[[27.0,37.0],[27.0,43.0],[43.0,43.0],[27.0,37.0]],[[17.0,27.0],[17.0,28.0],[18.0,28.0],[17.0,27.0]]]],\"type\":\"MultiPolygon\"}" );
res = exportC.asJson( 1 );
QCOMPARE( res, expectedJsonWithRings );

Expand All @@ -13974,7 +13974,7 @@ void TestQgsGeometry::multiSurface()
part.setExteriorRing( lineRing.clone() );
exportFloat.addGeometry( part.clone() );

QString expectedJsonPrec3( QStringLiteral( "{\"coordinates\":[[[0.123,0.123],[0.123,1.234],[1.234,1.234],[0.123,0.123]]],\"type\":\"MultiPolygon\"}" ) );
QString expectedJsonPrec3( QStringLiteral( "{\"coordinates\":[[[[0.123,0.123],[0.123,1.234],[1.234,1.234],[0.123,0.123]]]],\"type\":\"MultiPolygon\"}" ) );
res = exportFloat.asJson( 3 );
QCOMPARE( res, expectedJsonPrec3 );

Expand Down
10 changes: 5 additions & 5 deletions tests/src/core/testqgsjsonutils.cpp
Expand Up @@ -139,25 +139,25 @@ void TestQgsJsonUtils::testDoubleList()

void TestQgsJsonUtils::testExportAttributesJson_data()
{
QTest::addColumn<JsonAlgs>( "JsonAlgs" );
QTest::addColumn<JsonAlgs>( "jsonAlg" );
QTest::newRow( "Use json" ) << JsonAlgs::Json;
QTest::newRow( "Use old string concat" ) << JsonAlgs::String;
}

void TestQgsJsonUtils::testExportAttributesJson()
{

QFETCH( enum JsonAlgs, JsonAlgs );
QFETCH( enum JsonAlgs, jsonAlg );

QgsVectorLayer vl { QStringLiteral( "Point?field=fldtxt:string&field=fldint:integer&field=flddbl:double" ), QStringLiteral( "mem" ), QStringLiteral( "memory" ) };
QgsFeature feature { vl.fields() };
feature.setAttributes( QgsAttributes() << QStringLiteral( "a value" ) << 1 << 2.0 );

if ( JsonAlgs == JsonAlgs::Json ) // 0.0022
if ( jsonAlg == JsonAlgs::Json ) // 0.0022
{
QBENCHMARK
{
json j { QgsJsonUtils::exportAttributesToJsonObject( feature, &vl ) };
json j( QgsJsonUtils::exportAttributesToJsonObject( feature, &vl ) );
QCOMPARE( QString::fromStdString( j.dump() ), QStringLiteral( R"raw({"flddbl":2.0,"fldint":1,"fldtxt":"a value"})raw" ) );
}
}
Expand Down Expand Up @@ -188,7 +188,7 @@ void TestQgsJsonUtils::testExportFeatureJson()
",\"id\":0,\"properties\":{\"flddbl\":2.0,\"fldint\":1,\"fldtxt\":\"a value\"}"
",\"type\":\"Feature\"}" ) };

const auto j { exporter.exportFeatureToJsonObject( feature ) };
const auto j( exporter.exportFeatureToJsonObject( feature ) );
QCOMPARE( QString::fromStdString( j.dump() ), expectedJson );
const auto json { exporter.exportFeature( feature ) };
QCOMPARE( json, expectedJson );
Expand Down

0 comments on commit e4582c9

Please sign in to comment.