QGIS API Documentation 3.43.0-Master (e01d6d7c4c0)
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
26QString QgsSumLineLengthAlgorithm::name() const
27{
28 return QStringLiteral( "sumlinelengths" );
29}
30
31QString QgsSumLineLengthAlgorithm::displayName() const
32{
33 return QObject::tr( "Sum line lengths" );
34}
35
36QStringList QgsSumLineLengthAlgorithm::tags() const
37{
38 return QObject::tr( "line,intersects,intersecting,sum,length,count" ).split( ',' );
39}
40
41QString QgsSumLineLengthAlgorithm::svgIconPath() const
42{
43 return QgsApplication::iconPath( QStringLiteral( "/algorithms/mAlgorithmSumLengthLines.svg" ) );
44}
45
46QIcon QgsSumLineLengthAlgorithm::icon() const
47{
48 return QgsApplication::getThemeIcon( QStringLiteral( "/algorithms/mAlgorithmSumLengthLines.svg" ) );
49}
50
51QString QgsSumLineLengthAlgorithm::group() const
52{
53 return QObject::tr( "Vector analysis" );
54}
55
56QString QgsSumLineLengthAlgorithm::groupId() const
57{
58 return QStringLiteral( "vectoranalysis" );
59}
60
61QString 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
72QString QgsSumLineLengthAlgorithm::shortDescription() const
73{
74 return QObject::tr( "Takes a polygon layer and a line layer and "
75 "measures the total length of lines and the total number of "
76 "them that cross each polygon." );
77}
78
79QgsSumLineLengthAlgorithm *QgsSumLineLengthAlgorithm::createInstance() const
80{
81 return new QgsSumLineLengthAlgorithm();
82}
83
84QList<int> QgsSumLineLengthAlgorithm::inputLayerTypes() const
85{
86 return QList<int>() << static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon );
87}
88
89Qgis::ProcessingSourceType QgsSumLineLengthAlgorithm::outputLayerType() const
90{
92}
93
94QgsCoordinateReferenceSystem QgsSumLineLengthAlgorithm::outputCrs( const QgsCoordinateReferenceSystem &inputCrs ) const
95{
96 mCrs = inputCrs;
97 mDa.setSourceCrs( mCrs, mTransformContext );
98 return mCrs;
99}
100
101QString QgsSumLineLengthAlgorithm::inputParameterName() const
102{
103 return QStringLiteral( "POLYGONS" );
104}
105
106QString QgsSumLineLengthAlgorithm::inputParameterDescription() const
107{
108 return QObject::tr( "Polygons" );
109}
110
111QString QgsSumLineLengthAlgorithm::outputName() const
112{
113 return QObject::tr( "Line length" );
114}
115
116void QgsSumLineLengthAlgorithm::initParameters( const QVariantMap &configuration )
117{
118 mIsInPlace = configuration.value( QStringLiteral( "IN_PLACE" ) ).toBool();
119
120 addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "LINES" ), QObject::tr( "Lines" ), QList<int>() << static_cast<int>( Qgis::ProcessingSourceType::VectorLine ) ) );
121 if ( mIsInPlace )
122 {
123 addParameter( new QgsProcessingParameterField( QStringLiteral( "LEN_FIELD" ), QObject::tr( "Lines length field name" ), QStringLiteral( "LENGTH" ), inputParameterName(), Qgis::ProcessingFieldParameterDataType::Any, false, true ) );
124 addParameter( new QgsProcessingParameterField( QStringLiteral( "COUNT_FIELD" ), QObject::tr( "Lines count field name" ), QStringLiteral( "COUNT" ), inputParameterName(), Qgis::ProcessingFieldParameterDataType::Any, false, true ) );
125 }
126 else
127 {
128 addParameter( new QgsProcessingParameterString( QStringLiteral( "LEN_FIELD" ), QObject::tr( "Lines length field name" ), QStringLiteral( "LENGTH" ) ) );
129 addParameter( new QgsProcessingParameterString( QStringLiteral( "COUNT_FIELD" ), QObject::tr( "Lines count field name" ), QStringLiteral( "COUNT" ) ) );
130 }
131}
132
133bool QgsSumLineLengthAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
134{
135 mLengthFieldName = parameterAsString( parameters, QStringLiteral( "LEN_FIELD" ), context );
136 mCountFieldName = parameterAsString( parameters, QStringLiteral( "COUNT_FIELD" ), context );
137
138 mLinesSource.reset( parameterAsSource( parameters, QStringLiteral( "LINES" ), context ) );
139 if ( !mLinesSource )
140 throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "LINES" ) ) );
141
142 if ( mLinesSource->hasSpatialIndex() == Qgis::SpatialIndexPresence::NotPresent )
143 feedback->pushWarning( QObject::tr( "No spatial index exists for lines layer, performance will be severely degraded" ) );
144
145 mDa.setEllipsoid( context.ellipsoid() );
146 mTransformContext = context.transformContext();
147
148 return true;
149}
150
151QgsFields QgsSumLineLengthAlgorithm::outputFields( const QgsFields &inputFields ) const
152{
153 if ( mIsInPlace )
154 {
155 mLengthFieldIndex = mLengthFieldName.isEmpty() ? -1 : inputFields.lookupField( mLengthFieldName );
156 mCountFieldIndex = mCountFieldName.isEmpty() ? -1 : inputFields.lookupField( mCountFieldName );
157 return inputFields;
158 }
159 else
160 {
161 QgsFields outFields = inputFields;
162 mLengthFieldIndex = inputFields.lookupField( mLengthFieldName );
163 if ( mLengthFieldIndex < 0 )
164 outFields.append( QgsField( mLengthFieldName, QMetaType::Type::Double ) );
165
166 mCountFieldIndex = inputFields.lookupField( mCountFieldName );
167 if ( mCountFieldIndex < 0 )
168 outFields.append( QgsField( mCountFieldName, QMetaType::Type::Double ) );
169
170 mFields = outFields;
171 return outFields;
172 }
173}
174
175bool QgsSumLineLengthAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const
176{
177 if ( const QgsVectorLayer *vl = qobject_cast<const QgsVectorLayer *>( layer ) )
178 {
179 return vl->geometryType() == Qgis::GeometryType::Polygon;
180 }
181 return false;
182}
183
184QgsFeatureList QgsSumLineLengthAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
185{
186 QgsFeature outputFeature = feature;
187 if ( !feature.hasGeometry() )
188 {
189 QgsAttributes attrs = feature.attributes();
190 if ( !mIsInPlace && mLengthFieldIndex < 0 )
191 attrs.append( 0 );
192 else if ( mLengthFieldIndex >= 0 )
193 attrs[mLengthFieldIndex] = 0;
194
195 if ( !mIsInPlace && mCountFieldIndex < 0 )
196 attrs.append( 0 );
197 else if ( mCountFieldIndex >= 0 )
198 attrs[mCountFieldIndex] = 0;
199
200 outputFeature.setAttributes( attrs );
201 return QList<QgsFeature>() << outputFeature;
202 }
203 else
204 {
205 const QgsGeometry polyGeom = feature.geometry();
206 std::unique_ptr<QgsGeometryEngine> engine( QgsGeometry::createGeometryEngine( polyGeom.constGet() ) );
207 engine->prepareGeometry();
208
210 req.setSubsetOfAttributes( QList<int>() );
211 QgsFeatureIterator it = mLinesSource->getFeatures( req );
212
213 double count = 0;
214 double length = 0;
215
216 QgsFeature lineFeature;
217 while ( it.nextFeature( lineFeature ) )
218 {
219 if ( feedback->isCanceled() )
220 break;
221
222 if ( engine->intersects( lineFeature.geometry().constGet() ) )
223 {
224 const QgsGeometry outGeom = polyGeom.intersection( lineFeature.geometry() );
225 try
226 {
227 length += mDa.measureLength( outGeom );
228 }
229 catch ( QgsCsException & )
230 {
231 throw QgsProcessingException( QObject::tr( "An error occurred while calculating feature length" ) );
232 }
233 count++;
234 }
235 }
236
237 QgsAttributes attrs = feature.attributes();
238 if ( !mIsInPlace && mLengthFieldIndex < 0 )
239 attrs.append( length );
240 else if ( mLengthFieldIndex >= 0 )
241 attrs[mLengthFieldIndex] = length;
242
243 if ( !mIsInPlace && mCountFieldIndex < 0 )
244 attrs.append( count );
245 else if ( mCountFieldIndex >= 0 )
246 attrs[mCountFieldIndex] = count;
247
248 outputFeature.setAttributes( attrs );
249 return QList<QgsFeature>() << outputFeature;
250 }
251}
252
ProcessingSourceType
Processing data source types.
Definition qgis.h:3399
@ VectorPolygon
Vector polygon layers.
@ VectorLine
Vector line layers.
@ NotPresent
No spatial index exists for the source.
@ Polygon
Polygons.
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.
Represents a coordinate reference system (CRS).
Custom exception class for Coordinate Reference System related exceptions.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
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.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
QgsAttributes attributes
Definition qgsfeature.h:67
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
QgsGeometry geometry
Definition qgsfeature.h:69
bool hasGeometry() const
Returns true if the feature has an associated geometry.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:53
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:53
Container of fields for a vector layer.
Definition qgsfields.h:46
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
Definition qgsfields.cpp:70
bool isEmpty
Definition qgsfields.h:49
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
A geometry is the spatial representation of a feature.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QgsGeometry intersection(const QgsGeometry &geometry, const QgsGeometryParameters &parameters=QgsGeometryParameters()) const
Returns a geometry representing the points shared by this geometry and other.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry, double precision=0.0, Qgis::GeosCreationFlags flags=Qgis::GeosCreationFlag::SkipEmptyInteriorRings)
Creates and returns a new geometry engine representing the specified geometry using precision on a gr...
Base class for all map layer types.
Definition qgsmaplayer.h:77
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.
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.
Represents a vector layer which manages a vector based dataset.
QList< QgsFeature > QgsFeatureList