QGIS API Documentation 4.3.0-Master (ffcfc20b9b4)
Loading...
Searching...
No Matches
qgsalgorithmbuffer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmbuffer.cpp
3 ---------------------
4 begin : April 2017
5 copyright : (C) 2017 by Nyall Dawson
6 email : nyall dot dawson 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 "qgsalgorithmbuffer.h"
19
20#include "qgsmessagelog.h"
21#include "qgsvectorlayer.h"
22
23#include <QString>
24
25using namespace Qt::StringLiterals;
26
28
29QString QgsBufferAlgorithm::name() const
30{
31 return u"buffer"_s;
32}
33
34QString QgsBufferAlgorithm::displayName() const
35{
36 return QObject::tr( "Buffer" );
37}
38
39QStringList QgsBufferAlgorithm::tags() const
40{
41 return QObject::tr( "buffer,grow,fixed,variable,distance" ).split( ',' );
42}
43
44QString QgsBufferAlgorithm::group() const
45{
46 return QObject::tr( "Vector geometry" );
47}
48
49QString QgsBufferAlgorithm::groupId() const
50{
51 return u"vectorgeometry"_s;
52}
53
54void QgsBufferAlgorithm::initAlgorithm( const QVariantMap & )
55{
56 addParameter( new QgsProcessingParameterFeatureSource( u"INPUT"_s, QObject::tr( "Input layer" ) ) );
57
58 auto bufferParam = std::make_unique<QgsProcessingParameterDistance>( u"DISTANCE"_s, QObject::tr( "Distance" ), 10, u"INPUT"_s );
59 bufferParam->setIsDynamic( true );
60 bufferParam->setDynamicPropertyDefinition( QgsPropertyDefinition( u"Distance"_s, QObject::tr( "Buffer distance" ), QgsPropertyDefinition::Double ) );
61 bufferParam->setDynamicLayerParameterName( u"INPUT"_s );
62 addParameter( bufferParam.release() );
63 auto segmentParam = std::make_unique<QgsProcessingParameterNumber>( u"SEGMENTS"_s, QObject::tr( "Segments" ), Qgis::ProcessingNumberParameterType::Integer, 5, false, 1 );
64 segmentParam->setHelp( QObject::tr( "The segments parameter controls the number of line segments to use to approximate a quarter circle when creating rounded offsets." ) );
65 addParameter( segmentParam.release() );
66 addParameter(
67 new QgsProcessingParameterEnum( u"END_CAP_STYLE"_s, QObject::tr( "End cap style" ), QStringList() << QObject::tr( "Round" ) << QObject::tr( "Flat" ) << QObject::tr( "Square" ), false, 0 )
68 );
69 addParameter( new QgsProcessingParameterEnum( u"JOIN_STYLE"_s, QObject::tr( "Join style" ), QStringList() << QObject::tr( "Round" ) << QObject::tr( "Miter" ) << QObject::tr( "Bevel" ), false, 0 ) );
70 addParameter( new QgsProcessingParameterNumber( u"MITER_LIMIT"_s, QObject::tr( "Miter limit" ), Qgis::ProcessingNumberParameterType::Double, 2, false, 1 ) );
71
72 addParameter( new QgsProcessingParameterBoolean( u"DISSOLVE"_s, QObject::tr( "Dissolve result" ), false ) );
73
74 auto keepDisjointParam = std::make_unique<QgsProcessingParameterBoolean>( u"SEPARATE_DISJOINT"_s, QObject::tr( "Keep disjoint results separate" ), false );
75 keepDisjointParam->setFlags( keepDisjointParam->flags() | Qgis::ProcessingParameterFlag::Advanced );
76 keepDisjointParam->setHelp( QObject::tr( "If checked, then any disjoint parts in the buffer results will be output as separate single-part features." ) );
77 addParameter( keepDisjointParam.release() );
78
79 addParameter( new QgsProcessingParameterFeatureSink( u"OUTPUT"_s, QObject::tr( "Buffered" ), Qgis::ProcessingSourceType::VectorPolygon, QVariant(), false, true, true ) );
80}
81
82QString QgsBufferAlgorithm::shortHelpString() const
83{
84 return QObject::tr(
85 "This algorithm computes a buffer area for all the features in an input layer, using a fixed or dynamic distance.\n\n"
86 "The segments parameter controls the number of line segments to use to approximate a quarter circle when creating rounded offsets.\n\n"
87 "The end cap style parameter controls how line endings are handled in the buffer.\n\n"
88 "The join style parameter specifies whether round, miter or beveled joins should be used when offsetting corners in a line.\n\n"
89 "The miter limit parameter is only applicable for miter join styles, and controls the maximum distance from the offset curve to use when creating a mitered join."
90 );
91}
92
93QString QgsBufferAlgorithm::shortDescription() const
94{
95 return QObject::tr( "Computes a buffer area for all the features in an input layer, using a fixed or dynamic distance." );
96}
97
98Qgis::ProcessingAlgorithmDocumentationFlags QgsBufferAlgorithm::documentationFlags() const
99{
101}
102
103QgsBufferAlgorithm *QgsBufferAlgorithm::createInstance() const
104{
105 return new QgsBufferAlgorithm();
106}
107
108QVariantMap QgsBufferAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
109{
110 QGS_MARK_ALGORITHM_SOURCE
111
112 std::unique_ptr<QgsProcessingFeatureSource> source( parameterAsSource( parameters, u"INPUT"_s, context ) );
113 if ( !source )
114 throw QgsProcessingException( invalidSourceError( parameters, u"INPUT"_s ) );
115
116 // fixed parameters
117 const bool dissolve = parameterAsBoolean( parameters, u"DISSOLVE"_s, context );
118 const bool keepDisjointSeparate = parameterAsBoolean( parameters, u"SEPARATE_DISJOINT"_s, context );
119 const int segments = parameterAsInt( parameters, u"SEGMENTS"_s, context );
120 const Qgis::EndCapStyle endCapStyle = static_cast<Qgis::EndCapStyle>( 1 + parameterAsInt( parameters, u"END_CAP_STYLE"_s, context ) );
121 const Qgis::JoinStyle joinStyle = static_cast<Qgis::JoinStyle>( 1 + parameterAsInt( parameters, u"JOIN_STYLE"_s, context ) );
122 const double miterLimit = parameterAsDouble( parameters, u"MITER_LIMIT"_s, context );
123 const double bufferDistance = parameterAsDouble( parameters, u"DISTANCE"_s, context );
124 const bool dynamicBuffer = QgsProcessingParameters::isDynamic( parameters, u"DISTANCE"_s );
125
126 QString dest;
127 std::unique_ptr<QgsFeatureSink> sink(
128 parameterAsSink( parameters, u"OUTPUT"_s, context, dest, source->fields(), Qgis::WkbType::MultiPolygon, source->sourceCrs(), keepDisjointSeparate ? QgsFeatureSink::RegeneratePrimaryKey : QgsFeatureSink::SinkFlags() )
129 );
130 if ( !sink )
131 throw QgsProcessingException( invalidSinkError( parameters, u"OUTPUT"_s ) );
132
133 QgsExpressionContext expressionContext = createExpressionContext( parameters, context, source.get() );
134 QgsProperty bufferProperty;
135 if ( dynamicBuffer )
136 {
137 bufferProperty = parameters.value( u"DISTANCE"_s ).value<QgsProperty>();
138 }
139
140 const long count = source->featureCount();
141
142 QgsFeature f;
143 // buffer doesn't care about invalid features, and buffering can be used to repair geometries
145
146 const double step = count > 0 ? 100.0 / count : 1;
147 int current = 0;
148
149 QVector<QgsGeometry> bufferedGeometriesForDissolve;
150 QgsAttributes dissolveAttrs;
151
152 while ( it.nextFeature( f ) )
153 {
154 if ( feedback->isCanceled() )
155 {
156 break;
157 }
158 if ( dissolveAttrs.isEmpty() )
159 dissolveAttrs = f.attributes();
160
161 QgsFeature out = f;
162 if ( out.hasGeometry() )
163 {
164 double distance = bufferDistance;
165 if ( dynamicBuffer )
166 {
167 expressionContext.setFeature( f );
168 distance = bufferProperty.valueAsDouble( expressionContext, bufferDistance );
169 }
170
171 QgsGeometry outputGeometry = f.geometry().buffer( distance, segments, endCapStyle, joinStyle, miterLimit, feedback );
172 if ( outputGeometry.isNull() )
173 {
174 QgsMessageLog::logMessage( QObject::tr( "Error calculating buffer for feature %1" ).arg( f.id() ), QObject::tr( "Processing" ), Qgis::MessageLevel::Warning );
175 }
176 if ( dissolve )
177 {
178 bufferedGeometriesForDissolve << outputGeometry;
179 }
180 else
181 {
182 outputGeometry.convertToMultiType();
183
184 if ( !keepDisjointSeparate )
185 {
186 out.setGeometry( outputGeometry );
187
188 if ( !sink->addFeature( out, QgsFeatureSink::FastInsert ) )
189 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, u"OUTPUT"_s ) );
190 else
191 feedback->featureAddedToSink( u"OUTPUT"_s );
192 }
193 else
194 {
195 for ( auto partIt = outputGeometry.const_parts_begin(); partIt != outputGeometry.const_parts_end(); ++partIt )
196 {
197 if ( const QgsAbstractGeometry *part = *partIt )
198 {
199 out.setGeometry( QgsGeometry( part->clone() ) );
200 if ( !sink->addFeature( out, QgsFeatureSink::FastInsert ) )
201 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, u"OUTPUT"_s ) );
202 else
203 feedback->featureAddedToSink( u"OUTPUT"_s );
204 }
205 }
206 }
207 }
208 }
209 else if ( !dissolve )
210 {
211 if ( !sink->addFeature( out, QgsFeatureSink::FastInsert ) )
212 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, u"OUTPUT"_s ) );
213 else
214 feedback->featureAddedToSink( u"OUTPUT"_s );
215 }
216
217 feedback->setProgress( current * step );
218 current++;
219 }
220
221 if ( dissolve && !bufferedGeometriesForDissolve.isEmpty() )
222 {
223 QgsGeometry finalGeometry = QgsGeometry::unaryUnion( bufferedGeometriesForDissolve, QgsGeometryParameters(), feedback );
224 finalGeometry.convertToMultiType();
225 QgsFeature f;
226 f.setAttributes( dissolveAttrs );
227
228 if ( !keepDisjointSeparate )
229 {
230 f.setGeometry( finalGeometry );
231 if ( !sink->addFeature( f, QgsFeatureSink::FastInsert ) )
232 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, u"OUTPUT"_s ) );
233 else
234 feedback->featureAddedToSink( u"OUTPUT"_s );
235 }
236 else
237 {
238 for ( auto partIt = finalGeometry.const_parts_begin(); partIt != finalGeometry.const_parts_end(); ++partIt )
239 {
240 if ( const QgsAbstractGeometry *part = *partIt )
241 {
242 f.setGeometry( QgsGeometry( part->clone() ) );
243 if ( !sink->addFeature( f, QgsFeatureSink::FastInsert ) )
244 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, u"OUTPUT"_s ) );
245 else
246 feedback->featureAddedToSink( u"OUTPUT"_s );
247 }
248 }
249 }
250 }
251
252 sink->finalize();
253 feedback->featureSinkFinalized( u"OUTPUT"_s );
254
255 QVariantMap outputs;
256 outputs.insert( u"OUTPUT"_s, dest );
257 return outputs;
258}
259
260Qgis::ProcessingAlgorithmFlags QgsBufferAlgorithm::flags() const
261{
264 return f;
265}
266
267QgsProcessingAlgorithm::VectorProperties QgsBufferAlgorithm::sinkProperties(
268 const QString &sink, const QVariantMap &parameters, QgsProcessingContext &context, const QMap<QString, QgsProcessingAlgorithm::VectorProperties> &sourceProperties
269) const
270{
271 const bool keepDisjointSeparate = parameterAsBoolean( parameters, u"SEPARATE_DISJOINT"_s, context );
272
274 if ( sink == "OUTPUT"_L1 )
275 {
276 if ( sourceProperties.value( u"INPUT"_s ).availability == Qgis::ProcessingPropertyAvailability::Available )
277 {
278 const VectorProperties inputProps = sourceProperties.value( u"INPUT"_s );
279 result.fields = inputProps.fields;
280 result.crs = inputProps.crs;
281 result.wkbType = keepDisjointSeparate ? Qgis::WkbType::Polygon : Qgis::WkbType::MultiPolygon;
283 return result;
284 }
285 else
286 {
287 std::unique_ptr<QgsProcessingFeatureSource> source( parameterAsSource( parameters, u"INPUT"_s, context ) );
288 if ( source )
289 {
290 result.fields = source->fields();
291 result.crs = source->sourceCrs();
292 result.wkbType = keepDisjointSeparate ? Qgis::WkbType::Polygon : Qgis::WkbType::MultiPolygon;
294 return result;
295 }
296 }
297 }
298 return result;
299}
300
301bool QgsBufferAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const
302{
303 const QgsVectorLayer *vlayer = qobject_cast<const QgsVectorLayer *>( layer );
304 if ( !vlayer )
305 return false;
306 //Only Polygons
307 return vlayer->wkbType() == Qgis::WkbType::Polygon || vlayer->wkbType() == Qgis::WkbType::MultiPolygon;
308}
309
@ VectorPolygon
Vector polygon layers.
Definition qgis.h:3752
@ Warning
Warning message.
Definition qgis.h:162
@ Available
Properties are available.
Definition qgis.h:3861
JoinStyle
Join styles for buffers.
Definition qgis.h:2273
@ RegeneratesPrimaryKeyInSomeScenarios
Algorithm may drop the existing primary keys or FID values in some scenarios, depending on algorithm ...
Definition qgis.h:3837
QFlags< ProcessingAlgorithmFlag > ProcessingAlgorithmFlags
Flags indicating how and when an algorithm operates and should be exposed to users.
Definition qgis.h:3826
EndCapStyle
End cap styles for buffers.
Definition qgis.h:2260
QFlags< ProcessingAlgorithmDocumentationFlag > ProcessingAlgorithmDocumentationFlags
Flags describing algorithm behavior for documentation purposes.
Definition qgis.h:3847
@ SkipGeometryValidityChecks
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
Definition qgis.h:3930
@ Polygon
Polygon.
Definition qgis.h:298
@ MultiPolygon
MultiPolygon.
Definition qgis.h:302
@ SupportsInPlaceEdits
Algorithm supports in-place editing.
Definition qgis.h:3807
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
Definition qgis.h:3982
@ Double
Double/float values.
Definition qgis.h:4023
Abstract base class for all geometries.
A vector of attributes.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
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).
QFlags< SinkFlag > SinkFlags
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
@ RegeneratePrimaryKey
This flag indicates, that a primary key field cannot be guaranteed to be unique and the sink should i...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:60
QgsAttributes attributes
Definition qgsfeature.h:64
QgsFeatureId id
Definition qgsfeature.h:63
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
QgsGeometry geometry
Definition qgsfeature.h:66
bool hasGeometry() const
Returns true if the feature has an associated geometry.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:56
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:65
Encapsulates parameters under which a geometry operation is performed.
A geometry is the spatial representation of a feature.
QgsAbstractGeometry::const_part_iterator const_parts_begin() const
Returns STL-style const iterator pointing to the first part of the geometry.
static QgsGeometry unaryUnion(const QVector< QgsGeometry > &geometries, const QgsGeometryParameters &parameters=QgsGeometryParameters(), QgsFeedback *feedback=nullptr)
Compute the unary union on a list of geometries.
QgsGeometry buffer(double distance, int segments, QgsFeedback *feedback=nullptr) const
Returns a buffer region around this geometry having the given width and with a specified number of se...
QgsAbstractGeometry::const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry.
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
Base class for all map layer types.
Definition qgsmaplayer.h:83
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
virtual Qgis::ProcessingAlgorithmFlags flags() const
Returns the flags indicating how and when the algorithm operates and should be exposed to users.
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
void featureAddedToSink(const QString &output)
Reports that a feature was added to the the sink associated with the specified algorithm output.
void featureSinkFinalized(const QString &output)
Reports that a feature sink has been finalized.
A boolean parameter for processing algorithms.
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 bool isDynamic(const QVariantMap &parameters, const QString &name)
Returns true if the parameter with matching name is a dynamic parameter, and must be evaluated once f...
Definition for a property.
Definition qgsproperty.h:47
@ Double
Double value (including negative values).
Definition qgsproperty.h:56
A store for object properties.
QVariant value(const QgsExpressionContext &context, const QVariant &defaultValue=QVariant(), bool *ok=nullptr) const
Calculates the current value of the property, including any transforms which are set for the property...
double valueAsDouble(const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property and interprets it as a double.
Represents a vector layer which manages a vector based dataset.
Q_INVOKABLE Qgis::WkbType wkbType() const final
Returns the WKBType or WKBUnknown in case of error.
Properties of a vector source or sink used in an algorithm.
Qgis::WkbType wkbType
Geometry (WKB) type.
QgsCoordinateReferenceSystem crs
Coordinate Reference System.
Qgis::ProcessingPropertyAvailability availability
Availability of the properties. By default properties are not available.