27#include <QNetworkRequest> 
   28#include <QJsonDocument> 
   31QMutex QgsNominatimGeocoder::sMutex;
 
   34qint64 QgsNominatimGeocoder::sLastRequestTimestamp = 0;
 
   38  , mCountryCodes( countryCodes )
 
   39  , mEndpoint( QStringLiteral( 
"https://nominatim.qgis.org/search" ) )
 
 
   53  fields.
append( 
QgsField( QStringLiteral( 
"osm_type" ), QMetaType::Type::QString ) );
 
   54  fields.
append( 
QgsField( QStringLiteral( 
"display_name" ), QMetaType::Type::QString ) );
 
   55  fields.
append( 
QgsField( QStringLiteral( 
"place_id" ), QMetaType::Type::QString ) );
 
   56  fields.
append( 
QgsField( QStringLiteral( 
"class" ), QMetaType::Type::QString ) );
 
   57  fields.
append( 
QgsField( QStringLiteral( 
"type" ), QMetaType::Type::QString ) );
 
   58  fields.
append( 
QgsField( QStringLiteral( 
"road" ), QMetaType::Type::QString ) );
 
   59  fields.
append( 
QgsField( QStringLiteral( 
"village" ), QMetaType::Type::QString ) );
 
   60  fields.
append( 
QgsField( QStringLiteral( 
"city_district" ), QMetaType::Type::QString ) );
 
   61  fields.
append( 
QgsField( QStringLiteral( 
"town" ), QMetaType::Type::QString ) );
 
   62  fields.
append( 
QgsField( QStringLiteral( 
"city" ), QMetaType::Type::QString ) );
 
   63  fields.
append( 
QgsField( QStringLiteral( 
"state" ), QMetaType::Type::QString ) );
 
   64  fields.
append( 
QgsField( QStringLiteral( 
"country" ), QMetaType::Type::QString ) );
 
   65  fields.
