Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsalgorithmbatchgeocode.cpp 3 : : ------------------ 4 : : begin : August 2020 5 : : copyright : (C) 2020 by Nyall Dawson 6 : : email : nyall dot dawson at gmail dot com 7 : : ***************************************************************************/ 8 : : 9 : : /*************************************************************************** 10 : : * * 11 : : * This program is free software; you can redistribute it and/or modify * 12 : : * it under the terms of the GNU General Public License as published by * 13 : : * the Free Software Foundation; either version 2 of the License, or * 14 : : * (at your option) any later version. * 15 : : * * 16 : : ***************************************************************************/ 17 : : 18 : : #include "qgsalgorithmbatchgeocode.h" 19 : : #include "qgsgeocoder.h" 20 : : #include "qgsgeocoderresult.h" 21 : : #include "qgsgeocodercontext.h" 22 : : #include "qgsvectorlayer.h" 23 : : 24 : 0 : QgsBatchGeocodeAlgorithm::QgsBatchGeocodeAlgorithm( QgsGeocoderInterface *geocoder ) 25 : 0 : : QgsProcessingFeatureBasedAlgorithm() 26 : 0 : , mGeocoder( geocoder ) 27 : 0 : { 28 : : 29 : 0 : } 30 : : 31 : 0 : QStringList QgsBatchGeocodeAlgorithm::tags() const 32 : : { 33 : 0 : return QObject::tr( "geocode" ).split( ',' ); 34 : 0 : } 35 : : 36 : 0 : QString QgsBatchGeocodeAlgorithm::group() const 37 : : { 38 : 0 : return QObject::tr( "Vector general" ); 39 : : } 40 : : 41 : 0 : QString QgsBatchGeocodeAlgorithm::groupId() const 42 : : { 43 : 0 : return QStringLiteral( "vectorgeneral" ); 44 : : } 45 : : 46 : 0 : void QgsBatchGeocodeAlgorithm::initParameters( const QVariantMap &configuration ) 47 : : { 48 : 0 : mIsInPlace = configuration.value( QStringLiteral( "IN_PLACE" ) ).toBool(); 49 : : 50 : 0 : addParameter( new QgsProcessingParameterField( QStringLiteral( "FIELD" ), QObject::tr( "Address field" ), QVariant(), QStringLiteral( "INPUT" ), QgsProcessingParameterField::String ) ); 51 : : 52 : 0 : if ( mIsInPlace ) 53 : : { 54 : 0 : const QgsFields newFields = mGeocoder->appendedFields(); 55 : 0 : for ( const QgsField &newField : newFields ) 56 : 0 : addParameter( new QgsProcessingParameterField( newField.name(), QObject::tr( "%1 field" ).arg( newField.name() ), newField.name(), QStringLiteral( "INPUT" ), QgsProcessingParameterField::Any, false, true ) ); 57 : 0 : } 58 : 0 : } 59 : : 60 : 0 : QList<int> QgsBatchGeocodeAlgorithm::inputLayerTypes() const 61 : : { 62 : 0 : return QList<int>() << QgsProcessing::TypeVector; 63 : 0 : } 64 : : 65 : 0 : bool QgsBatchGeocodeAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const 66 : : { 67 : 0 : if ( const QgsVectorLayer *vl = qobject_cast< const QgsVectorLayer * >( layer ) ) 68 : : { 69 : 0 : return vl->geometryType() == QgsWkbTypes::PointGeometry; 70 : : } 71 : 0 : return false; 72 : 0 : } 73 : : 74 : 0 : QString QgsBatchGeocodeAlgorithm::outputName() const 75 : : { 76 : 0 : return QObject::tr( "Geocoded" ); 77 : : } 78 : : 79 : 0 : bool QgsBatchGeocodeAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * ) 80 : : { 81 : 0 : mAddressField = parameterAsString( parameters, QStringLiteral( "FIELD" ), context ); 82 : : 83 : 0 : if ( mIsInPlace ) 84 : : { 85 : 0 : const QgsFields newFields = mGeocoder->appendedFields(); 86 : 0 : for ( const QgsField &newField : newFields ) 87 : 0 : mInPlaceFieldMap.insert( newField.name(), parameterAsString( parameters, newField.name(), context ) ); 88 : 0 : } 89 : : 90 : 0 : return true; 91 : 0 : } 92 : : 93 : 0 : QgsWkbTypes::Type QgsBatchGeocodeAlgorithm::outputWkbType( QgsWkbTypes::Type ) const 94 : : { 95 : 0 : return QgsWkbTypes::Point; 96 : : } 97 : : 98 : 0 : QgsCoordinateReferenceSystem QgsBatchGeocodeAlgorithm::outputCrs( const QgsCoordinateReferenceSystem &inputCrs ) const 99 : : { 100 : 0 : mOutputCrs = inputCrs; 101 : 0 : return mOutputCrs; 102 : : } 103 : : 104 : 0 : QgsFields QgsBatchGeocodeAlgorithm::outputFields( const QgsFields &inputFields ) const 105 : : { 106 : 0 : if ( !mIsInPlace ) 107 : : { 108 : : // append any additional fields created by the geocoder 109 : 0 : const QgsFields newFields = mGeocoder->appendedFields(); 110 : 0 : mAdditionalFields = newFields.names(); 111 : : 112 : 0 : return QgsProcessingUtils::combineFields( inputFields, newFields ); 113 : 0 : } 114 : : else 115 : : { 116 : 0 : return inputFields; 117 : : } 118 : 0 : } 119 : : 120 : 0 : QgsFeatureList QgsBatchGeocodeAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) 121 : : { 122 : 0 : QgsFeature f = feature; 123 : : 124 : 0 : const QString address = f.attribute( mAddressField ).toString(); 125 : 0 : if ( address.isEmpty() ) 126 : : { 127 : 0 : f.padAttributes( mAdditionalFields.count() ); 128 : 0 : feedback->pushWarning( QObject::tr( "Empty address field for feature %1" ).arg( feature.id() ) ); 129 : 0 : return QgsFeatureList() << f; 130 : : } 131 : : 132 : 0 : QgsGeocoderContext geocodeContext( context.transformContext() ); 133 : 0 : const QList< QgsGeocoderResult > results = mGeocoder->geocodeString( address, geocodeContext, feedback ); 134 : 0 : if ( results.empty() ) 135 : : { 136 : 0 : f.padAttributes( mAdditionalFields.count() ); 137 : 0 : feedback->pushWarning( QObject::tr( "No result for %1" ).arg( address ) ); 138 : 0 : return QgsFeatureList() << f; 139 : : } 140 : : 141 : 0 : if ( !results.at( 0 ).isValid() ) 142 : : { 143 : 0 : f.padAttributes( mAdditionalFields.count() ); 144 : 0 : feedback->reportError( QObject::tr( "Error geocoding %1: %2" ).arg( address, results.at( 0 ).error() ) ); 145 : 0 : return QgsFeatureList() << f; 146 : : } 147 : : 148 : 0 : QgsAttributes attr = f.attributes(); 149 : 0 : const QVariantMap additionalAttributes = results.at( 0 ).additionalAttributes(); 150 : 0 : if ( !mIsInPlace ) 151 : : { 152 : 0 : for ( const QString &additionalField : mAdditionalFields ) 153 : : { 154 : 0 : attr.append( additionalAttributes.value( additionalField ) ); 155 : : } 156 : 0 : f.setAttributes( attr ); 157 : 0 : } 158 : : else 159 : : { 160 : 0 : for ( auto it = mInPlaceFieldMap.constBegin(); it != mInPlaceFieldMap.constEnd(); ++it ) 161 : : { 162 : 0 : if ( !it.value().isEmpty() ) 163 : : { 164 : 0 : f.setAttribute( it.value(), additionalAttributes.value( it.key() ) ); 165 : 0 : } 166 : 0 : } 167 : : } 168 : : 169 : 0 : QgsCoordinateTransform transform = QgsCoordinateTransform( results.at( 0 ).crs(), mOutputCrs, context.transformContext() ); 170 : 0 : QgsGeometry g = results.at( 0 ).geometry(); 171 : : try 172 : : { 173 : 0 : g.transform( transform ); 174 : 0 : } 175 : : catch ( QgsCsException & ) 176 : : { 177 : 0 : feedback->reportError( QObject::tr( "Error transforming %1 to layer CRS" ).arg( address ) ); 178 : 0 : return QgsFeatureList() << f; 179 : 0 : } 180 : : 181 : 0 : f.setGeometry( g ); 182 : 0 : return QgsFeatureList() << f; 183 : 0 : }