Skip to content
Permalink
Browse files

Add optional viewport property for geocoder results

Allows specifying an optional recommended viewport bounds for
displaying the geocode result (e.g. the canvas extent to zoom
to for showing the results)
  • Loading branch information
nyalldawson committed Nov 3, 2020
1 parent e70caeb commit cbaeb99a72c0c21bc401835f3a0b625157c4823c
@@ -99,6 +99,32 @@ Sets the coordinate reference system for the calculated :py:func:`~QgsGeocoderRe
.. seealso:: :py:func:`crs`

.. seealso:: :py:func:`geometry`
%End

QgsRectangle viewport() const;
%Docstring
Returns the suggested viewport for the result, which reflects a recommended
map extent for displaying the result.

This is an optional property, and will return a null rectangle if a recommended viewport
is not available (or not appropriate).

The viewport CRS will match the CRS of :py:func:`~QgsGeocoderResult.geometry`, and can be retrieved via the :py:func:`~QgsGeocoderResult.crs` method.

.. seealso:: :py:func:`setViewport`
%End

void setViewport( const QgsRectangle &viewport );
%Docstring
Sets the suggested ``viewport`` for the result, which reflects a recommended
map extent for displaying the result.

This is an optional property, and can be set to a null rectangle if a recommended viewport
is not available (or not appropriate).

The viewport CRS must match the CRS of geometry()d.

.. seealso:: :py:func:`viewport`
%End

QVariantMap additionalAttributes() const;
@@ -76,6 +76,7 @@ QgsGeocoderResult QgsAbstractGeocoderLocatorFilter::locatorResultToGeocoderResul
attrs.value( QStringLiteral( "geom" ) ).value< QgsGeometry >(),
attrs.value( QStringLiteral( "crs" ) ).value< QgsCoordinateReferenceSystem >() );
geocodeResult.setAdditionalAttributes( attrs.value( QStringLiteral( "attributes" ) ).toMap() );
geocodeResult.setViewport( attrs.value( QStringLiteral( "viewport" ) ).value< QgsRectangle >() );
return geocodeResult;
}

@@ -84,6 +85,7 @@ QgsLocatorResult QgsAbstractGeocoderLocatorFilter::geocoderResultToLocatorResult
QVariantMap attrs;
attrs.insert( QStringLiteral( "identifier" ), result.identifier() );
attrs.insert( QStringLiteral( "geom" ), result.geometry() );
attrs.insert( QStringLiteral( "viewport" ), result.viewport() );
attrs.insert( QStringLiteral( "crs" ), result.crs() );
attrs.insert( QStringLiteral( "attributes" ), result.additionalAttributes() );
return QgsLocatorResult( this, result.identifier(), attrs );
@@ -107,6 +107,32 @@ class CORE_EXPORT QgsGeocoderResult
*/
void setCrs( const QgsCoordinateReferenceSystem &crs ) { mCrs = crs; }

/**
* Returns the suggested viewport for the result, which reflects a recommended
* map extent for displaying the result.
*
* This is an optional property, and will return a null rectangle if a recommended viewport
* is not available (or not appropriate).
*
* The viewport CRS will match the CRS of geometry(), and can be retrieved via the crs() method.
*
* \see setViewport()
*/
QgsRectangle viewport() const { return mViewport; }

/**
* Sets the suggested \a viewport for the result, which reflects a recommended
* map extent for displaying the result.
*
* This is an optional property, and can be set to a null rectangle if a recommended viewport
* is not available (or not appropriate).
*
* The viewport CRS must match the CRS of geometry()d.
*
* \see viewport()
*/
void setViewport( const QgsRectangle &viewport ) { mViewport = viewport; }

/**
* Contains additional attributes generated during the geocode,
* which may be added to features being geocoded.
@@ -133,6 +159,7 @@ class CORE_EXPORT QgsGeocoderResult
QString mIdentifier;
QgsGeometry mGeometry;
QgsCoordinateReferenceSystem mCrs;
QgsRectangle mViewport;
QVariantMap mAdditionalAttributes;

};
@@ -243,6 +243,18 @@ QgsGeocoderResult QgsGoogleMapsGeocoder::jsonToResult( const QVariantMap &json )
}
}

if ( geometry.contains( QStringLiteral( "viewport" ) ) )
{
const QVariantMap viewport = geometry.value( QStringLiteral( "viewport" ) ).toMap();
const QVariantMap northEast = viewport.value( QStringLiteral( "northeast" ) ).toMap();
const QVariantMap southWest = viewport.value( QStringLiteral( "southwest" ) ).toMap();
res.setViewport( QgsRectangle( southWest.value( QStringLiteral( "lng" ) ).toDouble(),
southWest.value( QStringLiteral( "lat" ) ).toDouble(),
northEast.value( QStringLiteral( "lng" ) ).toDouble(),
northEast.value( QStringLiteral( "lat" ) ).toDouble()
) );
}

res.setAdditionalAttributes( attributes );
return res;
}
@@ -34,10 +34,19 @@ void QgsGeocoderLocatorFilter::handleGeocodeResult( const QgsGeocoderResult &res
{
QgsCoordinateTransform ct( result.crs(), mCanvas->mapSettings().destinationCrs(), mCanvas->mapSettings().transformContext() );
QgsGeometry g = result.geometry();
const QgsRectangle viewport = result.viewport();
try
{
g.transform( ct );
QgsRectangle bounds = g.boundingBox();
QgsRectangle bounds;
if ( viewport.isNull() )
{
g.transform( ct );
bounds = g.boundingBox();
}
else
{
bounds = ct.transformBoundingBox( viewport );
}
mCanvas->zoomToFeatureExtent( bounds );

mCanvas->flashGeometries( QList< QgsGeometry >() << g );
@@ -22,7 +22,8 @@
QgsCoordinateReferenceSystem,
QgsLocatorContext,
QgsFeedback,
QgsGeocoderContext
QgsGeocoderContext,
QgsRectangle
)
from qgis.gui import (
QgsMapCanvas,
@@ -55,6 +56,7 @@ def geocodeString(self, string, context, feedback):
result2 = QgsGeocoderResult('res 2', QgsGeometry.fromPointXY(QgsPointXY(13, 14)),
QgsCoordinateReferenceSystem('EPSG:3857'))
result2.setAdditionalAttributes({'d': 456})
result2.setViewport(QgsRectangle(1, 2, 3, 4))
return [result1, result2]

return []
@@ -93,6 +95,7 @@ def test_geocode(self):
self.assertEqual(geocode_result.geometry().asWkt(), 'Point (1 2)')
self.assertEqual(geocode_result.crs().authid(), 'EPSG:4326')
self.assertEqual(geocode_result.additionalAttributes(), {'b': 123, 'c': 'xyz'})
self.assertTrue(geocode_result.viewport().isNull())

# two possible results
filter.fetchResults('b', context, feedback)
@@ -105,12 +108,14 @@ def test_geocode(self):
self.assertEqual(geocode_result.geometry().asWkt(), 'Point (11 12)')
self.assertEqual(geocode_result.crs().authid(), 'EPSG:4326')
self.assertEqual(geocode_result.additionalAttributes(), {'b': 123, 'c': 'xyz'})
self.assertTrue(geocode_result.viewport().isNull())
self.assertEqual(res2.displayString, 'res 2')
geocode_result = filter.locatorResultToGeocoderResult(res2)
self.assertEqual(geocode_result.identifier(), 'res 2')
self.assertEqual(geocode_result.geometry().asWkt(), 'Point (13 14)')
self.assertEqual(geocode_result.crs().authid(), 'EPSG:3857')
self.assertEqual(geocode_result.additionalAttributes(), {'d': 456})
self.assertEqual(geocode_result.viewport(), QgsRectangle(1, 2, 3, 4))


if __name__ == '__main__':
@@ -144,6 +144,16 @@ def test_json_to_result(self):
"lng": -83.55521200000001
},
"location_type": "APPROXIMATE",
"viewport": {
"northeast": {
"lat": 42.1,
"lng": -87.7
},
"southwest": {
"lat": 42.0,
"lng": -87.7
}
}
},
"place_id": "ChIJeU4e_C2HO4gRRcM6RZ_IPHw",
"types": ["locality", "political"]
@@ -159,6 +169,7 @@ def test_json_to_result(self):
'locality': 'Mountain View', 'location_type': 'APPROXIMATE',
'place_id': 'ChIJeU4e_C2HO4gRRcM6RZ_IPHw', 'postal_code': '94043',
'route': 'Amphitheatre Pkwy', 'street_number': '1600'})
self.assertEqual(res.viewport(), QgsRectangle(-87.7, 42, -87.7, 42.1))

def test_geocode(self):
geocoder = QgsGoogleMapsGeocoder('my key')

0 comments on commit cbaeb99

Please sign in to comment.
You can’t perform that action at this time.