Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsalgorithmnultitingconstantbuffer.cpp 3 : : -------------------------- 4 : : begin : February 2018 5 : : copyright : (C) 2018 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 "qgsalgorithmmultiringconstantbuffer.h" 19 : : #include "qgsvectorlayer.h" 20 : : 21 : : ///@cond PRIVATE 22 : : 23 : 0 : QString QgsMultiRingConstantBufferAlgorithm::name() const 24 : : { 25 : 0 : return QStringLiteral( "multiringconstantbuffer" ); 26 : : } 27 : : 28 : 0 : QString QgsMultiRingConstantBufferAlgorithm::displayName() const 29 : : { 30 : 0 : return QObject::tr( "Multi-ring buffer (constant distance)" ); 31 : : } 32 : : 33 : 0 : QStringList QgsMultiRingConstantBufferAlgorithm::tags() const 34 : : { 35 : 0 : return QObject::tr( "buffer,grow,multiple,rings,distance,donut" ).split( ',' ); 36 : 0 : } 37 : : 38 : 0 : QString QgsMultiRingConstantBufferAlgorithm::group() const 39 : : { 40 : 0 : return QObject::tr( "Vector geometry" ); 41 : : } 42 : : 43 : 0 : QString QgsMultiRingConstantBufferAlgorithm::groupId() const 44 : : { 45 : 0 : return QStringLiteral( "vectorgeometry" ); 46 : : } 47 : : 48 : 0 : QString QgsMultiRingConstantBufferAlgorithm::outputName() const 49 : : { 50 : 0 : return QObject::tr( "Multi-ring buffer (constant distance)" ); 51 : : } 52 : : 53 : 0 : QString QgsMultiRingConstantBufferAlgorithm::shortHelpString() const 54 : : { 55 : 0 : return QObject::tr( "This algorithm computes multi-ring ('donuts') buffer for all the features in an input layer, using a fixed or dynamic distance and rings number." ); 56 : : } 57 : : 58 : 0 : QgsMultiRingConstantBufferAlgorithm *QgsMultiRingConstantBufferAlgorithm::createInstance() const 59 : : { 60 : 0 : return new QgsMultiRingConstantBufferAlgorithm(); 61 : 0 : } 62 : : 63 : 0 : void QgsMultiRingConstantBufferAlgorithm::initParameters( const QVariantMap & ) 64 : : { 65 : 0 : std::unique_ptr< QgsProcessingParameterNumber> rings = std::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "RINGS" ), 66 : 0 : QObject::tr( "Number of rings" ), QgsProcessingParameterNumber::Integer, 67 : 0 : 1, false, 0 ); 68 : 0 : rings->setIsDynamic( true ); 69 : 0 : rings->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "RINGS" ), QObject::tr( "Number of rings" ), QgsPropertyDefinition::IntegerPositive ) ); 70 : 0 : rings->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) ); 71 : 0 : addParameter( rings.release() ); 72 : : 73 : 0 : std::unique_ptr< QgsProcessingParameterDistance > distance = std::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "DISTANCE" ), 74 : 0 : QObject::tr( "Distance between rings" ), 1, QStringLiteral( "INPUT" ), false ); 75 : 0 : distance->setIsDynamic( true ); 76 : 0 : distance->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DISTANCE" ), QObject::tr( "Distance between rings" ), QgsPropertyDefinition::DoublePositive ) ); 77 : 0 : distance->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) ); 78 : 0 : addParameter( distance.release() ); 79 : 0 : } 80 : : 81 : 0 : bool QgsMultiRingConstantBufferAlgorithm::supportInPlaceEdit( const QgsMapLayer *l ) const 82 : : { 83 : 0 : const QgsVectorLayer *layer = qobject_cast< const QgsVectorLayer * >( l ); 84 : 0 : if ( !layer ) 85 : 0 : return false; 86 : : 87 : 0 : if ( ! QgsProcessingFeatureBasedAlgorithm::supportInPlaceEdit( layer ) ) 88 : 0 : return false; 89 : : // Polygons only 90 : 0 : return layer->wkbType() == QgsWkbTypes::Type::Polygon || layer->wkbType() == QgsWkbTypes::Type::MultiPolygon; 91 : 0 : } 92 : : 93 : 0 : bool QgsMultiRingConstantBufferAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * ) 94 : : { 95 : 0 : mRingsNumber = parameterAsInt( parameters, QStringLiteral( "RINGS" ), context ); 96 : 0 : mDynamicRingsNumber = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "RINGS" ) ); 97 : 0 : if ( mDynamicRingsNumber ) 98 : 0 : mRingsNumberProperty = parameters.value( QStringLiteral( "RINGS" ) ).value< QgsProperty >(); 99 : : 100 : 0 : mDistance = parameterAsDouble( parameters, QStringLiteral( "DISTANCE" ), context ); 101 : 0 : mDynamicDistance = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DISTANCE" ) ); 102 : 0 : if ( mDynamicDistance ) 103 : 0 : mDistanceProperty = parameters.value( QStringLiteral( "DISTANCE" ) ).value< QgsProperty >(); 104 : : 105 : 0 : return true; 106 : 0 : } 107 : : 108 : 0 : QgsFields QgsMultiRingConstantBufferAlgorithm::outputFields( const QgsFields &inputFields ) const 109 : : { 110 : 0 : QgsFields fields = inputFields; 111 : 0 : fields.append( QgsField( QStringLiteral( "ringId" ), QVariant::Int, QString(), 10, 0 ) ); 112 : 0 : fields.append( QgsField( QStringLiteral( "distance" ), QVariant::Double, QString(), 20, 6 ) ); 113 : 0 : return fields; 114 : 0 : } 115 : : 116 : 0 : QgsProcessingFeatureSource::Flag QgsMultiRingConstantBufferAlgorithm::sourceFlags() const 117 : : { 118 : 0 : return QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks; 119 : : } 120 : : 121 : 0 : QgsFeatureSink::SinkFlags QgsMultiRingConstantBufferAlgorithm::sinkFlags() const 122 : : { 123 : 0 : return QgsFeatureSink::RegeneratePrimaryKey; 124 : : } 125 : : 126 : 0 : QgsFeatureList QgsMultiRingConstantBufferAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) 127 : : { 128 : 0 : double currentDistance = 0; 129 : 0 : QgsGeometry outputGeometry, previousGeometry; 130 : : 131 : 0 : int rings = mRingsNumber; 132 : 0 : if ( mDynamicRingsNumber ) 133 : 0 : rings = mRingsNumberProperty.valueAsInt( context.expressionContext(), rings ); 134 : : 135 : 0 : double distance = mDistance; 136 : 0 : if ( mDynamicDistance ) 137 : 0 : distance = mDistanceProperty.valueAsDouble( context.expressionContext(), distance ); 138 : : 139 : 0 : QgsFeatureList outputs; 140 : : 141 : : // Set previous geometry to a zero-distance buffer of the original geometry, 142 : : // this is needed for negative distance values 143 : 0 : previousGeometry = feature.geometry().buffer( 0.0, 40 ); 144 : 0 : previousGeometry.convertToMultiType(); 145 : : 146 : 0 : for ( int i = 1; i <= rings; ++i ) 147 : : { 148 : 0 : QgsFeature out; 149 : 0 : currentDistance = i * distance; 150 : 0 : outputGeometry = feature.geometry().buffer( currentDistance, 40 ); 151 : 0 : outputGeometry.convertToMultiType(); 152 : 0 : if ( outputGeometry.isNull() ) 153 : : { 154 : 0 : feedback->reportError( QObject::tr( "Error calculating buffer for feature %1" ).arg( feature.id() ) ); 155 : 0 : continue; 156 : : } 157 : : 158 : 0 : if ( distance < 0.0 ) 159 : : { 160 : 0 : out.setGeometry( previousGeometry.symDifference( outputGeometry ) ); 161 : 0 : } 162 : 0 : else if ( i == 1 ) 163 : : { 164 : 0 : out.setGeometry( outputGeometry ); 165 : 0 : } 166 : : else 167 : : { 168 : 0 : out.setGeometry( outputGeometry.symDifference( previousGeometry ) ); 169 : : } 170 : 0 : previousGeometry = outputGeometry; 171 : 0 : QgsAttributes attrs = feature.attributes(); 172 : 0 : attrs << i << currentDistance; 173 : 0 : out.setAttributes( attrs ); 174 : 0 : outputs.append( out ); 175 : 0 : } 176 : : 177 : : // For negative distance values, the last generated buffer geometry needs to be added 178 : 0 : if ( distance < 0.0 ) 179 : : { 180 : 0 : QgsFeature out; 181 : 0 : out.setGeometry( previousGeometry ); 182 : 0 : QgsAttributes attrs = feature.attributes(); 183 : 0 : attrs << 0 << 0.0; 184 : 0 : out.setAttributes( attrs ); 185 : 0 : outputs.append( out ); 186 : 0 : } 187 : : 188 : 0 : return outputs; 189 : 0 : } 190 : : 191 : : ///@endcond