append( 
QgsField( QStringLiteral( 
"postcode" ), QMetaType::Type::QString ) );
 
 
   88      QgsDebugError( 
"Could not transform geocode bounds to WGS84" );
 
   94  const QMutexLocker locker( &sMutex );
 
   95  const auto it = sCachedResultsNominatim()->constFind( url );
 
   96  if ( it != sCachedResultsNominatim()->constEnd() )
 
  101  while ( QDateTime::currentMSecsSinceEpoch() - sLastRequestTimestamp < 1000 / mRequestsPerSecond )
 
  103    QThread::msleep( 50 );
 
  105      return QList<QgsGeocoderResult>();
 
  108  QNetworkRequest request( url );
 
  114  sLastRequestTimestamp = QDateTime::currentMSecsSinceEpoch();
 
  123  const QJsonDocument doc = QJsonDocument::fromJson( newReq.
reply().
content(), &err );
 
  129  const QVariantList results = doc.array().toVariantList();
 
  130  if ( results.isEmpty() )
 
  132    sCachedResultsNominatim()->insert( url, QList<QgsGeocoderResult>() );
 
  133    return QList<QgsGeocoderResult>();
 
  136  QList< QgsGeocoderResult > matches;
 
  137  matches.reserve( results.size() );
 
  138  for ( 
const QVariant &result : results )
 
  143  sCachedResultsNominatim()->insert( url, matches );
 
 
  150  QUrl res( mEndpoint );
 
  152  query.addQueryItem( QStringLiteral( 
"format" ), QStringLiteral( 
"json" ) );
 
  153  query.addQueryItem( QStringLiteral( 
"addressdetails" ), QStringLiteral( 
"1" ) );
 
  156    query.addQueryItem( QStringLiteral( 
"viewbox" ), bounds.
toString( 7 ).replace( QLatin1String( 
" : " ), QLatin1String( 
"," ) ) );
 
  158  if ( !mCountryCodes.isEmpty() )
 
  160    query.addQueryItem( QStringLiteral( 
"countrycodes" ), mCountryCodes.toLower() );
 
  162  query.addQueryItem( QStringLiteral( 
"q" ), address );
 
  163  res.setQuery( query );
 
 
  170  const double latitude = json.value( QStringLiteral( 
"lat" ) ).toDouble();
 
  171  const double longitude = json.value( QStringLiteral( 
"lon" ) ).toDouble();
 
  175  QgsGeocoderResult res( json.value( QStringLiteral( 
"display_name" ) ).toString(),
 
  179  QVariantMap attributes;
 
  181  if ( json.contains( QStringLiteral( 
"display_name" ) ) )
 
  182    attributes.insert( QStringLiteral( 
"display_name" ), json.value( QStringLiteral( 
"display_name" ) ).toString() );
 
  183  if ( json.contains( QStringLiteral( 
"place_id" ) ) )
 
  184    attributes.insert( QStringLiteral( 
"place_id" ), json.value( QStringLiteral( 
"place_id" ) ).toString() );
 
  185  if ( json.contains( QStringLiteral( 
"osm_type" ) ) )
 
  186    attributes.insert( QStringLiteral( 
"osm_type" ), json.value( QStringLiteral( 
"osm_type" ) ).toString() );
 
  187  if ( json.contains( QStringLiteral( 
"class" ) ) )
 
  188    attributes.insert( QStringLiteral( 
"class" ), json.value( QStringLiteral( 
"class" ) ).toString() );
 
  189  if ( json.contains( QStringLiteral( 
"type" ) ) )
 
  190    attributes.insert( QStringLiteral( 
"type" ), json.value( QStringLiteral( 
"type" ) ).toString() );
 
  192  if ( json.contains( QStringLiteral( 
"address" ) ) )
 
  194    const QVariantMap address_components = json.value( QStringLiteral( 
"address" ) ).toMap();
 
  195    if ( address_components.contains( QStringLiteral( 
"road" ) ) )
 
  196      attributes.insert( QStringLiteral( 
"road" ), address_components.value( QStringLiteral( 
"road" ) ).toString() );
 
  197    if ( address_components.contains( QStringLiteral( 
"village" ) ) )
 
  198      attributes.insert( QStringLiteral( 
"village" ), address_components.value( QStringLiteral( 
"village" ) ).toString() );
 
  199    if ( address_components.contains( QStringLiteral( 
"city_district" ) ) )
 
  200      attributes.insert( QStringLiteral( 
"city_district" ), address_components.value( QStringLiteral( 
"city_district" ) ).toString() );
 
  201    if ( address_components.contains( QStringLiteral( 
"town" ) ) )
 
  202      attributes.insert( QStringLiteral( 
"town" ), address_components.value( QStringLiteral( 
"town" ) ).toString() );
 
  203    if ( address_components.contains( QStringLiteral( 
"city" ) ) )
 
  204      attributes.insert( QStringLiteral( 
"city" ), address_components.value( QStringLiteral( 
"city" ) ).toString() );
 
  205    if ( address_components.contains( QStringLiteral( 
"state" ) ) )
 
  207      attributes.insert( QStringLiteral( 
"state" ), address_components.value( QStringLiteral( 
"state" ) ).toString() );
 
  208      res.
setGroup( address_components.value( QStringLiteral( 
"state" ) ).toString() );
 
  210    if ( address_components.contains( QStringLiteral( 
"country" ) ) )
 
  211      attributes.insert( QStringLiteral( 
"country" ), address_components.value( QStringLiteral( 
"country" ) ).toString() );
 
  212    if ( address_components.contains( QStringLiteral( 
"postcode" ) ) )
 
  213      attributes.insert( QStringLiteral( 
"postcode" ), address_components.value( QStringLiteral( 
"postcode" ) ).toString() );
 
  216  if ( json.contains( QStringLiteral( 
"boundingbox" ) ) )
 
  218    const QVariantList boundingBox = json.value( QStringLiteral( 
"boundingbox" ) ).toList();
 
  219    if ( boundingBox.size() == 4 )
 
  221                                     boundingBox.at( 0 ).toDouble(),
 
  222                                     boundingBox.at( 3 ).toDouble(),
 
  223                                     boundingBox.at( 1 ).toDouble() ) );
 
 
  242  return mCountryCodes;
 
 
