26 #include <QNetworkRequest>
27 #include <QJsonDocument>
30 QMutex QgsNominatimGeocoder::sMutex;
33 qint64 QgsNominatimGeocoder::sLastRequestTimestamp = 0;
37 , mCountryCodes( countryCodes )
38 , mEndpoint( QStringLiteral(
"https://nominatim.qgis.org/search" ) )
52 fields.
append(
QgsField( QStringLiteral(
"osm_type" ), QVariant::String ) );
53 fields.
append(
QgsField( QStringLiteral(
"display_name" ), QVariant::String ) );
54 fields.
append(
QgsField( QStringLiteral(
"place_id" ), QVariant::String ) );
55 fields.
append(
QgsField( QStringLiteral(
"class" ), QVariant::String ) );
56 fields.
append(
QgsField( QStringLiteral(
"type" ), QVariant::String ) );
57 fields.
append(
QgsField( QStringLiteral(
"road" ), QVariant::String ) );
58 fields.
append(
QgsField( QStringLiteral(
"village" ), QVariant::String ) );
59 fields.
append(
QgsField( QStringLiteral(
"city_district" ), QVariant::String ) );
60 fields.
append(
QgsField( QStringLiteral(
"town" ), QVariant::String ) );
61 fields.
append(
QgsField( QStringLiteral(
"city" ), QVariant::String ) );
62 fields.
append(
QgsField( QStringLiteral(
"state" ), QVariant::String ) );
63 fields.
append(
QgsField( QStringLiteral(
"country" ), QVariant::String ) );
64 fields.
append(
QgsField( QStringLiteral(
"postcode" ), QVariant::String ) );
87 QgsDebugMsg(
"Could not transform geocode bounds to WGS84" );
93 const QMutexLocker locker( &sMutex );
94 const auto it = sCachedResults()->constFind( url );
95 if ( it != sCachedResults()->constEnd() )
100 while ( QDateTime::currentMSecsSinceEpoch() - sLastRequestTimestamp < 1000 / mRequestsPerSecond )
102 QThread::msleep( 50 );
104 return QList<QgsGeocoderResult>();
107 QNetworkRequest request( url );
113 sLastRequestTimestamp = QDateTime::currentMSecsSinceEpoch();
122 const QJsonDocument doc = QJsonDocument::fromJson( newReq.
reply().
content(), &err );
128 const QVariantList results = doc.array().toVariantList();
129 if ( results.isEmpty() )
131 sCachedResults()->insert( url, QList<QgsGeocoderResult>() );
132 return QList<QgsGeocoderResult>();
135 QList< QgsGeocoderResult > matches;
136 matches.reserve( results.size() );
137 for (
const QVariant &result : results )
142 sCachedResults()->insert( url, matches );
149 QUrl res( mEndpoint );
151 query.addQueryItem( QStringLiteral(
"format" ), QStringLiteral(
"json" ) );
152 query.addQueryItem( QStringLiteral(
"addressdetails" ), QStringLiteral(
"1" ) );
155 query.addQueryItem( QStringLiteral(
"viewbox" ), QStringLiteral(
"%1,%2,%3,%4" ).arg( bounds.
xMinimum() )
160 if ( !mCountryCodes.isEmpty() )
162 query.addQueryItem( QStringLiteral(
"countrycodes" ), mCountryCodes.toLower() );
164 query.addQueryItem( QStringLiteral(
"q" ), address );
165 res.setQuery( query );
172 const double latitude = json.value( QStringLiteral(
"lat" ) ).toDouble();
173 const double longitude = json.value( QStringLiteral(
"lon" ) ).toDouble();
177 QgsGeocoderResult res( json.value( QStringLiteral(
"display_name" ) ).toString(),
181 QVariantMap attributes;
183 if ( json.contains( QStringLiteral(
"display_name" ) ) )
184 attributes.insert( QStringLiteral(
"display_name" ), json.value( QStringLiteral(
"display_name" ) ).toString() );
185 if ( json.contains( QStringLiteral(
"place_id" ) ) )
186 attributes.insert( QStringLiteral(
"place_id" ), json.value( QStringLiteral(
"place_id" ) ).toString() );
187 if ( json.contains( QStringLiteral(
"osm_type" ) ) )
188 attributes.insert( QStringLiteral(
"osm_type" ), json.value( QStringLiteral(
"osm_type" ) ).toString() );
189 if ( json.contains( QStringLiteral(
"class" ) ) )
190 attributes.insert( QStringLiteral(
"class" ), json.value( QStringLiteral(
"class" ) ).toString() );
191 if ( json.contains( QStringLiteral(
"type" ) ) )
192 attributes.insert( QStringLiteral(
"type" ), json.value( QStringLiteral(
"type" ) ).toString() );
194 if ( json.contains( QStringLiteral(
"address" ) ) )
196 const QVariantMap address_components = json.value( QStringLiteral(
"address" ) ).toMap();
197 if ( address_components.contains( QStringLiteral(
"road" ) ) )
198 attributes.insert( QStringLiteral(
"road" ), address_components.value( QStringLiteral(
"road" ) ).toString() );
199 if ( address_components.contains( QStringLiteral(
"village" ) ) )
200 attributes.insert( QStringLiteral(
"village" ), address_components.value( QStringLiteral(
"village" ) ).toString() );
201 if ( address_components.contains( QStringLiteral(
"city_district" ) ) )
202 attributes.insert( QStringLiteral(
"city_district" ), address_components.value( QStringLiteral(
"city_district" ) ).toString() );
203 if ( address_components.contains( QStringLiteral(
"town" ) ) )
204 attributes.insert( QStringLiteral(
"town" ), address_components.value( QStringLiteral(
"town" ) ).toString() );
205 if ( address_components.contains( QStringLiteral(
"city" ) ) )
206 attributes.insert( QStringLiteral(
"city" ), address_components.value( QStringLiteral(
"city" ) ).toString() );
207 if ( address_components.contains( QStringLiteral(
"state" ) ) )
209 attributes.insert( QStringLiteral(
"state" ), address_components.value( QStringLiteral(
"state" ) ).toString() );
210 res.
setGroup( address_components.value( QStringLiteral(
"state" ) ).toString() );
212 if ( address_components.contains( QStringLiteral(
"country" ) ) )
213 attributes.insert( QStringLiteral(
"country" ), address_components.value( QStringLiteral(
"country" ) ).toString() );
214 if ( address_components.contains( QStringLiteral(
"postcode" ) ) )
215 attributes.insert( QStringLiteral(
"postcode" ), address_components.value( QStringLiteral(
"postcode" ) ).toString() );
218 if ( json.contains( QStringLiteral(
"boundingbox" ) ) )
220 const QVariantList boundingBox = json.value( QStringLiteral(
"boundingbox" ) ).toList();
221 if ( boundingBox.size() == 4 )
223 boundingBox.at( 0 ).toDouble(),
224 boundingBox.at( 3 ).toDouble(),
225 boundingBox.at( 1 ).toDouble() ) );
244 return mCountryCodes;