24 QString QgsJoinByNearestAlgorithm::name()
const 26 return QStringLiteral(
"joinbynearest" );
29 QString QgsJoinByNearestAlgorithm::displayName()
const 31 return QObject::tr(
"Join attributes by nearest" );
34 QStringList QgsJoinByNearestAlgorithm::tags()
const 36 return QObject::tr(
"join,connect,attributes,values,fields,tables,proximity,closest,neighbour,neighbor,n-nearest,distance" ).split(
',' );
39 QString QgsJoinByNearestAlgorithm::group()
const 41 return QObject::tr(
"Vector general" );
44 QString QgsJoinByNearestAlgorithm::groupId()
const 46 return QStringLiteral(
"vectorgeneral" );
49 void QgsJoinByNearestAlgorithm::initAlgorithm(
const QVariantMap & )
52 QObject::tr(
"Input layer" ) ) );
54 QObject::tr(
"Input layer 2" ) ) );
57 QObject::tr(
"Layer 2 fields to copy (leave empty to copy all fields)" ),
62 QObject::tr(
"Discard records which could not be joined" ),
66 QObject::tr(
"Joined field prefix" ), QVariant(),
false,
true ) );
72 QObject::tr(
"Maximum distance" ), QVariant(), QStringLiteral(
"INPUT" ),
true, 0 ) );
76 std::unique_ptr< QgsProcessingParameterFeatureSink > nonMatchingSink = qgis::make_unique< QgsProcessingParameterFeatureSink >(
80 addParameter( nonMatchingSink.release() );
82 addOutput(
new QgsProcessingOutputNumber( QStringLiteral(
"JOINED_COUNT" ), QObject::tr(
"Number of joined features from input table" ) ) );
83 addOutput(
new QgsProcessingOutputNumber( QStringLiteral(
"UNJOINABLE_COUNT" ), QObject::tr(
"Number of unjoinable features from input table" ) ) );
86 QString QgsJoinByNearestAlgorithm::shortHelpString()
const 88 return QObject::tr(
"This algorithm takes an input vector layer and creates a new vector layer that is an extended version of the " 89 "input one, with additional attributes in its attribute table.\n\n" 90 "The additional attributes and their values are taken from a second vector layer, where features are joined " 91 "by finding the closest features from each layer. By default only the single nearest feature is joined," 92 "but optionally the join can use the n-nearest neighboring features instead. If multiple features are found " 93 "with identical distances these will all be returned (even if the total number of features exceeds the specified " 94 "maximum feature count).\n\n" 95 "If a maximum distance is specified, then only features which are closer than this distance " 96 "will be matched.\n\n" 97 "The output features will contain the selected attributes from the nearest feature, " 98 "along with new attributes for the distance to the near feature, the index of the feature, " 99 "and the coordinates of the closest point on the input feature (feature_x, feature_y) " 100 "to the matched nearest feature, and the coordinates of the closet point on the matched feature " 101 "(nearest_x, nearest_y).\n\n" 102 "This algorithm uses purely Cartesian calculations for distance, and does not consider " 103 "geodetic or ellipsoid properties when determining feature proximity." );
106 QString QgsJoinByNearestAlgorithm::shortDescription()
const 108 return QObject::tr(
"Joins a layer to another layer, using the closest features (nearest neighbors)." );
111 QgsJoinByNearestAlgorithm *QgsJoinByNearestAlgorithm::createInstance()
const 113 return new QgsJoinByNearestAlgorithm();
118 const int neighbors = parameterAsInt( parameters, QStringLiteral(
"NEIGHBORS" ), context );
119 const bool discardNonMatching = parameterAsBoolean( parameters, QStringLiteral(
"DISCARD_NONMATCHING" ), context );
120 const double maxDistance = parameters.value( QStringLiteral(
"MAX_DISTANCE" ) ).isValid() ? parameterAsDouble( parameters, QStringLiteral(
"MAX_DISTANCE" ), context ) : std::numeric_limits< double >::quiet_NaN();
121 std::unique_ptr< QgsProcessingFeatureSource > input( parameterAsSource( parameters, QStringLiteral(
"INPUT" ), context ) );
125 std::unique_ptr< QgsProcessingFeatureSource > input2( parameterAsSource( parameters, QStringLiteral(
"INPUT_2" ), context ) );
129 const bool sameSourceAndTarget = parameters.value( QStringLiteral(
"INPUT" ) ) == parameters.value( QStringLiteral(
"INPUT_2" ) );
131 QString prefix = parameterAsString( parameters, QStringLiteral(
"PREFIX" ), context );
132 const QStringList fieldsToCopy = parameterAsFields( parameters, QStringLiteral(
"FIELDS_TO_COPY" ), context );
136 if ( fieldsToCopy.empty() )
138 outFields2 = input2->fields();
139 fields2Indices.reserve( outFields2.
count() );
140 for (
int i = 0; i < outFields2.
count(); ++i )
147 fields2Indices.reserve( fieldsToCopy.count() );
148 for (
const QString &field : fieldsToCopy )
153 fields2Indices << index;
154 outFields2.
append( input2->fields().at( index ) );
159 if ( !prefix.isEmpty() )
161 for (
int i = 0; i < outFields2.
count(); ++i )
163 outFields2.
rename( i, prefix + outFields2[ i ].name() );
170 outFields.
append(
QgsField( QStringLiteral(
"n" ), QVariant::Int ) );
171 outFields.
append(
QgsField( QStringLiteral(
"distance" ), QVariant::Double ) );
172 outFields.
append(
QgsField( QStringLiteral(
"feature_x" ), QVariant::Double ) );
173 outFields.
append(
QgsField( QStringLiteral(
"feature_y" ), QVariant::Double ) );
174 outFields.
append(
QgsField( QStringLiteral(
"nearest_x" ), QVariant::Double ) );
175 outFields.
append(
QgsField( QStringLiteral(
"nearest_y" ), QVariant::Double ) );
178 std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral(
"OUTPUT" ), context, dest, outFields,
180 if ( parameters.value( QStringLiteral(
"OUTPUT" ) ).isValid() && !sink )
183 QString destNonMatching1;
184 std::unique_ptr< QgsFeatureSink > sinkNonMatching1( parameterAsSink( parameters, QStringLiteral(
"NON_MATCHING" ), context, destNonMatching1, input->fields(),
186 if ( parameters.value( QStringLiteral(
"NON_MATCHING" ) ).isValid() && !sinkNonMatching1 )
191 QHash< QgsFeatureId, QgsAttributes > input2AttributeCache;
192 double step = input2->featureCount() > 0 ? 50.0 / input2->featureCount() : 1;
207 for (
int j = 0; j < f.
attributes().count(); ++j )
209 if ( ! fields2Indices.contains( j ) )
213 input2AttributeCache.insert( f.
id(), attributes );
222 nullMatch.reserve( fields2Indices.size() + 6 );
223 for (
int i = 0; i < fields2Indices.count() + 6; ++i )
224 nullMatch << QVariant();
226 long long joinedCount = 0;
227 long long unjoinedCount = 0;
230 step = input->featureCount() > 0 ? 50.0 / input->featureCount() : 1;
243 if ( !f.hasGeometry() )
246 if ( sinkNonMatching1 )
250 if ( sink && !discardNonMatching )
253 attr.append( nullMatch );
254 f.setAttributes( attr );
261 const QList< QgsFeatureId > nearest = index.nearestNeighbor( f.geometry(), neighbors + ( sameSourceAndTarget ? 1 : 0 ), std::isnan( maxDistance ) ? 0 : maxDistance );
263 if ( nearest.count() > neighbors + ( sameSourceAndTarget ? 1 : 0 ) )
265 feedback->
pushInfo( QObject::tr(
"Multiple matching features found at same distance from search feature, found %1 features instead of %2" ).arg( nearest.count() - ( sameSourceAndTarget ? 1 : 0 ) ).arg( neighbors ) );
272 if ( sameSourceAndTarget &&
id == f.id() )
278 attr.append( input2AttributeCache.value(
id ) );
282 if (
const QgsLineString *line = qgsgeometry_cast< const QgsLineString *>( closestLine.
constGet() ) )
284 attr.append( line->length() );
285 attr.append( line->startPoint().x() );
286 attr.append( line->startPoint().y() );
287 attr.append( line->endPoint().x() );
288 attr.append( line->endPoint().y() );
292 attr.append( QVariant() );
293 attr.append( QVariant() );
294 attr.append( QVariant() );
295 attr.append( QVariant() );
296 attr.append( QVariant() );
306 if ( sinkNonMatching1 )
310 if ( !discardNonMatching && sink )
313 attr.append( nullMatch );
314 f.setAttributes( attr );
323 outputs.insert( QStringLiteral(
"JOINED_COUNT" ), joinedCount );
324 outputs.insert( QStringLiteral(
"UNJOINABLE_COUNT" ), unjoinedCount );
326 outputs.insert( QStringLiteral(
"OUTPUT" ), dest );
327 if ( sinkNonMatching1 )
328 outputs.insert( QStringLiteral(
"NON_MATCHING" ), destNonMatching1 );
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
A boolean parameter for processing algorithms.
Wrapper for iterator of features from vector data provider or vector layer.
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
Base class for providing feedback from a processing algorithm.
A vector layer or feature source field parameter for processing algorithms.
void setProgress(double progress)
Sets the current progress for the feedback object.
Container of fields for a vector layer.
A geometry is the spatial representation of a feature.
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
A numeric output for processing algorithms.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
bool rename(int fieldIdx, const QString &name)
Renames a name of field.
bool hasGeometry() const
Returns true if the feature has an associated geometry.
int count() const
Returns number of items.
A feature sink output for processing algorithms.
This flag indicates, that a primary key field cannot be guaranteed to be unique and the sink should i...
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
A double numeric parameter for distance values.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
Custom exception class for processing related exceptions.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false) ...
Encapsulate a field in an attribute table or data source.
A numeric parameter for processing algorithms.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
A spatial index for QgsFeature objects.
bool isCanceled() const
Tells whether the operation has been canceled already.
An input feature source (such as vector layers) parameter for processing algorithms.
Line string geometry type, with support for z-dimension and m-values.
QgsGeometry shortestLine(const QgsGeometry &other) const
Returns the shortest line joining this geometry to another geometry.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
QList< int > QgsAttributeList
bool nextFeature(QgsFeature &f)
static QgsFields combineFields(const QgsFields &fieldsA, const QgsFields &fieldsB, const QString &fieldsBPrefix=QString())
Combines two field lists, avoiding duplicate field names (in a case-insensitive manner).
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Contains information about the context in which a processing algorithm is executed.
A string parameter for processing algorithms.
Any vector layer with geometry.
Indicates that the spatial index should also store feature geometries. This requires more memory...