Branch data Line data Source code
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 : : 18 : : #include "qgsalgorithmsumlinelength.h" 19 : : #include "qgsprocessing.h" 20 : : #include "qgsgeometryengine.h" 21 : : #include "qgsvectorlayer.h" 22 : : #include "qgsapplication.h" 23 : : 24 : : ///@cond PRIVATE 25 : : 26 : 0 : QString QgsSumLineLengthAlgorithm::name() const 27 : : { 28 : 0 : return QStringLiteral( "sumlinelengths" ); 29 : : } 30 : : 31 : 0 : QString QgsSumLineLengthAlgorithm::displayName() const 32 : : { 33 : 0 : return QObject::tr( "Sum line lengths" ); 34 : : } 35 : : 36 : 0 : QStringList QgsSumLineLengthAlgorithm::tags() const 37 : : { 38 : 0 : return QObject::tr( "line,intersects,intersecting,sum,length,count" ).split( ',' ); 39 : 0 : } 40 : : 41 : 0 : QString QgsSumLineLengthAlgorithm::svgIconPath() const 42 : : { 43 : 0 : return QgsApplication::iconPath( QStringLiteral( "/algorithms/mAlgorithmSumLengthLines.svg" ) ); 44 : 0 : } 45 : : 46 : 0 : QIcon QgsSumLineLengthAlgorithm::icon() const 47 : : { 48 : 0 : return QgsApplication::getThemeIcon( QStringLiteral( "/algorithms/mAlgorithmSumLengthLines.svg" ) ); 49 : 0 : } 50 : : 51 : 0 : QString QgsSumLineLengthAlgorithm::group() const 52 : : { 53 : 0 : return QObject::tr( "Vector analysis" ); 54 : : } 55 : : 56 : 0 : QString QgsSumLineLengthAlgorithm::groupId() const 57 : : { 58 : 0 : return QStringLiteral( "vectoranalysis" ); 59 : : } 60 : : 61 : 0 : QString QgsSumLineLengthAlgorithm::shortHelpString() const 62 : : { 63 : 0 : 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 : 0 : QgsSumLineLengthAlgorithm *QgsSumLineLengthAlgorithm::createInstance() const 73 : : { 74 : 0 : return new QgsSumLineLengthAlgorithm(); 75 : 0 : } 76 : : 77 : 0 : QList<int> QgsSumLineLengthAlgorithm::inputLayerTypes() const 78 : : { 79 : 0 : return QList< int >() << QgsProcessing::TypeVectorPolygon; 80 : 0 : } 81 : : 82 : 0 : QgsProcessing::SourceType QgsSumLineLengthAlgorithm::outputLayerType() const 83 : : { 84 : 0 : return QgsProcessing::TypeVectorPolygon; 85 : : } 86 : : 87 : 0 : QgsCoordinateReferenceSystem QgsSumLineLengthAlgorithm::outputCrs( const QgsCoordinateReferenceSystem &inputCrs ) const 88 : : { 89 : 0 : mCrs = inputCrs; 90 : 0 : mDa.setSourceCrs( mCrs, mTransformContext ); 91 : 0 : return mCrs; 92 : : } 93 : : 94 : 0 : QString QgsSumLineLengthAlgorithm::inputParameterName() const 95 : : { 96 : 0 : return QStringLiteral( "POLYGONS" ); 97 : : } 98 : : 99 : 0 : QString QgsSumLineLengthAlgorithm::inputParameterDescription() const 100 : : { 101 : 0 : return QObject::tr( "Polygons" ); 102 : : } 103 : : 104 : 0 : QString QgsSumLineLengthAlgorithm::outputName() const 105 : : { 106 : 0 : return QObject::tr( "Line length" ); 107 : : } 108 : : 109 : 0 : void QgsSumLineLengthAlgorithm::initParameters( const QVariantMap &configuration ) 110 : : { 111 : 0 : mIsInPlace = configuration.value( QStringLiteral( "IN_PLACE" ) ).toBool(); 112 : : 113 : 0 : addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "LINES" ), 114 : 0 : QObject::tr( "Lines" ), QList< int > () << QgsProcessing::TypeVectorLine ) ); 115 : 0 : if ( mIsInPlace ) 116 : : { 117 : 0 : addParameter( new QgsProcessingParameterField( QStringLiteral( "LEN_FIELD" ), 118 : 0 : QObject::tr( "Lines length field name" ), QStringLiteral( "LENGTH" ), inputParameterName(), QgsProcessingParameterField::Any, false, true ) ); 119 : 0 : addParameter( new QgsProcessingParameterField( QStringLiteral( "COUNT_FIELD" ), 120 : 0 : QObject::tr( "Lines count field name" ), QStringLiteral( "COUNT" ), inputParameterName(), QgsProcessingParameterField::Any, false, true ) ); 121 : 0 : } 122 : : else 123 : : { 124 : 0 : addParameter( new QgsProcessingParameterString( QStringLiteral( "LEN_FIELD" ), 125 : 0 : QObject::tr( "Lines length field name" ), QStringLiteral( "LENGTH" ) ) ); 126 : 0 : addParameter( new QgsProcessingParameterString( QStringLiteral( "COUNT_FIELD" ), 127 : 0 : QObject::tr( "Lines count field name" ), QStringLiteral( "COUNT" ) ) ); 128 : : } 129 : 0 : } 130 : : 131 : 0 : bool QgsSumLineLengthAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) 132 : : { 133 : 0 : mLengthFieldName = parameterAsString( parameters, QStringLiteral( "LEN_FIELD" ), context ); 134 : 0 : mCountFieldName = parameterAsString( parameters, QStringLiteral( "COUNT_FIELD" ), context ); 135 : : 136 : 0 : mLinesSource.reset( parameterAsSource( parameters, QStringLiteral( "LINES" ), context ) ); 137 : 0 : if ( !mLinesSource ) 138 : 0 : throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "LINES" ) ) ); 139 : : 140 : 0 : if ( mLinesSource->hasSpatialIndex() == QgsFeatureSource::SpatialIndexNotPresent ) 141 : 0 : feedback->reportError( QObject::tr( "No spatial index exists for lines layer, performance will be severely degraded" ) ); 142 : : 143 : 0 : mDa.setEllipsoid( context.ellipsoid() ); 144 : 0 : mTransformContext = context.transformContext(); 145 : : 146 : 0 : return true; 147 : 0 : } 148 : : 149 : 0 : QgsFields QgsSumLineLengthAlgorithm::outputFields( const QgsFields &inputFields ) const 150 : : { 151 : 0 : if ( mIsInPlace ) 152 : : { 153 : 0 : mLengthFieldIndex = mLengthFieldName.isEmpty() ? -1 : inputFields.lookupField( mLengthFieldName ); 154 : 0 : mCountFieldIndex = mCountFieldName.isEmpty() ? -1 : inputFields.lookupField( mCountFieldName ); 155 : 0 : return inputFields; 156 : : } 157 : : else 158 : : { 159 : 0 : QgsFields outFields = inputFields; 160 : 0 : mLengthFieldIndex = inputFields.lookupField( mLengthFieldName ); 161 : 0 : if ( mLengthFieldIndex < 0 ) 162 : 0 : outFields.append( QgsField( mLengthFieldName, QVariant::Double ) ); 163 : : 164 : 0 : mCountFieldIndex = inputFields.lookupField( mCountFieldName ); 165 : 0 : if ( mCountFieldIndex < 0 ) 166 : 0 : outFields.append( QgsField( mCountFieldName, QVariant::Double ) ); 167 : : 168 : 0 : mFields = outFields; 169 : 0 : return outFields; 170 : 0 : } 171 : 0 : } 172 : : 173 : 0 : bool QgsSumLineLengthAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const 174 : : { 175 : 0 : if ( const QgsVectorLayer *vl = qobject_cast< const QgsVectorLayer * >( layer ) ) 176 : : { 177 : 0 : return vl->geometryType() == QgsWkbTypes::PolygonGeometry; 178 : : } 179 : 0 : return false; 180 : 0 : } 181 : : 182 : 0 : QgsFeatureList QgsSumLineLengthAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) 183 : : { 184 : 0 : QgsFeature outputFeature = feature; 185 : 0 : if ( !feature.hasGeometry() ) 186 : : { 187 : 0 : QgsAttributes attrs = feature.attributes(); 188 : 0 : if ( !mIsInPlace && mLengthFieldIndex < 0 ) 189 : 0 : attrs.append( 0 ); 190 : 0 : else if ( mLengthFieldIndex >= 0 ) 191 : 0 : attrs[mLengthFieldIndex] = 0; 192 : : 193 : 0 : if ( !mIsInPlace && mCountFieldIndex < 0 ) 194 : 0 : attrs.append( 0 ); 195 : 0 : else if ( mCountFieldIndex >= 0 ) 196 : 0 : attrs[mCountFieldIndex] = 0; 197 : : 198 : 0 : outputFeature.setAttributes( attrs ); 199 : 0 : return QList< QgsFeature > () << outputFeature; 200 : 0 : } 201 : : else 202 : : { 203 : 0 : const QgsGeometry polyGeom = feature.geometry(); 204 : 0 : std::unique_ptr< QgsGeometryEngine > engine( QgsGeometry::createGeometryEngine( polyGeom.constGet() ) ); 205 : 0 : engine->prepareGeometry(); 206 : : 207 : 0 : QgsFeatureRequest req = QgsFeatureRequest().setFilterRect( polyGeom.boundingBox() ).setDestinationCrs( mCrs, context.transformContext() ); 208 : 0 : req.setSubsetOfAttributes( QList< int >() ); 209 : 0 : QgsFeatureIterator it = mLinesSource->getFeatures( req ); 210 : : 211 : 0 : double count = 0; 212 : 0 : double length = 0; 213 : : 214 : 0 : QgsFeature lineFeature; 215 : 0 : while ( it.nextFeature( lineFeature ) ) 216 : : { 217 : 0 : if ( feedback->isCanceled() ) 218 : 0 : break; 219 : : 220 : 0 : if ( engine->intersects( lineFeature.geometry().constGet() ) ) 221 : : { 222 : 0 : QgsGeometry outGeom = polyGeom.intersection( lineFeature.geometry() ); 223 : 0 : length += mDa.measureLength( outGeom ); 224 : 0 : count++; 225 : 0 : } 226 : : } 227 : : 228 : 0 : QgsAttributes attrs = feature.attributes(); 229 : 0 : if ( !mIsInPlace && mLengthFieldIndex < 0 ) 230 : 0 : attrs.append( length ); 231 : 0 : else if ( mLengthFieldIndex >= 0 ) 232 : 0 : attrs[mLengthFieldIndex] = length; 233 : : 234 : 0 : if ( !mIsInPlace && mCountFieldIndex < 0 ) 235 : 0 : attrs.append( count ); 236 : 0 : else if ( mCountFieldIndex >= 0 ) 237 : 0 : attrs[mCountFieldIndex] = count; 238 : : 239 : 0 : outputFeature.setAttributes( attrs ); 240 : 0 : return QList< QgsFeature >() << outputFeature; 241 : 0 : } 242 : 0 : } 243 : : 244 : : ///@endcond