Skip to content

Commit 766d7e4

Browse files
committed
[asf] Fix parsing of polygons
1 parent adf4a32 commit 766d7e4

File tree

3 files changed

+95
-34
lines changed

3 files changed

+95
-34
lines changed

src/providers/arcgisrest/qgsarcgisrestutils.cpp

+51-31
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,13 @@
1818
#include "qgslogger.h"
1919
#include "qgsnetworkaccessmanager.h"
2020
#include "qgsrectangle.h"
21-
#include "geometry/qgsabstractgeometry.h"
22-
#include "geometry/qgscircularstring.h"
23-
#include "geometry/qgscompoundcurve.h"
24-
#include "geometry/qgscurvepolygon.h"
25-
#include "geometry/qgslinestring.h"
26-
#include "geometry/qgsmultipoint.h"
27-
#include "geometry/qgsmulticurve.h"
28-
#include "geometry/qgspolygon.h"
29-
#include "geometry/qgspoint.h"
3021
#include "qgsfeedback.h"
3122
#include "qgssymbol.h"
3223
#include "qgssymbollayer.h"
3324
#include "qgsauthmanager.h"
3425
#include "qgssettings.h"
3526
#include "qgslinesymbollayer.h"
3627
#include "qgsfillsymbollayer.h"
37-
#include "qgsmarkersymbollayer.h"
3828
#include "qgsrenderer.h"
3929
#include "qgssinglesymbolrenderer.h"
4030
#include "qgscategorizedsymbolrenderer.h"
@@ -88,7 +78,7 @@ QgsWkbTypes::Type QgsArcGisRestUtils::mapEsriGeometryType( const QString &esriGe
8878
else if ( esriGeometryType == QLatin1String( "esriGeometryPolyline" ) )
8979
return QgsWkbTypes::MultiCurve;
9080
else if ( esriGeometryType == QLatin1String( "esriGeometryPolygon" ) )
91-
return QgsWkbTypes::Polygon;
81+
return QgsWkbTypes::MultiPolygon;
9282
else if ( esriGeometryType == QLatin1String( "esriGeometryEnvelope" ) )
9383
return QgsWkbTypes::Polygon;
9484
// Unsupported (either by qgis, or format unspecified by the specification)
@@ -109,7 +99,7 @@ QgsWkbTypes::Type QgsArcGisRestUtils::mapEsriGeometryType( const QString &esriGe
10999
return QgsWkbTypes::Unknown;
110100
}
111101

112-
static std::unique_ptr< QgsPoint > parsePoint( const QVariantList &coordList, QgsWkbTypes::Type pointType )
102+
std::unique_ptr< QgsPoint > QgsArcGisRestUtils::parsePoint( const QVariantList &coordList, QgsWkbTypes::Type pointType )
113103
{
114104
int nCoords = coordList.size();
115105
if ( nCoords < 2 )
@@ -124,7 +114,7 @@ static std::unique_ptr< QgsPoint > parsePoint( const QVariantList &coordList, Qg
124114
return qgis::make_unique< QgsPoint >( pointType, x, y, z, m );
125115
}
126116

127-
static std::unique_ptr< QgsCircularString > parseCircularString( const QVariantMap &curveData, QgsWkbTypes::Type pointType, const QgsPoint &startPoint )
117+
std::unique_ptr< QgsCircularString > QgsArcGisRestUtils::parseCircularString( const QVariantMap &curveData, QgsWkbTypes::Type pointType, const QgsPoint &startPoint )
128118
{
129119
const QVariantList coordsList = curveData[QStringLiteral( "c" )].toList();
130120
if ( coordsList.isEmpty() )
@@ -145,7 +135,7 @@ static std::unique_ptr< QgsCircularString > parseCircularString( const QVariantM
145135
return curve;
146136
}
147137

148-
static std::unique_ptr< QgsCompoundCurve > parseCompoundCurve( const QVariantList &curvesList, QgsWkbTypes::Type pointType )
138+
std::unique_ptr< QgsCompoundCurve > QgsArcGisRestUtils::parseCompoundCurve( const QVariantList &curvesList, QgsWkbTypes::Type pointType )
149139
{
150140
// [[6,3],[5,3],{"b":[[3,2],[6,1],[2,4]]},[1,2],{"c": [[3,3],[1,4]]}]
151141
std::unique_ptr< QgsCompoundCurve > compoundCurve = qgis::make_unique< QgsCompoundCurve >();
@@ -186,7 +176,7 @@ static std::unique_ptr< QgsCompoundCurve > parseCompoundCurve( const QVariantLis
186176
return compoundCurve;
187177
}
188178

189-
static std::unique_ptr< QgsPoint > parseEsriGeometryPoint( const QVariantMap &geometryData, QgsWkbTypes::Type pointType )
179+
std::unique_ptr< QgsPoint > QgsArcGisRestUtils::parseEsriGeometryPoint( const QVariantMap &geometryData, QgsWkbTypes::Type pointType )
190180
{
191181
// {"x" : <x>, "y" : <y>, "z" : <z>, "m" : <m>}
192182
bool xok = false, yok = false;
@@ -199,7 +189,7 @@ static std::unique_ptr< QgsPoint > parseEsriGeometryPoint( const QVariantMap &ge
199189
return qgis::make_unique< QgsPoint >( pointType, x, y, z, m );
200190
}
201191

202-
static std::unique_ptr< QgsMultiPoint > parseEsriGeometryMultiPoint( const QVariantMap &geometryData, QgsWkbTypes::Type pointType )
192+
std::unique_ptr< QgsMultiPoint > QgsArcGisRestUtils::parseEsriGeometryMultiPoint( const QVariantMap &geometryData, QgsWkbTypes::Type pointType )
203193
{
204194
// {"points" : [[ <x1>, <y1>, <z1>, <m1> ] , [ <x2>, <y2>, <z2>, <m2> ], ... ]}
205195
const QVariantList coordsList = geometryData[QStringLiteral( "points" )].toList();
@@ -230,7 +220,7 @@ static std::unique_ptr< QgsMultiPoint > parseEsriGeometryMultiPoint( const QVari
230220
return multiPoint;
231221
}
232222

233-
static std::unique_ptr< QgsMultiCurve > parseEsriGeometryPolyline( const QVariantMap &geometryData, QgsWkbTypes::Type pointType )
223+
std::unique_ptr< QgsMultiCurve > QgsArcGisRestUtils::parseEsriGeometryPolyline( const QVariantMap &geometryData, QgsWkbTypes::Type pointType )
234224
{
235225
// {"curvePaths": [[[0,0], {"c": [[3,3],[1,4]]} ]]}
236226
QVariantList pathsList;
@@ -253,7 +243,7 @@ static std::unique_ptr< QgsMultiCurve > parseEsriGeometryPolyline( const QVarian
253243
return multiCurve;
254244
}
255245

256-
static std::unique_ptr< QgsCurvePolygon > parseEsriGeometryPolygon( const QVariantMap &geometryData, QgsWkbTypes::Type pointType )
246+
std::unique_ptr< QgsMultiSurface > QgsArcGisRestUtils::parseEsriGeometryPolygon( const QVariantMap &geometryData, QgsWkbTypes::Type pointType )
257247
{
258248
// {"curveRings": [[[0,0], {"c": [[3,3],[1,4]]} ]]}
259249
QVariantList ringsList;
@@ -263,26 +253,56 @@ static std::unique_ptr< QgsCurvePolygon > parseEsriGeometryPolygon( const QVaria
263253
ringsList = geometryData[QStringLiteral( "ringPaths" )].toList();
264254
if ( ringsList.isEmpty() )
265255
return nullptr;
266-
std::unique_ptr< QgsCurvePolygon > polygon = qgis::make_unique< QgsCurvePolygon >();
267-
std::unique_ptr< QgsCompoundCurve > ext = parseCompoundCurve( ringsList.front().toList(), pointType );
268-
if ( !ext )
269-
{
270-
return nullptr;
271-
}
272-
polygon->setExteriorRing( ext.release() );
273-
for ( int i = 1, n = ringsList.size(); i < n; ++i )
256+
257+
QList< QgsCompoundCurve * > curves;
258+
for ( int i = 0, n = ringsList.size(); i < n; ++i )
274259
{
275260
std::unique_ptr< QgsCompoundCurve > curve = parseCompoundCurve( ringsList[i].toList(), pointType );
276261
if ( !curve )
277262
{
278-
return nullptr;
263+
continue;
264+
}
265+
curves.append( curve.release() );
266+
}
267+
if ( curves.count() == 0 )
268+
return nullptr;
269+
270+
std::sort( curves.begin(), curves.end(), []( const QgsCompoundCurve * a, const QgsCompoundCurve * b )->bool{ double a_area = 0.0; double b_area = 0.0; a->sumUpArea( a_area ); b->sumUpArea( b_area ); return std::abs( a_area ) > std::abs( b_area ); } );
271+
std::unique_ptr< QgsMultiSurface > result = qgis::make_unique< QgsMultiSurface >();
272+
while ( !curves.isEmpty() )
273+
{
274+
QgsCompoundCurve *exterior = curves.takeFirst();
275+
QgsCurvePolygon *newPolygon = new QgsCurvePolygon();
276+
newPolygon->setExteriorRing( exterior );
277+
std::unique_ptr<QgsGeometryEngine> engine( QgsGeometry::createGeometryEngine( newPolygon ) );
278+
engine->prepareGeometry();
279+
280+
QMutableListIterator< QgsCompoundCurve * > it( curves );
281+
while ( it.hasNext() )
282+
{
283+
QgsCompoundCurve *curve = it.next();
284+
QgsRectangle boundingBox = newPolygon->boundingBox();
285+
if ( boundingBox.intersects( curve->boundingBox() ) )
286+
{
287+
QgsPoint point = curve->startPoint();
288+
if ( engine->contains( &point ) )
289+
{
290+
newPolygon->addInteriorRing( curve );
291+
it.remove();
292+
engine.reset( QgsGeometry::createGeometryEngine( newPolygon ) );
293+
engine->prepareGeometry();
294+
}
295+
}
279296
}
280-
polygon->addInteriorRing( curve.release() );
297+
result->addGeometry( newPolygon );
281298
}
282-
return polygon;
299+
if ( result->numGeometries() == 0 )
300+
return nullptr;
301+
302+
return result;
283303
}
284304

285-
static std::unique_ptr< QgsPolygon > parseEsriEnvelope( const QVariantMap &geometryData )
305+
std::unique_ptr< QgsPolygon > QgsArcGisRestUtils::parseEsriEnvelope( const QVariantMap &geometryData )
286306
{
287307
// {"xmin" : -109.55, "ymin" : 25.76, "xmax" : -86.39, "ymax" : 49.94}
288308
bool xminOk = false, yminOk = false, xmaxOk = false, ymaxOk = false;
@@ -628,7 +648,7 @@ std::unique_ptr<QgsFillSymbol> QgsArcGisRestUtils::parseEsriFillSymbolJson( cons
628648
return symbol;
629649
}
630650

631-
QgsSimpleMarkerSymbolLayerBase::Shape parseEsriMarkerShape( const QString &style )
651+
QgsSimpleMarkerSymbolLayerBase::Shape QgsArcGisRestUtils::parseEsriMarkerShape( const QString &style )
632652
{
633653
if ( style == QLatin1String( "esriSMSCircle" ) )
634654
return QgsSimpleMarkerSymbolLayerBase::Circle;

src/providers/arcgisrest/qgsarcgisrestutils.h

+25-2
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,23 @@
1515
#ifndef QGSARCGISRESTUTILS_H
1616
#define QGSARCGISRESTUTILS_H
1717

18-
#include <QStringList>
19-
#include <QVariant>
2018
#include "qgswkbtypes.h"
2119
#include "qgsrectangle.h"
20+
#include "qgsmarkersymbollayer.h"
21+
#include "geometry/qgsabstractgeometry.h"
22+
#include "geometry/qgscircularstring.h"
23+
#include "geometry/qgscompoundcurve.h"
24+
#include "geometry/qgscurvepolygon.h"
25+
#include "geometry/qgsgeometryengine.h"
26+
#include "geometry/qgslinestring.h"
27+
#include "geometry/qgsmultipoint.h"
28+
#include "geometry/qgsmulticurve.h"
29+
#include "geometry/qgsmultisurface.h"
30+
#include "geometry/qgspolygon.h"
31+
#include "geometry/qgspoint.h"
32+
33+
#include <QStringList>
34+
#include <QVariant>
2235

2336
class QNetworkReply;
2437
class QgsNetworkAccessManager;
@@ -51,6 +64,15 @@ class QgsArcGisRestUtils
5164
static QByteArray queryService( const QUrl &url, const QString &authcfg, QString &errorTitle, QString &errorText, QgsFeedback *feedback = nullptr );
5265
static QVariantMap queryServiceJSON( const QUrl &url, const QString &authcfg, QString &errorTitle, QString &errorText, QgsFeedback *feedback = nullptr );
5366

67+
static std::unique_ptr< QgsPoint > parsePoint( const QVariantList &coordList, QgsWkbTypes::Type pointType );
68+
static std::unique_ptr< QgsCircularString > parseCircularString( const QVariantMap &curveData, QgsWkbTypes::Type pointType, const QgsPoint &startPoint );
69+
static std::unique_ptr< QgsCompoundCurve > parseCompoundCurve( const QVariantList &curvesList, QgsWkbTypes::Type pointType );
70+
static std::unique_ptr< QgsPoint > parseEsriGeometryPoint( const QVariantMap &geometryData, QgsWkbTypes::Type pointType );
71+
static std::unique_ptr< QgsMultiPoint > parseEsriGeometryMultiPoint( const QVariantMap &geometryData, QgsWkbTypes::Type pointType );
72+
static std::unique_ptr< QgsMultiCurve > parseEsriGeometryPolyline( const QVariantMap &geometryData, QgsWkbTypes::Type pointType );
73+
static std::unique_ptr< QgsMultiSurface > parseEsriGeometryPolygon( const QVariantMap &geometryData, QgsWkbTypes::Type pointType );
74+
static std::unique_ptr< QgsPolygon > parseEsriEnvelope( const QVariantMap &geometryData );
75+
5476
static std::unique_ptr< QgsSymbol > parseEsriSymbolJson( const QVariantMap &symbolData );
5577
static std::unique_ptr< QgsLineSymbol > parseEsriLineSymbolJson( const QVariantMap &symbolData );
5678
static std::unique_ptr< QgsFillSymbol > parseEsriFillSymbolJson( const QVariantMap &symbolData );
@@ -60,6 +82,7 @@ class QgsArcGisRestUtils
6082
static QColor parseEsriColorJson( const QVariant &colorData );
6183
static Qt::PenStyle parseEsriLineStyle( const QString &style );
6284
static Qt::BrushStyle parseEsriFillStyle( const QString &style );
85+
static QgsSimpleMarkerSymbolLayerBase::Shape parseEsriMarkerShape( const QString &style );
6386

6487
static QDateTime parseDateTime( const QVariant &value );
6588

tests/src/providers/testqgsarcgisrestutils.cpp

+19-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include "qgsmarkersymbollayer.h"
2626
#include "qgssinglesymbolrenderer.h"
2727
#include "qgscategorizedsymbolrenderer.h"
28+
#include "geometry/qgsmultisurface.h"
29+
2830
#include <QObject>
2931

3032
class TestQgsArcGisRestUtils : public QObject
@@ -39,6 +41,7 @@ class TestQgsArcGisRestUtils : public QObject
3941
void testMapEsriFieldType();
4042
void testParseSpatialReference();
4143
void testMapEsriGeometryType();
44+
void testParseEsriGeometryPolygon();
4245
void testParseEsriFillStyle();
4346
void testParseEsriLineStyle();
4447
void testParseEsriColorJson();
@@ -109,12 +112,27 @@ void TestQgsArcGisRestUtils::testMapEsriGeometryType()
109112
QCOMPARE( QgsArcGisRestUtils::mapEsriGeometryType( QStringLiteral( "esriGeometryMultipoint" ) ), QgsWkbTypes::MultiPoint );
110113
//unsure why this maps to multicurve and not multilinestring
111114
//QCOMPARE( QgsArcGisRestUtils::mapEsriGeometryType( QStringLiteral("esriGeometryPolyline") ),QgsWkbTypes::MultiCurve );
112-
QCOMPARE( QgsArcGisRestUtils::mapEsriGeometryType( QStringLiteral( "esriGeometryPolygon" ) ), QgsWkbTypes::Polygon );
115+
QCOMPARE( QgsArcGisRestUtils::mapEsriGeometryType( QStringLiteral( "esriGeometryPolygon" ) ), QgsWkbTypes::MultiPolygon );
113116
QCOMPARE( QgsArcGisRestUtils::mapEsriGeometryType( QStringLiteral( "esriGeometryEnvelope" ) ), QgsWkbTypes::Polygon );
114117

115118
QCOMPARE( QgsArcGisRestUtils::mapEsriGeometryType( QStringLiteral( "xxx" ) ), QgsWkbTypes::Unknown );
116119
}
117120

121+
void TestQgsArcGisRestUtils::testParseEsriGeometryPolygon()
122+
{
123+
QVariantMap map = jsonStringToMap( "{"
124+
"\"rings\": ["
125+
"[[12,0],[13,0],[13,10],[12,10],[12,0]],"
126+
"[[3,3],[9,3],[6,9],[3,3]],"
127+
"[[0,0],[10,0],[10,10],[0,10],[0,0]]"
128+
"]"
129+
"}" );
130+
QCOMPARE( map[QStringLiteral( "rings" )].isValid(), true );
131+
std::unique_ptr<QgsMultiSurface> geometry = QgsArcGisRestUtils::parseEsriGeometryPolygon( map, QgsWkbTypes::Point );
132+
QVERIFY( geometry.get() );
133+
QCOMPARE( geometry->asWkt(), QStringLiteral( "MultiSurface (CurvePolygon (CompoundCurve ((0 0, 10 0, 10 10, 0 10, 0 0)),CompoundCurve ((3 3, 9 3, 6 9, 3 3))),CurvePolygon (CompoundCurve ((12 0, 13 0, 13 10, 12 10, 12 0))))" ) );
134+
}
135+
118136
void TestQgsArcGisRestUtils::testParseEsriFillStyle()
119137
{
120138
QCOMPARE( QgsArcGisRestUtils::parseEsriFillStyle( QStringLiteral( "esriSFSBackwardDiagonal" ) ), Qt::BDiagPattern );

0 commit comments

Comments
 (0)