WkbType
The WKB type describes the number of dimensions a geometry has.
 
A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy...
 
QString errorMessage() const
Returns the error message string, after a get(), post(), head() or put() request has been made.
 
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr, RequestFlags requestFlags=QgsBlockingNetworkRequest::RequestFlags())
Performs a "get" operation on the specified request.
 
@ NoError
No error was encountered.
 
QgsNetworkReplyContent reply() const
Returns the content of the network reply, after a get(), post(), head() or put() request has been mad...
 
Represents a coordinate reference system (CRS).
 
Custom exception class for Coordinate Reference System related exceptions.
 
Base class for feedback objects to be used for cancellation of something running in a worker thread.
 
bool isCanceled() const
Tells whether the operation has been canceled already.
 
Encapsulate a field in an attribute table or data source.
 
Container of fields for a vector layer.
 
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
 
Encapsulates the context of a geocoding operation.
 
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which should be used whenever the geocoder constructs a coo...
 
QgsCoordinateReferenceSystem areaOfInterestCrs() const
Returns the coordinate reference system for the area of interest, which can be used to indicate the d...
 
QgsGeometry areaOfInterest() const
Returns the optional area of interest, which can be used to indicate the desired geographic area wher...
 
@ GeocodesStrings
Can geocode string input values.
 
Represents a matching result from a geocoder search.
 
void setAdditionalAttributes(const QVariantMap &attributes)
Setss additional attributes generated during the geocode, which may be added to features being geocod...
 
void setGroup(const QString &group)
Sets the optional group value for the result.
 
void setViewport(const QgsRectangle &viewport)
Sets the suggested viewport for the result, which reflects a recommended map extent for displaying th...
 
static QgsGeocoderResult errorResult(const QString &errorMessage)
Creates an invalid error result, with the specified errorMessage string.
 
A geometry is the spatial representation of a feature.
 
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
 
static QgsGeometry fromPointXY(const QgsPointXY &point)
Creates a new geometry from a QgsPointXY object.
 
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
 
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
 
QByteArray content() const
Returns the reply content.
 
QList< QgsGeocoderResult > geocodeString(const QString &string, const QgsGeocoderContext &context, QgsFeedback *feedback=nullptr) const override
Geocodes a string.
 
QgsGeocoderResult jsonToResult(const QVariantMap &json) const
Converts a JSON result returned from the Nominatim service to a geocoder result object.
 
QgsNominatimGeocoder(const QString &countryCodes=QString(), const QString &endpoint=QString())
Constructor for QgsNominatimGeocoder.
 
QString countryCodes() const
Returns the optional region bias which will be used to prioritize results in a certain region.
 
QString endpoint() const
Returns the API endpoint used for requests.
 
QgsFields appendedFields() const override
Returns a set of newly created fields which will be appended to existing features during the geocode ...
 
Qgis::WkbType wkbType() const override
Returns the WKB type of geometries returned by the geocoder.
 
void setEndpoint(const QString &endpoint)
Sets a specific API endpoint to use for requests.
 
Flags flags() const override
Returns the geocoder's capability flags.
 
void setCountryCodes(const QString &countryCodes)
Sets the optional region bias which will be used to prioritize results in a certain region.
 
QUrl requestUrl(const QString &address, const QgsRectangle &bounds=QgsRectangle()) const
Returns the URL generated for geocoding the specified address.
 
A rectangle specified with double values.
 
Q_INVOKABLE QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
 
bool isFinite() const
Returns true if the rectangle has finite boundaries.
 
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
 
QMap< QUrl, QList< QgsGeocoderResult > > CachedGeocodeResult
 
#define QgsDebugError(str)
 
QMap< QUrl, QList< QgsGeocoderResult > > CachedGeocodeResult
 
#define QgsSetRequestInitiatorClass(request, _class)