Skip to content

Commit

Permalink
[afs] Fix 'Limit to extent' option was ignored
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jun 14, 2018
1 parent 2fe394b commit a80f7ab
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 3 deletions.
8 changes: 7 additions & 1 deletion src/providers/arcgisrest/qgsafsprovider.cpp
Expand Up @@ -61,6 +61,7 @@ QgsAfsProvider::QgsAfsProvider( const QString &uri, const ProviderOptions &optio

// Set extent
QStringList coords = mSharedData->mDataSource.param( QStringLiteral( "bbox" ) ).split( ',' );
bool limitBbox = false;
if ( coords.size() == 4 )
{
bool xminOk = false, yminOk = false, xmaxOk = false, ymaxOk = false;
Expand All @@ -70,6 +71,11 @@ QgsAfsProvider::QgsAfsProvider( const QString &uri, const ProviderOptions &optio
mSharedData->mExtent.setYMaximum( coords[3].toDouble( &ymaxOk ) );
if ( !xminOk || !yminOk || !xmaxOk || !ymaxOk )
mSharedData->mExtent = QgsRectangle();
else
{
// user has set a bounding box limit on the layer - so we only EVER fetch features from this extent
limitBbox = true;
}
}

const QVariantMap layerExtentMap = layerData[QStringLiteral( "extent" )].toMap();
Expand Down Expand Up @@ -156,7 +162,7 @@ QgsAfsProvider::QgsAfsProvider( const QString &uri, const ProviderOptions &optio
// Read OBJECTIDs of all features: these may not be a continuous sequence,
// and we need to store these to iterate through the features. This query
// also returns the name of the ObjectID field.
QVariantMap objectIdData = QgsArcGisRestUtils::getObjectIds( mSharedData->mDataSource.param( QStringLiteral( "url" ) ), objectIdFieldName, errorTitle, errorMessage );
QVariantMap objectIdData = QgsArcGisRestUtils::getObjectIds( mSharedData->mDataSource.param( QStringLiteral( "url" ) ), objectIdFieldName, errorTitle, errorMessage, limitBbox ? mSharedData->mExtent : QgsRectangle() );
if ( objectIdData.isEmpty() )
{
appendError( QgsErrorMessage( tr( "getObjectIds failed: %1 - %2" ).arg( errorTitle, errorMessage ), QStringLiteral( "AFSProvider" ) ) );
Expand Down
10 changes: 9 additions & 1 deletion src/providers/arcgisrest/qgsarcgisrestutils.cpp
Expand Up @@ -367,13 +367,21 @@ QVariantMap QgsArcGisRestUtils::getLayerInfo( const QString &layerurl, QString &
return queryServiceJSON( queryUrl, errorTitle, errorText );
}

QVariantMap QgsArcGisRestUtils::getObjectIds( const QString &layerurl, const QString &objectIdFieldName, QString &errorTitle, QString &errorText )
QVariantMap QgsArcGisRestUtils::getObjectIds( const QString &layerurl, const QString &objectIdFieldName, QString &errorTitle, QString &errorText, const QgsRectangle &bbox )
{
// http://sampleserver5.arcgisonline.com/arcgis/rest/services/Energy/Geology/FeatureServer/1/query?where=objectid%3Dobjectid&returnIdsOnly=true&f=json
QUrl queryUrl( layerurl + "/query" );
queryUrl.addQueryItem( QStringLiteral( "f" ), QStringLiteral( "json" ) );
queryUrl.addQueryItem( QStringLiteral( "where" ), QStringLiteral( "%1=%1" ).arg( objectIdFieldName ) );
queryUrl.addQueryItem( QStringLiteral( "returnIdsOnly" ), QStringLiteral( "true" ) );
if ( !bbox.isNull() )
{
queryUrl.addQueryItem( QStringLiteral( "geometry" ), QStringLiteral( "%1,%2,%3,%4" )
.arg( bbox.xMinimum(), 0, 'f', -1 ).arg( bbox.yMinimum(), 0, 'f', -1 )
.arg( bbox.xMaximum(), 0, 'f', -1 ).arg( bbox.yMaximum(), 0, 'f', -1 ) );
queryUrl.addQueryItem( QStringLiteral( "geometryType" ), QStringLiteral( "esriGeometryEnvelope" ) );
queryUrl.addQueryItem( QStringLiteral( "spatialRel" ), QStringLiteral( "esriSpatialRelEnvelopeIntersects" ) );
}
return queryServiceJSON( queryUrl, errorTitle, errorText );
}

Expand Down
3 changes: 2 additions & 1 deletion src/providers/arcgisrest/qgsarcgisrestutils.h
Expand Up @@ -43,7 +43,8 @@ class QgsArcGisRestUtils

static QVariantMap getServiceInfo( const QString &baseurl, QString &errorTitle, QString &errorText );
static QVariantMap getLayerInfo( const QString &layerurl, QString &errorTitle, QString &errorText );
static QVariantMap getObjectIds( const QString &layerurl, const QString &objectIdFieldName, QString &errorTitle, QString &errorText );
static QVariantMap getObjectIds( const QString &layerurl, const QString &objectIdFieldName, QString &errorTitle, QString &errorText,
const QgsRectangle &bbox = QgsRectangle() );
static QVariantMap getObjects( const QString &layerurl, const QList<quint32> &objectIds, const QString &crs,
bool fetchGeometry, const QStringList &fetchAttributes, bool fetchM, bool fetchZ,
const QgsRectangle &filterRect, QString &errorTitle, QString &errorText, QgsFeedback *feedback = nullptr );
Expand Down
63 changes: 63 additions & 0 deletions tests/src/python/test_provider_afs.py
Expand Up @@ -310,6 +310,59 @@ def setUpClass(cls):
]
}""".encode('UTF-8'))

with open(sanitize(endpoint,
'/query?f=json&objectIds=2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=OBJECTID,pk,cnt,name,name2,num_char&returnM=false&returnZ=false'),
'wb') as f:
f.write("""
{
"displayFieldName": "name",
"fieldAliases": {
"name": "name"
},
"geometryType": "esriGeometryPoint",
"spatialReference": {
"wkid": 4326,
"latestWkid": 4326
},
"fields":[{"name":"OBJECTID","type":"esriFieldTypeOID","alias":"OBJECTID","domain":null},
{"name":"pk","type":"esriFieldTypeInteger","alias":"pk","domain":null},
{"name":"cnt","type":"esriFieldTypeInteger","alias":"cnt","domain":null},
{"name":"name","type":"esriFieldTypeString","alias":"name","length":100,"domain":null},
{"name":"name2","type":"esriFieldTypeString","alias":"name2","length":100,"domain":null},
{"name":"num_char","type":"esriFieldTypeString","alias":"num_char","length":100,"domain":null},
{"name":"Shape","type":"esriFieldTypeGeometry","alias":"Shape","domain":null}],
"features": [
{
"attributes": {
"OBJECTID": 2,
"pk": 2,
"cnt": 200,
"name": "Apple",
"name2":"Apple",
"num_char":"2"
},
"geometry": {
"x": -68.2,
"y": 70.8
}
},
{
"attributes": {
"OBJECTID": 4,
"pk": 4,
"cnt": 400,
"name": "Honey",
"name2":"Honey",
"num_char":"4"
},
"geometry": {
"x": -65.32,
"y": 78.3
}
}
]
}""".encode('UTF-8'))

with open(sanitize(endpoint, '/query?f=json&where=OBJECTID=OBJECTID&returnIdsOnly=true&geometry=-70.000000,67.000000,-60.000000,80.000000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects'), 'wb') as f:
f.write("""
{
Expand Down Expand Up @@ -647,6 +700,16 @@ def testRenderer(self):
self.assertEqual(vl.renderer().categories()[0].value(), 'US')
self.assertEqual(vl.renderer().categories()[1].value(), 'Canada')

def testBboxRestriction(self):
"""
Test limiting provider to features within a preset bounding box
"""
endpoint = self.basetestpath + '/fake_qgis_http_endpoint'
vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326' bbox='-70.000000,67.000000,-60.000000,80.000000'", 'test', 'arcgisfeatureserver')
self.assertTrue(vl.isValid())
self.assertEqual(vl.featureCount(), 2)
self.assertEqual([f['pk'] for f in vl.getFeatures()], [2, 4])


if __name__ == '__main__':
unittest.main()

0 comments on commit a80f7ab

Please sign in to comment.