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.\n\n" 93 "If a maximum distance is specified, then only features which are closer than this distance " 94 "will be matched.\n\n" 95 "The output features will contain the selected attributes from the nearest feature, " 96 "along with new attributes for the distance to the near feature, the index of the feature, " 97 "and the coordinates of the closest point on the input feature (feature_x, feature_y) " 98 "to the matched nearest feature, and the coordinates of the closet point on the matched feature " 99 "(nearest_x, nearest_y).\n\n" 100 "This algorithm uses purely Cartesian calculations for distance, and does not consider " 101 "geodetic or ellipsoid properties when determining feature proximity." );
104 QString QgsJoinByNearestAlgorithm::shortDescription()
const 106 return QObject::tr(
"Joins a layer to another layer, using the closest features (nearest neighbors)." );
109 QgsJoinByNearestAlgorithm *QgsJoinByNearestAlgorithm::createInstance()
const 111 return new QgsJoinByNearestAlgorithm();
116 const int neighbors = parameterAsInt( parameters, QStringLiteral(
"NEIGHBORS" ), context );
117 const bool discardNonMatching = parameterAsBoolean( parameters, QStringLiteral(
"DISCARD_NONMATCHING" ), context );
118 const double maxDistance = parameters.value( QStringLiteral(
"MAX_DISTANCE" ) ).isValid() ? parameterAsDouble( parameters, QStringLiteral(
"MAX_DISTANCE" ), context ) : std::numeric_limits< double >::quiet_NaN();
119 std::unique_ptr< QgsProcessingFeatureSource > input( parameterAsSource( parameters, QStringLiteral(
"INPUT" ), context ) );
123 std::unique_ptr< QgsProcessingFeatureSource > input2( parameterAsSource( parameters, QStringLiteral(
"INPUT_2" ), context ) );
127 const bool sameSourceAndTarget = parameters.value( QStringLiteral(
"INPUT" ) ) == parameters.value( QStringLiteral(
"INPUT_2" ) );
129 QString prefix = parameterAsString( parameters, QStringLiteral(
"PREFIX" ), context );
130 const QStringList fieldsToCopy = parameterAsFields( parameters, QStringLiteral(
"FIELDS_TO_COPY" ), context );
134 if ( fieldsToCopy.empty() )
136 outFields2 = input2->fields();
137 fields2Indices.reserve( outFields2.
count() );
138 for (
int i = 0; i < outFields2.
count(); ++i )
145 fields2Indices.reserve( fieldsToCopy.count() );
146 for (
const QString &field : fieldsToCopy )
151 fields2Indices << index;
152 outFields2.
append( input2->fields().at( index ) );
157 if ( !prefix.isEmpty() )
159 for (
int i = 0; i < outFields2.
count(); ++i )
161 outFields2[ i ].setName( prefix + outFields2[ i ].name() );
168 outFields.
append(
QgsField( QStringLiteral(
"n" ), QVariant::Int ) );
169 outFields.
append(
QgsField( QStringLiteral(
"distance" ), QVariant::Double ) );
170 outFields.
append(
QgsField( QStringLiteral(
"feature_x" ), QVariant::Double ) );
171 outFields.
append(
QgsField( QStringLiteral(
"feature_y" ), QVariant::Double ) );
172 outFields.
append(
QgsField( QStringLiteral(
"nearest_x" ), QVariant::Double ) );
173 outFields.
append(
QgsField( QStringLiteral(
"nearest_y" ), QVariant::Double ) );
176 std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral(
"OUTPUT" ), context, dest, outFields,
178 if ( parameters.value( QStringLiteral(
"OUTPUT" ) ).isValid() && !sink )
181 QString destNonMatching1;
182 std::unique_ptr< QgsFeatureSink > sinkNonMatching1( parameterAsSink( parameters, QStringLiteral(
"NON_MATCHING" ), context, destNonMatching1, input->fields(),
184 if ( parameters.value( QStringLiteral(
"NON_MATCHING" ) ).isValid() && !sinkNonMatching1 )
190 QHash< QgsFeatureId, QgsAttributes > input2AttributeCache;
192 double step = input2->featureCount() > 0 ? 50.0 / input2->featureCount() : 1;
205 index.addFeature( f );
208 for (
int j = 0; j < f.
attributes().count(); ++j )
210 if ( ! fields2Indices.contains( j ) )
214 input2AttributeCache.insert( f.
id(), attributes );
219 for (
int i = 0; i < fields2Indices.count() + 6; ++i )
220 nullMatch << QVariant();
222 long long joinedCount = 0;
223 long long unjoinedCount = 0;
226 step = input->featureCount() > 0 ? 50.0 / input->featureCount() : 1;
242 if ( sinkNonMatching1 )
246 if ( sink && !discardNonMatching )
249 attr.append( nullMatch );
257 const QList< QgsFeatureId > nearest = index.nearestNeighbor( f.
geometry(), neighbors + ( sameSourceAndTarget ? 1 : 0 ), std::isnan( maxDistance ) ? 0 : maxDistance );
263 if ( sameSourceAndTarget &&
id == f.
id() )
269 attr.append( input2AttributeCache.value(
id ) );
273 if (
const QgsLineString *line = qgsgeometry_cast< const QgsLineString *>( closestLine.
constGet() ) )
275 attr.append( line->length() );
276 attr.append( line->startPoint().x() );
277 attr.append( line->startPoint().y() );
278 attr.append( line->endPoint().x() );
279 attr.append( line->endPoint().y() );
283 attr.append( QVariant() );
284 attr.append( QVariant() );
285 attr.append( QVariant() );
286 attr.append( QVariant() );
287 attr.append( QVariant() );
297 if ( sinkNonMatching1 )
301 if ( !discardNonMatching && sink )
304 attr.append( nullMatch );
314 outputs.insert( QStringLiteral(
"JOINED_COUNT" ), joinedCount );
315 outputs.insert( QStringLiteral(
"UNJOINABLE_COUNT" ), unjoinedCount );
317 outputs.insert( QStringLiteral(
"OUTPUT" ), dest );
318 if ( sinkNonMatching1 )
319 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 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...
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...