QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
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#include "qgswkbtypes.h"
20#include "qgsvectorlayer.h"
21
23
24QString QgsBufferAlgorithm::name() const
25{
26 return QStringLiteral( "buffer" );
27}
28
29QString QgsBufferAlgorithm::displayName() const
30{
31 return QObject::tr( "Buffer" );
32}
33
34QStringList QgsBufferAlgorithm::tags() const
35{
36 return QObject::tr( "buffer,grow,fixed,variable,distance" ).split( ',' );
37}
38
39QString QgsBufferAlgorithm::group() const
40{
41 return QObject::tr( "Vector geometry" );
42}
43
44QString QgsBufferAlgorithm::groupId() const
45{
46 return QStringLiteral( "vectorgeometry" );
47}
48
49void QgsBufferAlgorithm::initAlgorithm( const QVariantMap & )
50{
51 addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
52
53 auto bufferParam = std::make_unique < QgsProcessingParameterDistance >( QStringLiteral( "DISTANCE" ), QObject::tr( "Distance" ), 10, QStringLiteral( "INPUT" ) );
54 bufferParam->setIsDynamic( true );
55 bufferParam->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "Distance" ), QObject::tr( "Buffer distance" ), QgsPropertyDefinition::Double ) );
56 bufferParam->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
57 addParameter( bufferParam.release() );
58 auto segmentParam = std::make_unique < QgsProcessingParameterNumber >( QStringLiteral( "SEGMENTS" ), QObject::tr( "Segments" ), QgsProcessingParameterNumber::Integer, 5, false, 1 );
59 segmentParam->setHelp( QObject::tr( "The segments parameter controls the number of line segments to use to approximate a quarter circle when creating rounded offsets." ) );
60 addParameter( segmentParam.release() );
61 addParameter( new QgsProcessingParameterEnum( QStringLiteral( "END_CAP_STYLE" ), QObject::tr( "End cap style" ), QStringList() << QObject::tr( "Round" ) << QObject::tr( "Flat" ) << QObject::tr( "Square" ), false, 0 ) );
62 addParameter( new QgsProcessingParameterEnum( QStringLiteral( "JOIN_STYLE" ), QObject::tr( "Join style" ), QStringList() << QObject::tr( "Round" ) << QObject::tr( "Miter" ) << QObject::tr( "Bevel" ), false, 0 ) );
63 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "MITER_LIMIT" ), QObject::tr( "Miter limit" ), QgsProcessingParameterNumber::Double, 2, false, 1 ) );
64
65 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "DISSOLVE" ), QObject::tr( "Dissolve result" ), false ) );
66 addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Buffered" ), QgsProcessing::TypeVectorPolygon, QVariant(), false, true, true ) );
67}
68
69QString QgsBufferAlgorithm::shortHelpString() const
70{
71 return QObject::tr( "This algorithm computes a buffer area for all the features in an input layer, using a fixed or dynamic distance.\n\n"
72 "The segments parameter controls the number of line segments to use to approximate a quarter circle when creating rounded offsets.\n\n"
73 "The end cap style parameter controls how line endings are handled in the buffer.\n\n"
74 "The join style parameter specifies whether round, miter or beveled joins should be used when offsetting corners in a line.\n\n"
75 "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." );
76}
77
78QgsBufferAlgorithm *QgsBufferAlgorithm::createInstance() const
79{
80 return new QgsBufferAlgorithm();
81}
82
83QVariantMap QgsBufferAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
84{
85 std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
86 if ( !source )
87 throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
88
89 QString dest;
90 std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(), Qgis::WkbType::MultiPolygon, source->sourceCrs() ) );
91 if ( !sink )
92 throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
93
94 // fixed parameters
95 const bool dissolve = parameterAsBoolean( parameters, QStringLiteral( "DISSOLVE" ), context );
96 const int segments = parameterAsInt( parameters, QStringLiteral( "SEGMENTS" ), context );
97 const Qgis::EndCapStyle endCapStyle = static_cast< Qgis::EndCapStyle >( 1 + parameterAsInt( parameters, QStringLiteral( "END_CAP_STYLE" ), context ) );
98 const Qgis::JoinStyle joinStyle = static_cast< Qgis::JoinStyle>( 1 + parameterAsInt( parameters, QStringLiteral( "JOIN_STYLE" ), context ) );
99 const double miterLimit = parameterAsDouble( parameters, QStringLiteral( "MITER_LIMIT" ), context );
100 const double bufferDistance = parameterAsDouble( parameters, QStringLiteral( "DISTANCE" ), context );
101 const bool dynamicBuffer = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DISTANCE" ) );
102 QgsExpressionContext expressionContext = createExpressionContext( parameters, context, source.get() );
103 QgsProperty bufferProperty;
104 if ( dynamicBuffer )
105 {
106 bufferProperty = parameters.value( QStringLiteral( "DISTANCE" ) ).value< QgsProperty >();
107 }
108
109 const long count = source->featureCount();
110
111 QgsFeature f;
112 // buffer doesn't care about invalid features, and buffering can be used to repair geometries
114
115 const double step = count > 0 ? 100.0 / count : 1;
116 int current = 0;
117
118 QVector< QgsGeometry > bufferedGeometriesForDissolve;
119 QgsAttributes dissolveAttrs;
120
121 while ( it.nextFeature( f ) )
122 {
123 if ( feedback->isCanceled() )
124 {
125 break;
126 }
127 if ( dissolveAttrs.isEmpty() )
128 dissolveAttrs = f.attributes();
129
130 QgsFeature out = f;
131 if ( out.hasGeometry() )
132 {
133 double distance = bufferDistance;
134 if ( dynamicBuffer )
135 {
136 expressionContext.setFeature( f );
137 distance = bufferProperty.valueAsDouble( expressionContext, bufferDistance );
138 }
139
140 QgsGeometry outputGeometry = f.geometry().buffer( distance, segments, endCapStyle, joinStyle, miterLimit );
141 if ( outputGeometry.isNull() )
142 {
143 QgsMessageLog::logMessage( QObject::tr( "Error calculating buffer for feature %1" ).arg( f.id() ), QObject::tr( "Processing" ), Qgis::MessageLevel::Warning );
144 }
145 if ( dissolve )
146 bufferedGeometriesForDissolve << outputGeometry;
147 else
148 {
149 outputGeometry.convertToMultiType();
150 out.setGeometry( outputGeometry );
151 }
152 }
153
154 if ( !dissolve )
155 {
156 if ( !sink->addFeature( out, QgsFeatureSink::FastInsert ) )
157 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
158 }
159
160 feedback->setProgress( current * step );
161 current++;
162 }
163
164 if ( dissolve && !bufferedGeometriesForDissolve.isEmpty() )
165 {
166 QgsGeometry finalGeometry = QgsGeometry::unaryUnion( bufferedGeometriesForDissolve );
167 finalGeometry.convertToMultiType();
168 QgsFeature f;
169 f.setGeometry( finalGeometry );
170 f.setAttributes( dissolveAttrs );
171 if ( !sink->addFeature( f, QgsFeatureSink::FastInsert ) )
172 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
173 }
174
175 QVariantMap outputs;
176 outputs.insert( QStringLiteral( "OUTPUT" ), dest );
177 return outputs;
178}
179
180QgsProcessingAlgorithm::Flags QgsBufferAlgorithm::flags() const
181{
184 return f;
185}
186
187QgsProcessingAlgorithm::VectorProperties QgsBufferAlgorithm::sinkProperties( const QString &sink, const QVariantMap &parameters, QgsProcessingContext &context, const QMap<QString, QgsProcessingAlgorithm::VectorProperties> &sourceProperties ) const
188{
190 if ( sink == QLatin1String( "OUTPUT" ) )
191 {
192 if ( sourceProperties.value( QStringLiteral( "INPUT" ) ).availability == QgsProcessingAlgorithm::Available )
193 {
194 const VectorProperties inputProps = sourceProperties.value( QStringLiteral( "INPUT" ) );
195 result.fields = inputProps.fields;
196 result.crs = inputProps.crs;
198 result.availability = Available;
199 return result;
200 }
201 else
202 {
203 std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
204 if ( source )
205 {
206 result.fields = source->fields();
207 result.crs = source->sourceCrs();
209 result.availability = Available;
210 return result;
211 }
212 }
213 }
214 return result;
215}
216
217bool QgsBufferAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const
218{
219 const QgsVectorLayer *vlayer = qobject_cast< const QgsVectorLayer * >( layer );
220 if ( !vlayer )
221 return false;
222 //Only Polygons
223 return vlayer->wkbType() == Qgis::WkbType::Polygon || vlayer->wkbType() == Qgis::WkbType::MultiPolygon;
224}
225
JoinStyle
Join styles for buffers.
Definition: qgis.h:1344
EndCapStyle
End cap styles for buffers.
Definition: qgis.h:1331
@ Polygon
Polygon.
@ MultiPolygon
MultiPolygon.
A vector of attributes.
Definition: qgsattributes.h:59
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)
This class wraps a request for features to a vector layer (or directly its vector data provider).
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
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:160
QgsGeometry geometry
Definition: qgsfeature.h:67
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:233
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:170
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:63
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:164
Q_GADGET bool isNull
Definition: qgsgeometry.h:166
QgsGeometry buffer(double distance, int segments) const
Returns a buffer region around this geometry having the given width and with a specified number of se...
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
static QgsGeometry unaryUnion(const QVector< QgsGeometry > &geometries, const QgsGeometryParameters &parameters=QgsGeometryParameters())
Compute the unary union on a list of geometries.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
@ Available
Properties are available.
virtual Flags flags() const
Returns the flags indicating how and when the algorithm operates and should be exposed to users.
@ FlagSupportsInPlaceEdits
Algorithm supports in-place editing.
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
Definition: qgsexception.h:83
@ FlagSkipGeometryValidityChecks
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
Base class for providing feedback from a processing algorithm.
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...
@ TypeVectorPolygon
Vector polygon layers.
Definition: qgsprocessing.h:52
Definition for a property.
Definition: qgsproperty.h:46
@ Double
Double value (including negative values)
Definition: qgsproperty.h:56
A store for object properties.
Definition: qgsproperty.h:230
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 data sets.
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.
QgsProcessingAlgorithm::PropertyAvailability availability
Availability of the properties. By default properties are not available.