QGIS API Documentation  3.24.2-Tisler (13c1a02865)
qgsalgorithmshortestline.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmshortestline.cpp
3  ---------------------
4  begin : September 2021
5  copyright : (C) 2020 by Matteo Ghetta, Clemens Raffler
6  email : clemens dot raffler 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 //Disclaimer:This feature was originally developed in Python by: Matteo Ghetta, August 2021
19 
21 #include "qgsdistancearea.h"
22 
24 
25 QString QgsShortestLineAlgorithm::name() const
26 {
27  return QStringLiteral( "shortestline" );
28 }
29 
30 QString QgsShortestLineAlgorithm::displayName() const
31 {
32  return QObject::tr( "Shortest line between features" );
33 }
34 
35 QStringList QgsShortestLineAlgorithm::tags() const
36 {
37  return QObject::tr( "distance,shortest,minimum,nearest,closest,proximity" ).split( ',' );
38 }
39 
40 QString QgsShortestLineAlgorithm::group() const
41 {
42  return QObject::tr( "Vector analysis" );
43 }
44 
45 QString QgsShortestLineAlgorithm::groupId() const
46 {
47  return QStringLiteral( "vectoranalysis" );
48 }
49 
50 QString QgsShortestLineAlgorithm::shortHelpString() const
51 {
52  return QObject::tr( "This algorithm creates a line layer as the "
53  "shortest line between the source and the destination layer. "
54  "By default only the first nearest feature of the "
55  "destination layer is taken into account. "
56  "The n-nearest neighboring features number can be specified.\n\n"
57  "If a maximum distance is specified, then only "
58  "features which are closer than this distance will "
59  "be considered.\n\nThe output features will contain all the "
60  "source layer attributes, all the attributes from the n-nearest "
61  "feature and the additional field of the distance.\n\n"
62  "This algorithm uses purely Cartesian calculations for distance, "
63  "and does not consider geodetic or ellipsoid properties when "
64  "determining feature proximity. The measurement and output coordinate "
65  "system is based on the coordinate system of the source layer."
66  );
67 }
68 
69 QgsShortestLineAlgorithm *QgsShortestLineAlgorithm::createInstance() const
70 {
71  return new QgsShortestLineAlgorithm();
72 }
73 
74 void QgsShortestLineAlgorithm::initAlgorithm( const QVariantMap & )
75 {
76  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "SOURCE" ), QObject::tr( "Source layer" ), QList<int>() << QgsProcessing::TypeVectorAnyGeometry ) );
77  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "DESTINATION" ), QObject::tr( "Destination layer" ), QList<int>() << QgsProcessing::TypeVectorAnyGeometry ) );
78  addParameter( new QgsProcessingParameterEnum( QStringLiteral( "METHOD" ), QObject::tr( "Method" ), QStringList() << "Distance to Nearest Point on feature" << "Distance to Feature Centroid", false, 0 ) );
79  addParameter( new QgsProcessingParameterNumber( QStringLiteral( "NEIGHBORS" ), QObject::tr( "Maximum number of neighbors" ), QgsProcessingParameterNumber::Integer, 1, false, 1 ) );
80  addParameter( new QgsProcessingParameterDistance( QStringLiteral( "DISTANCE" ), QObject::tr( "Maximum distance" ), QVariant(), QString( "SOURCE" ), true ) );
81  addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Shortest lines" ), QgsProcessing::TypeVectorLine ) );
82 }
83 
84 bool QgsShortestLineAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
85 {
86  mSource.reset( parameterAsSource( parameters, QStringLiteral( "SOURCE" ), context ) );
87  if ( !mSource )
88  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "SOURCE" ) ) );
89 
90  mDestination.reset( parameterAsSource( parameters, QStringLiteral( "DESTINATION" ), context ) );
91  if ( !mDestination )
92  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "DESTINATION" ) ) );
93 
94  mMethod = parameterAsInt( parameters, QStringLiteral( "METHOD" ), context );
95 
96  mKNeighbors = parameterAsInt( parameters, QStringLiteral( "NEIGHBORS" ), context );
97 
98  mMaxDistance = parameterAsDouble( parameters, QStringLiteral( "DISTANCE" ), context ); //defaults to zero if not set
99 
100  return true;
101 }
102 
103 QVariantMap QgsShortestLineAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
104 {
105  if ( mKNeighbors > mDestination->featureCount() )
106  mKNeighbors = mDestination->featureCount();
107 
108  QgsFields fields = QgsProcessingUtils::combineFields( mSource->fields(), mDestination->fields() );
109  fields.append( QgsField( QStringLiteral( "distance" ), QVariant::Double ) );
110 
111  QString dest;
112  std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, QgsWkbTypes::MultiLineString, mSource->sourceCrs() ) );
113  if ( !sink )
114  throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
115 
116  const QgsFeatureIterator destinationIterator = mDestination->getFeatures( QgsFeatureRequest().setDestinationCrs( mSource->sourceCrs(), context.transformContext() ) );
117  QHash< QgsFeatureId, QgsAttributes > destinationAttributeCache;
118  double step = mDestination->featureCount() > 0 ? 50.0 / mDestination->featureCount() : 1;
119  int i = 0;
120  const QgsSpatialIndex idx( destinationIterator, [&]( const QgsFeature & f )->bool
121  {
122  i++;
123  if ( feedback-> isCanceled() )
124  return false;
125 
126  feedback->setProgress( i * step );
127 
128  destinationAttributeCache.insert( f.id(), f.attributes() );
129 
130  return true;
132 
133  step = mSource->featureCount() > 0 ? 50.0 / mSource->featureCount() : 1;
134  QgsFeatureIterator sourceIterator = mSource->getFeatures();
135 
137  da.setSourceCrs( mSource->sourceCrs(), context.transformContext() );
138 
139  QgsFeature sourceFeature;
140  while ( sourceIterator.nextFeature( sourceFeature ) )
141  {
142  if ( feedback->isCanceled() )
143  break;
144 
145  const QgsGeometry sourceGeom = sourceFeature.geometry();
146  QgsFeatureIds nearestIds = qgis::listToSet( idx.nearestNeighbor( sourceGeom, mKNeighbors, mMaxDistance ) );
147 
148  for ( const QgsFeatureId id : nearestIds )
149  {
150  QgsGeometry destinationGeom = idx.geometry( id );
151  if ( mMethod == 1 )
152  {
153  destinationGeom = idx.geometry( id ).centroid();
154  }
155 
156  const QgsGeometry shortestLine = sourceGeom.shortestLine( destinationGeom );
157  double dist = da.measureLength( shortestLine );
158  QgsFeature f;
159  QgsAttributes attrs = sourceFeature.attributes();
160  attrs << destinationAttributeCache.value( id ) << dist;
161 
162  f.setAttributes( attrs );
163  f.setGeometry( shortestLine );
164  sink->addFeature( f, QgsFeatureSink::FastInsert );
165  }
166 
167  i++;
168  feedback->setProgress( i * step );
169  }
170 
171 
172  QVariantMap outputs;
173  outputs.insert( QStringLiteral( "OUTPUT" ), dest );
174  return outputs;
175 }
176 
A vector of attributes.
Definition: qgsattributes.h:58
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
double measureLength(const QgsGeometry &geometry) const
Measures the length of a geometry.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QgsAttributes attributes
Definition: qgsfeature.h:65
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:153
QgsGeometry geometry
Definition: qgsfeature.h:67
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:163
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:63
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
Container of fields for a vector layer.
Definition: qgsfields.h:45
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)
Definition: qgsfields.cpp:59
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:125
QgsGeometry centroid() const
Returns the center of mass of a geometry.
QgsGeometry shortestLine(const QgsGeometry &other) const
Returns the shortest line joining this geometry to another geometry.
Contains information about the context in which a processing algorithm is executed.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
Custom exception class for processing related exceptions.
Definition: qgsexception.h:83
Base class for providing feedback from a processing algorithm.
A double numeric parameter for distance values.
An enum based parameter for processing algorithms, allowing for selection from predefined values.
A feature sink output for processing algorithms.
An input feature source (such as vector layers) parameter for processing algorithms.
A numeric parameter for processing algorithms.
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).
@ TypeVectorLine
Vector line layers.
Definition: qgsprocessing.h:50
@ TypeVectorAnyGeometry
Any vector layer with geometry.
Definition: qgsprocessing.h:48
A spatial index for QgsFeature objects.
@ FlagStoreFeatureGeometries
Indicates that the spatial index should also store feature geometries. This requires more memory,...
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28