QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgsalgorithmsumlinelength.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmsumlinelength.cpp
3  ---------------------
4  begin : November 2019
5  copyright : (C) 2019 by Alexander Bruy
6  email : alexander dot bruy 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 
19 #include "qgsprocessing.h"
20 #include "qgsgeometryengine.h"
21 #include "qgsvectorlayer.h"
22 #include "qgsapplication.h"
23 
25 
26 QString QgsSumLineLengthAlgorithm::name() const
27 {
28  return QStringLiteral( "sumlinelengths" );
29 }
30 
31 QString QgsSumLineLengthAlgorithm::displayName() const
32 {
33  return QObject::tr( "Sum line lengths" );
34 }
35 
36 QStringList QgsSumLineLengthAlgorithm::tags() const
37 {
38  return QObject::tr( "line,intersects,intersecting,sum,length,count" ).split( ',' );
39 }
40 
41 QString QgsSumLineLengthAlgorithm::svgIconPath() const
42 {
43  return QgsApplication::iconPath( QStringLiteral( "/algorithms/mAlgorithmSumLengthLines.svg" ) );
44 }
45 
46 QIcon QgsSumLineLengthAlgorithm::icon() const
47 {
48  return QgsApplication::getThemeIcon( QStringLiteral( "/algorithms/mAlgorithmSumLengthLines.svg" ) );
49 }
50 
51 QString QgsSumLineLengthAlgorithm::group() const
52 {
53  return QObject::tr( "Vector analysis" );
54 }
55 
56 QString QgsSumLineLengthAlgorithm::groupId() const
57 {
58  return QStringLiteral( "vectoranalysis" );
59 }
60 
61 QString QgsSumLineLengthAlgorithm::shortHelpString() const
62 {
63  return QObject::tr( "This algorithm takes a polygon layer and a line layer and "
64  "measures the total length of lines and the total number of "
65  "them that cross each polygon.\n\n"
66  "The resulting layer has the same features as the input polygon "
67  "layer, but with two additional attributes containing the length "
68  "and count of the lines across each polygon. The names of these "
69  "two fields can be configured in the algorithm parameters." );
70 }
71 
72 QgsSumLineLengthAlgorithm *QgsSumLineLengthAlgorithm::createInstance() const
73 {
74  return new QgsSumLineLengthAlgorithm();
75 }
76 
77 QList<int> QgsSumLineLengthAlgorithm::inputLayerTypes() const
78 {
79  return QList< int >() << QgsProcessing::TypeVectorPolygon;
80 }
81 
82 QgsProcessing::SourceType QgsSumLineLengthAlgorithm::outputLayerType() const
83 {
85 }
86 
88 {
89  mCrs = inputCrs;
90  mDa.setSourceCrs( mCrs, mTransformContext );
91  return mCrs;
92 }
93 
94 QString QgsSumLineLengthAlgorithm::inputParameterName() const
95 {
96  return QStringLiteral( "POLYGONS" );
97 }
98 
99 QString QgsSumLineLengthAlgorithm::inputParameterDescription() const
100 {
101  return QObject::tr( "Polygons" );
102 }
103 
104 QString QgsSumLineLengthAlgorithm::outputName() const
105 {
106  return QObject::tr( "Line length" );
107 }
108 
109 void QgsSumLineLengthAlgorithm::initParameters( const QVariantMap &configuration )
110 {
111  mIsInPlace = configuration.value( QStringLiteral( "IN_PLACE" ) ).toBool();
112 
113  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "LINES" ),
114  QObject::tr( "Lines" ), QList< int > () << QgsProcessing::TypeVectorLine ) );
115  if ( mIsInPlace )
116  {
117  addParameter( new QgsProcessingParameterField( QStringLiteral( "LEN_FIELD" ),
118  QObject::tr( "Lines length field name" ), QStringLiteral( "LENGTH" ), inputParameterName(), QgsProcessingParameterField::Any, false, true ) );
119  addParameter( new QgsProcessingParameterField( QStringLiteral( "COUNT_FIELD" ),
120  QObject::tr( "Lines count field name" ), QStringLiteral( "COUNT" ), inputParameterName(), QgsProcessingParameterField::Any, false, true ) );
121  }
122  else
123  {
124  addParameter( new QgsProcessingParameterString( QStringLiteral( "LEN_FIELD" ),
125  QObject::tr( "Lines length field name" ), QStringLiteral( "LENGTH" ) ) );
126  addParameter( new QgsProcessingParameterString( QStringLiteral( "COUNT_FIELD" ),
127  QObject::tr( "Lines count field name" ), QStringLiteral( "COUNT" ) ) );
128  }
129 }
130 
131 bool QgsSumLineLengthAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
132 {
133  mLengthFieldName = parameterAsString( parameters, QStringLiteral( "LEN_FIELD" ), context );
134  mCountFieldName = parameterAsString( parameters, QStringLiteral( "COUNT_FIELD" ), context );
135 
136  mLinesSource.reset( parameterAsSource( parameters, QStringLiteral( "LINES" ), context ) );
137  if ( !mLinesSource )
138  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "LINES" ) ) );
139 
140  if ( mLinesSource->hasSpatialIndex() == QgsFeatureSource::SpatialIndexNotPresent )
141  feedback->pushWarning( QObject::tr( "No spatial index exists for lines layer, performance will be severely degraded" ) );
142 
143  mDa.setEllipsoid( context.ellipsoid() );
144  mTransformContext = context.transformContext();
145 
146  return true;
147 }
148 
149 QgsFields QgsSumLineLengthAlgorithm::outputFields( const QgsFields &inputFields ) const
150 {
151  if ( mIsInPlace )
152  {
153  mLengthFieldIndex = mLengthFieldName.isEmpty() ? -1 : inputFields.lookupField( mLengthFieldName );
154  mCountFieldIndex = mCountFieldName.isEmpty() ? -1 : inputFields.lookupField( mCountFieldName );
155  return inputFields;
156  }
157  else
158  {
159  QgsFields outFields = inputFields;
160  mLengthFieldIndex = inputFields.lookupField( mLengthFieldName );
161  if ( mLengthFieldIndex < 0 )
162  outFields.append( QgsField( mLengthFieldName, QVariant::Double ) );
163 
164  mCountFieldIndex = inputFields.lookupField( mCountFieldName );
165  if ( mCountFieldIndex < 0 )
166  outFields.append( QgsField( mCountFieldName, QVariant::Double ) );
167 
168  mFields = outFields;
169  return outFields;
170  }
171 }
172 
173 bool QgsSumLineLengthAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const
174 {
175  if ( const QgsVectorLayer *vl = qobject_cast< const QgsVectorLayer * >( layer ) )
176  {
177  return vl->geometryType() == QgsWkbTypes::PolygonGeometry;
178  }
179  return false;
180 }
181 
182 QgsFeatureList QgsSumLineLengthAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
183 {
184  QgsFeature outputFeature = feature;
185  if ( !feature.hasGeometry() )
186  {
187  QgsAttributes attrs = feature.attributes();
188  if ( !mIsInPlace && mLengthFieldIndex < 0 )
189  attrs.append( 0 );
190  else if ( mLengthFieldIndex >= 0 )
191  attrs[mLengthFieldIndex] = 0;
192 
193  if ( !mIsInPlace && mCountFieldIndex < 0 )
194  attrs.append( 0 );
195  else if ( mCountFieldIndex >= 0 )
196  attrs[mCountFieldIndex] = 0;
197 
198  outputFeature.setAttributes( attrs );
199  return QList< QgsFeature > () << outputFeature;
200  }
201  else
202  {
203  const QgsGeometry polyGeom = feature.geometry();
204  std::unique_ptr< QgsGeometryEngine > engine( QgsGeometry::createGeometryEngine( polyGeom.constGet() ) );
205  engine->prepareGeometry();
206 
208  req.setSubsetOfAttributes( QList< int >() );
209  QgsFeatureIterator it = mLinesSource->getFeatures( req );
210 
211  double count = 0;
212  double length = 0;
213 
214  QgsFeature lineFeature;
215  while ( it.nextFeature( lineFeature ) )
216  {
217  if ( feedback->isCanceled() )
218  break;
219 
220  if ( engine->intersects( lineFeature.geometry().constGet() ) )
221  {
222  QgsGeometry outGeom = polyGeom.intersection( lineFeature.geometry() );
223  length += mDa.measureLength( outGeom );
224  count++;
225  }
226  }
227 
228  QgsAttributes attrs = feature.attributes();
229  if ( !mIsInPlace && mLengthFieldIndex < 0 )
230  attrs.append( length );
231  else if ( mLengthFieldIndex >= 0 )
232  attrs[mLengthFieldIndex] = length;
233 
234  if ( !mIsInPlace && mCountFieldIndex < 0 )
235  attrs.append( count );
236  else if ( mCountFieldIndex >= 0 )
237  attrs[mCountFieldIndex] = count;
238 
239  outputFeature.setAttributes( attrs );
240  return QList< QgsFeature >() << outputFeature;
241  }
242 }
243 
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
A vector of attributes.
Definition: qgsattributes.h:58
This class represents a coordinate 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).
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature's geometries.
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
@ SpatialIndexNotPresent
No spatial index exists for the source.
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:135
QgsGeometry geometry
Definition: qgsfeature.h:67
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:205
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
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
bool isEmpty() const
Checks whether the container is empty.
Definition: qgsfields.cpp:128
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:344
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QgsGeometry intersection(const QgsGeometry &geometry) const
Returns a geometry representing the points shared by this geometry and other.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine representing the specified geometry.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Base class for all map layer types.
Definition: qgsmaplayer.h:70
Contains information about the context in which a processing algorithm is executed.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
QString ellipsoid() const
Returns the ellipsoid to use for distance and area calculations.
Custom exception class for processing related exceptions.
Definition: qgsexception.h:83
Base class for providing feedback from a processing algorithm.
virtual void pushWarning(const QString &warning)
Pushes a warning informational message from the algorithm.
An input feature source (such as vector layers) parameter for processing algorithms.
A vector layer or feature source field parameter for processing algorithms.
A string parameter for processing algorithms.
SourceType
Data source types enum.
Definition: qgsprocessing.h:46
@ TypeVectorLine
Vector line layers.
Definition: qgsprocessing.h:50
@ TypeVectorPolygon
Vector polygon layers.
Definition: qgsprocessing.h:51
Represents a vector layer which manages a vector based data sets.
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:736
const QgsCoordinateReferenceSystem & outputCrs