Skip to content

Commit 43c5a1f

Browse files
committedMar 5, 2019
[asf] Fix parsing of polygons
1 parent 850905e commit 43c5a1f

File tree

3 files changed

+95
-34
lines changed

3 files changed

+95
-34
lines changed
 

‎src/providers/arcgisrest/qgsarcgisrestutils.cpp

Lines changed: 51 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,6 @@
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 "qgspallabeling.h"
3223
#include "qgssymbol.h"
@@ -35,7 +26,6 @@
3526
#include "qgssettings.h"
3627
#include "qgslinesymbollayer.h"
3728
#include "qgsfillsymbollayer.h"
38-
#include "qgsmarkersymbollayer.h"
3929
#include "qgsrenderer.h"
4030
#include "qgsrulebasedlabeling.h"
4131
#include "qgssinglesymbolrenderer.h"
@@ -91,7 +81,7 @@ QgsWkbTypes::Type QgsArcGisRestUtils::mapEsriGeometryType( const QString &esriGe
9181
else if ( esriGeometryType == QLatin1String( "esriGeometryPolyline" ) )
9282
return QgsWkbTypes::MultiCurve;
9383
else if ( esriGeometryType == QLatin1String( "esriGeometryPolygon" ) )
94-
return QgsWkbTypes::Polygon;
84+
return QgsWkbTypes::MultiPolygon;
9585
else if ( esriGeometryType == QLatin1String( "esriGeometryEnvelope" ) )
9686
return QgsWkbTypes::Polygon;
9787
// Unsupported (either by qgis, or format unspecified by the specification)
@@ -112,7 +102,7 @@ QgsWkbTypes::Type QgsArcGisRestUtils::mapEsriGeometryType( const QString &esriGe
112102
return QgsWkbTypes::Unknown;
113103
}
114104

115-
static std::unique_ptr< QgsPoint > parsePoint( const QVariantList &coordList, QgsWkbTypes::Type pointType )
105+
std::unique_ptr< QgsPoint > QgsArcGisRestUtils::parsePoint( const QVariantList &coordList, QgsWkbTypes::Type pointType )
116106
{
117107
int nCoords = coordList.size();
118108
if ( nCoords < 2 )
@@ -127,7 +117,7 @@ static std::unique_ptr< QgsPoint > parsePoint( const QVariantList &coordList, Qg
127117
return qgis::make_unique< QgsPoint >( pointType, x, y, z, m );
128118
}
129119

130-
static std::unique_ptr< QgsCircularString > parseCircularString( const QVariantMap &curveData, QgsWkbTypes::Type pointType, const QgsPoint &startPoint )
120+
std::unique_ptr< QgsCircularString > QgsArcGisRestUtils::parseCircularString( const QVariantMap &curveData, QgsWkbTypes::Type pointType, const QgsPoint &startPoint )
131121
{
132122
const QVariantList coordsList = curveData[QStringLiteral( "c" )].toList();
133123
if ( coordsList.isEmpty() )
@@ -148,7 +138,7 @@ static std::unique_ptr< QgsCircularString > parseCircularString( const QVariantM
148138
return curve;
149139
}
150140

151-
static std::unique_ptr< QgsCompoundCurve > parseCompoundCurve( const QVariantList &curvesList, QgsWkbTypes::Type pointType )
141+
std::unique_ptr< QgsCompoundCurve > QgsArcGisRestUtils::parseCompoundCurve( const QVariantList &curvesList, QgsWkbTypes::Type pointType )
152142
{
153143
// [[6,3],[5,3],{"b":[[3,2],[6,1],[2,4]]},[1,2],{"c": [[3,3],[1,4]]}]
154144
std::unique_ptr< QgsCompoundCurve > compoundCurve = qgis::make_unique< QgsCompoundCurve >();
@@ -189,7 +179,7 @@ static std::unique_ptr< QgsCompoundCurve > parseCompoundCurve( const QVariantLis
189179
return compoundCurve;
190180
}
191181

192-
static std::unique_ptr< QgsPoint > parseEsriGeometryPoint( const QVariantMap &geometryData, QgsWkbTypes::Type pointType )
182+
std::unique_ptr< QgsPoint > QgsArcGisRestUtils::parseEsriGeometryPoint( const QVariantMap &geometryData, QgsWkbTypes::Type pointType )
193183
{
194184
// {"x" : <x>, "y" : <y>, "z" : <z>, "m" : <m>}
195185
bool xok = false, yok = false;
@@ -202,7 +192,7 @@ static std::unique_ptr< QgsPoint > parseEsriGeometryPoint( const QVariantMap &ge
202192
return qgis::make_unique< QgsPoint >( pointType, x, y, z, m );
203193
}
204194

205-
static std::unique_ptr< QgsMultiPoint > parseEsriGeometryMultiPoint( const QVariantMap &geometryData, QgsWkbTypes::Type pointType )
195+
std::unique_ptr< QgsMultiPoint > QgsArcGisRestUtils::parseEsriGeometryMultiPoint( const QVariantMap &geometryData, QgsWkbTypes::Type pointType )
206196
{
207197
// {"points" : [[ <x1>, <y1>, <z1>, <m1> ] , [ <x2>, <y2>, <z2>, <m2> ], ... ]}
208198
const QVariantList coordsList = geometryData[QStringLiteral( "points" )].toList();
@@ -233,7 +223,7 @@ static std::unique_ptr< QgsMultiPoint > parseEsriGeometryMultiPoint( const QVari
233223
return multiPoint;
234224
}
235225

236-
static std::unique_ptr< QgsMultiCurve > parseEsriGeometryPolyline( const QVariantMap &geometryData, QgsWkbTypes::Type pointType )
226+
std::unique_ptr< QgsMultiCurve > QgsArcGisRestUtils::parseEsriGeometryPolyline( const QVariantMap &geometryData, QgsWkbTypes::Type pointType )
237227
{
238228
// {"curvePaths": [[[0,0], {"c": [[3,3],[1,4]]} ]]}
239229
QVariantList pathsList;
@@ -256,7 +246,7 @@ static std::unique_ptr< QgsMultiCurve > parseEsriGeometryPolyline( const QVarian
256246
return multiCurve;
257247
}
258248

259-
static std::unique_ptr< QgsCurvePolygon > parseEsriGeometryPolygon( const QVariantMap &geometryData, QgsWkbTypes::Type pointType )
249+
std::unique_ptr< QgsMultiSurface > QgsArcGisRestUtils::parseEsriGeometryPolygon( const QVariantMap &geometryData, QgsWkbTypes::Type pointType )
260250
{
261251
// {"curveRings": [[[0,0], {"c": [[3,3],[1,4]]} ]]}
262252
QVariantList ringsList;
@@ -266,26 +256,56 @@ static std::unique_ptr< QgsCurvePolygon > parseEsriGeometryPolygon( const QVaria
266256
ringsList = geometryData[QStringLiteral( "ringPaths" )].toList();
267257
if ( ringsList.isEmpty() )
268258
return nullptr;
269-
std::unique_ptr< QgsCurvePolygon > polygon = qgis::make_unique< QgsCurvePolygon >();
270-
std::unique_ptr< QgsCompoundCurve > ext = parseCompoundCurve( ringsList.front().toList(), pointType );
271-
if ( !ext )
272-
{
273-
return nullptr;
274-
}
275-
polygon->setExteriorRing( ext.release() );
276-
for ( int i = 1, n = ringsList.size(); i < n; ++i )
259+
260+
QList< QgsCompoundCurve * > curves;
261+
for ( int i = 0, n = ringsList.size(); i < n; ++i )
277262
{
278263
std::unique_ptr< QgsCompoundCurve > curve = parseCompoundCurve( ringsList[i].toList(), pointType );
279264
if ( !curve )
280265
{
281-
return nullptr;
266+
continue;
282267
}
283-
polygon->addInteriorRing( curve.release() );
268+
curves.append( curve.release() );
284269
}
285-
return polygon;
270+
if ( curves.count() == 0 )
271+
return nullptr;
272+
273+
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 ); } );
274+
std::unique_ptr< QgsMultiSurface > result = qgis::make_unique< QgsMultiSurface >();
275+
while ( !curves.isEmpty() )
276+
{
277+
QgsCompoundCurve *exterior = curves.takeFirst();
278+
QgsCurvePolygon *newPolygon = new QgsCurvePolygon();
279+
newPolygon->setExteriorRing( exterior );
280+
std::unique_ptr<QgsGeometryEngine> engine( QgsGeometry::createGeometryEngine( newPolygon ) );
281+
engine->prepareGeometry();
282+
283+
QMutableListIterator< QgsCompoundCurve * > it( curves );
284+
while ( it.hasNext() )
285+
{
286+
QgsCompoundCurve *curve = it.next();
287+
QgsRectangle boundingBox = newPolygon->boundingBox();
288+
if ( boundingBox.intersects( curve->boundingBox() ) )
289+
{
290+
QgsPoint point = curve->startPoint();
291+
if ( engine->contains( &point ) )
292+
{
293+
newPolygon->addInteriorRing( curve );
294+
it.remove();
295+
engine.reset( QgsGeometry::createGeometryEngine( newPolygon ) );
296+
engine->prepareGeometry();
297+
}
298+
}
299+
}
300+
result->addGeometry( newPolygon );
301+
}
302+
if ( result->numGeometries() == 0 )
303+
return nullptr;
304+
305+
return result;
286306
}
287307

288-
static std::unique_ptr< QgsPolygon > parseEsriEnvelope( const QVariantMap &geometryData )
308+
std::unique_ptr< QgsPolygon > QgsArcGisRestUtils::parseEsriEnvelope( const QVariantMap &geometryData )
289309
{
290310
// {"xmin" : -109.55, "ymin" : 25.76, "xmax" : -86.39, "ymax" : 49.94}
291311
bool xminOk = false, yminOk = false, xmaxOk = false, ymaxOk = false;
@@ -651,7 +671,7 @@ std::unique_ptr<QgsFillSymbol> QgsArcGisRestUtils::parseEsriPictureFillSymbolJso
651671
return symbol;
652672
}
653673

654-
QgsSimpleMarkerSymbolLayerBase::Shape parseEsriMarkerShape( const QString &style )
674+
QgsSimpleMarkerSymbolLayerBase::Shape QgsArcGisRestUtils::parseEsriMarkerShape( const QString &style )
655675
{
656676
if ( style == QLatin1String( "esriSMSCircle" ) )
657677
return QgsSimpleMarkerSymbolLayerBase::Circle;

‎src/providers/arcgisrest/qgsarcgisrestutils.h

Lines changed: 25 additions & 2 deletions
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;
@@ -52,6 +65,15 @@ class QgsArcGisRestUtils
5265
static QByteArray queryService( const QUrl &url, const QString &authcfg, QString &errorTitle, QString &errorText, const QgsStringMap &requestHeaders = QgsStringMap(), QgsFeedback *feedback = nullptr );
5366
static QVariantMap queryServiceJSON( const QUrl &url, const QString &authcfg, QString &errorTitle, QString &errorText, const QgsStringMap &requestHeaders = QgsStringMap(), QgsFeedback *feedback = nullptr );
5467

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

6992
static QDateTime parseDateTime( const QVariant &value );
7093

‎tests/src/providers/testqgsarcgisrestutils.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
#include "qgsrulebasedlabeling.h"
2727
#include "qgssinglesymbolrenderer.h"
2828
#include "qgscategorizedsymbolrenderer.h"
29+
#include "geometry/qgsmultisurface.h"
30+
2931
#include <QObject>
3032

3133
class TestQgsArcGisRestUtils : public QObject
@@ -40,6 +42,7 @@ class TestQgsArcGisRestUtils : public QObject
4042
void testMapEsriFieldType();
4143
void testParseSpatialReference();
4244
void testMapEsriGeometryType();
45+
void testParseEsriGeometryPolygon();
4346
void testParseEsriFillStyle();
4447
void testParseEsriLineStyle();
4548
void testParseEsriColorJson();
@@ -113,12 +116,27 @@ void TestQgsArcGisRestUtils::testMapEsriGeometryType()
113116
QCOMPARE( QgsArcGisRestUtils::mapEsriGeometryType( QStringLiteral( "esriGeometryMultipoint" ) ), QgsWkbTypes::MultiPoint );
114117
//unsure why this maps to multicurve and not multilinestring
115118
//QCOMPARE( QgsArcGisRestUtils::mapEsriGeometryType( QStringLiteral("esriGeometryPolyline") ),QgsWkbTypes::MultiCurve );
116-
QCOMPARE( QgsArcGisRestUtils::mapEsriGeometryType( QStringLiteral( "esriGeometryPolygon" ) ), QgsWkbTypes::Polygon );
119+
QCOMPARE( QgsArcGisRestUtils::mapEsriGeometryType( QStringLiteral( "esriGeometryPolygon" ) ), QgsWkbTypes::MultiPolygon );
117120
QCOMPARE( QgsArcGisRestUtils::mapEsriGeometryType( QStringLiteral( "esriGeometryEnvelope" ) ), QgsWkbTypes::Polygon );
118121

119122
QCOMPARE( QgsArcGisRestUtils::mapEsriGeometryType( QStringLiteral( "xxx" ) ), QgsWkbTypes::Unknown );
120123
}
121124

125+
void TestQgsArcGisRestUtils::testParseEsriGeometryPolygon()
126+
{
127+
QVariantMap map = jsonStringToMap( "{"
128+
"\"rings\": ["
129+
"[[12,0],[13,0],[13,10],[12,10],[12,0]],"
130+
"[[3,3],[9,3],[6,9],[3,3]],"
131+
"[[0,0],[10,0],[10,10],[0,10],[0,0]]"
132+
"]"
133+
"}" );
134+
QCOMPARE( map[QStringLiteral( "rings" )].isValid(), true );
135+
std::unique_ptr<QgsMultiSurface> geometry = QgsArcGisRestUtils::parseEsriGeometryPolygon( map, QgsWkbTypes::Point );
136+
QVERIFY( geometry.get() );
137+
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))))" ) );
138+
}
139+
122140
void TestQgsArcGisRestUtils::testParseEsriFillStyle()
123141
{
124142
QCOMPARE( QgsArcGisRestUtils::parseEsriFillStyle( QStringLiteral( "esriSFSBackwardDiagonal" ) ), Qt::BDiagPattern );

0 commit comments

Comments
 (0)
Please sign in to comment.