QGIS API Documentation 3.34.0-Prizren (ffbdd678812)
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#include "qgsvectorlayer.h"
20
22
23QString QgsBufferAlgorithm::name() const
24{
25 return QStringLiteral( "buffer" );
26}
27
28QString QgsBufferAlgorithm::displayName() const
29{
30 return QObject::tr( "Buffer" );
31}
32
33QStringList QgsBufferAlgorithm::tags() const
34{
35 return QObject::tr( "buffer,grow,fixed,variable,distance" ).split( ',' );
36}
37
38QString QgsBufferAlgorithm::group() const
39{
40 return QObject::tr( "Vector geometry" );
41}
42
43QString QgsBufferAlgorithm::groupId() const
44{
45 return QStringLiteral( "vectorgeometry" );
46}
47
48void QgsBufferAlgorithm::initAlgorithm( const QVariantMap & )
49{
50 addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
51
52 auto bufferParam = std::make_unique < QgsProcessingParameterDistance >( QStringLiteral( "DISTANCE" ), QObject::tr( "Distance" ), 10, QStringLiteral( "INPUT" ) );
53 bufferParam->setIsDynamic( true );
54 bufferParam->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "Distance" ), QObject::tr( "Buffer distance" ), QgsPropertyDefinition::Double ) );
55 bufferParam->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
56 addParameter( bufferParam.release() );
57 auto segmentParam = std::make_unique < QgsProcessingParameterNumber >( QStringLiteral( "SEGMENTS" ), QObject::tr( "Segments" ), QgsProcessingParameterNumber::Integer, 5, false, 1 );
58 segmentParam->setHelp( QObject::tr( "The segments parameter controls the number of line segments to use to approximate a quarter circle when creating rounded offsets." ) );
59 addParameter( segmentParam.release() );
60 addParameter( new QgsProcessingParameterEnum( QStringLiteral( "END_CAP_STYLE" ), QObject::tr( "End cap style" ), QStringList() << QObject::tr( "Round" ) << QObject::tr( "Flat" ) << QObject::tr( "Square" ), false, 0 ) );
61 addParameter( new QgsProcessingParameterEnum( QStringLiteral( "JOIN_STYLE" ), QObject::tr( "Join style" ), QStringList() << QObject::tr( "Round" ) << QObject::tr( "Miter" ) << QObject::tr( "Bevel" ), false, 0 ) );
62 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "MITER_LIMIT" ), QObject::tr( "Miter limit" ), QgsProcessingParameterNumber::Double, 2, false, 1 ) );
63
64 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "DISSOLVE" ), QObject::tr( "Dissolve result" ), false ) );
65
66 auto keepDisjointParam = std::make_unique < QgsProcessingParameterBoolean >( QStringLiteral( "SEPARATE_DISJOINT" ), QObject::tr( "Keep disjoint results separate" ), false );
67 keepDisjointParam->setFlags( keepDisjointParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
68 keepDisjointParam->setHelp( QObject::tr( "If checked, then any disjoint parts in the buffer results will be output as separate single-part features." ) );
69 addParameter( keepDisjointParam.release() );
70
71 addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Buffered" ), QgsProcessing::TypeVectorPolygon, QVariant(), false, true, true ) );
72}
73
74QString QgsBufferAlgorithm::shortHelpString() const
75{
76 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"
77 "The segments parameter controls the number of line segments to use to approximate a quarter circle when creating rounded offsets.\n\n"
78 "The end cap style parameter controls how line endings are handled in the buffer.\n\n"
79 "The join style parameter specifies whether round, miter or beveled joins should be used when offsetting corners in a line.\n\n"
80 "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." );
81}
82
83QgsBufferAlgorithm *QgsBufferAlgorithm::createInstance() const
84{
85 return new QgsBufferAlgorithm();
86}
87
88QVariantMap QgsBufferAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
89{
90 std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
91 if ( !source )
92 throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
93
94 QString dest;
95 std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(), Qgis::WkbType::MultiPolygon, source->sourceCrs() ) );
96 if ( !sink )
97 throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
98
99 // fixed parameters
100 const bool dissolve = parameterAsBoolean( parameters, QStringLiteral( "DISSOLVE" ), context );
101 const bool keepDisjointSeparate = parameterAsBoolean( parameters, QStringLiteral( "SEPARATE_DISJOINT" ), context );
102 const int segments = parameterAsInt( parameters, QStringLiteral( "SEGMENTS" ), context );
103 const Qgis::EndCapStyle endCapStyle = static_cast< Qgis::EndCapStyle >( 1 + parameterAsInt( parameters, QStringLiteral( "END_CAP_STYLE" ), context ) );
104 const Qgis::JoinStyle joinStyle = static_cast< Qgis::JoinStyle>( 1 + parameterAsInt( parameters, QStringLiteral( "JOIN_STYLE" ), context ) );
105 const double miterLimit = parameterAsDouble( parameters, QStringLiteral( "MITER_LIMIT" ), context );
106 const double bufferDistance = parameterAsDouble( parameters, QStringLiteral( "DISTANCE" ), context );
107 const bool dynamicBuffer = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DISTANCE" ) );
108 QgsExpressionContext expressionContext = createExpressionContext( parameters, context, source.get() );
109 QgsProperty bufferProperty;
110 if ( dynamicBuffer )
111 {
112 bufferProperty = parameters.value( QStringLiteral( "DISTANCE" ) ).value< QgsProperty >();
113 }
114
115 const long count = source->featureCount();
116
117 QgsFeature f;
118 // buffer doesn't care about invalid features, and buffering can be used to repair geometries
120
121 const double step = count > 0 ? 100.0 / count : 1;
122 int current = 0;
123
124 QVector< QgsGeometry > bufferedGeometriesForDissolve;
125 QgsAttributes dissolveAttrs;
126
127 while ( it.nextFeature( f ) )
128 {
129 if ( feedback->isCanceled() )
130 {
131 break;
132 }
133 if ( dissolveAttrs.isEmpty() )
134 dissolveAttrs = f.attributes();
135
136 QgsFeature out = f;
137 if ( out.hasGeometry() )
138 {
139 double distance = bufferDistance;
140 if ( dynamicBuffer )
141 {
142 expressionContext.setFeature( f );
143 distance = bufferProperty.valueAsDouble( expressionContext, bufferDistance );
144 }
145
146 QgsGeometry outputGeometry = f.geometry().buffer( distance, segments, endCapStyle, joinStyle, miterLimit );
147 if ( outputGeometry.isNull() )
148 {
149 QgsMessageLog::logMessage( QObject::tr( "Error calculating buffer for feature %1" ).arg( f.id() ), QObject::tr( "Processing" ), Qgis::MessageLevel::Warning );
150 }
151 if ( dissolve )
152 {
153 bufferedGeometriesForDissolve << outputGeometry;
154 }
155 else
156 {
157 outputGeometry.convertToMultiType();
158
159 if ( !keepDisjointSeparate )
160 {
161 out.setGeometry( outputGeometry );
162
163 if ( !sink->addFeature( out, QgsFeatureSink::FastInsert ) )
164 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
165 }
166 else
167 {
168 for ( auto partIt = outputGeometry.const_parts_begin(); partIt != outputGeometry.const_parts_end(); ++partIt )
169 {
170 if ( const QgsAbstractGeometry *part = *partIt )
171 {
172 out.setGeometry( QgsGeometry( part->clone() ) );
173 if ( !sink->addFeature( out, QgsFeatureSink::FastInsert ) )
174 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
175 }
176 }
177 }
178 }
179 }
180 else if ( !dissolve )
181 {
182 if ( !sink->addFeature( out, QgsFeatureSink::FastInsert ) )
183 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
184 }
185
186 feedback->setProgress( current * step );
187 current++;
188 }
189
190 if ( dissolve && !bufferedGeometriesForDissolve.isEmpty() )
191 {
192 QgsGeometry finalGeometry = QgsGeometry::unaryUnion( bufferedGeometriesForDissolve );
193 finalGeometry.convertToMultiType();
194 QgsFeature f;
195 f.setAttributes( dissolveAttrs );
196
197 if ( !keepDisjointSeparate )
198 {
199 f.setGeometry( finalGeometry );
200 if ( !sink->addFeature( f, QgsFeatureSink::FastInsert ) )
201 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
202 }
203 else
204 {
205 for ( auto partIt = finalGeometry.const_parts_begin(); partIt != finalGeometry.const_parts_end(); ++partIt )
206 {
207 if ( const QgsAbstractGeometry *part = *partIt )
208 {
209 f.setGeometry( QgsGeometry( part->clone() ) );
210 if ( !sink->addFeature( f, QgsFeatureSink::FastInsert ) )
211 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
212 }
213 }
214 }
215 }
216
217 QVariantMap outputs;
218 outputs.insert( QStringLiteral( "OUTPUT" ), dest );
219 return outputs;
220}
221
222QgsProcessingAlgorithm::Flags QgsBufferAlgorithm::flags() const
223{
226 return f;
227}
228
229QgsProcessingAlgorithm::VectorProperties QgsBufferAlgorithm::sinkProperties( const QString &sink, const QVariantMap &parameters, QgsProcessingContext &context, const QMap<QString, QgsProcessingAlgorithm::VectorProperties> &sourceProperties ) const
230{
231 const bool keepDisjointSeparate = parameterAsBoolean( parameters, QStringLiteral( "SEPARATE_DISJOINT" ), context );
232
234 if ( sink == QLatin1String( "OUTPUT" ) )
235 {
236 if ( sourceProperties.value( QStringLiteral( "INPUT" ) ).availability == QgsProcessingAlgorithm::Available )
237 {
238 const VectorProperties inputProps = sourceProperties.value( QStringLiteral( "INPUT" ) );
239 result.fields = inputProps.fields;
240 result.crs = inputProps.crs;
241 result.wkbType = keepDisjointSeparate ? Qgis::WkbType::Polygon : Qgis::WkbType::MultiPolygon;
242 result.availability = Available;
243 return result;
244 }
245 else
246 {
247 std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
248 if ( source )
249 {
250 result.fields = source->fields();
251 result.crs = source->sourceCrs();
252 result.wkbType = keepDisjointSeparate ? Qgis::WkbType::Polygon : Qgis::WkbType::MultiPolygon;
253 result.availability = Available;
254 return result;
255 }
256 }
257 }
258 return result;
259}
260
261bool QgsBufferAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const
262{
263 const QgsVectorLayer *vlayer = qobject_cast< const QgsVectorLayer * >( layer );
264 if ( !vlayer )
265 return false;
266 //Only Polygons
267 return vlayer->wkbType() == Qgis::WkbType::Polygon || vlayer->wkbType() == Qgis::WkbType::MultiPolygon;
268}
269
@ Warning
Warning message.
Definition qgis.h:101
JoinStyle
Join styles for buffers.
Definition qgis.h:1599
EndCapStyle
End cap styles for buffers.
Definition qgis.h:1586
@ Polygon
Polygon.
@ MultiPolygon
MultiPolygon.
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)
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
QgsFeatureId id
Definition qgsfeature.h:64
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
QgsGeometry geometry
Definition qgsfeature.h:67
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: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.
QgsAbstractGeometry::const_part_iterator const_parts_begin() const
Returns STL-style const iterator pointing to the first part of the geometry.
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...
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.
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:74
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.
@ 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.
@ FlagAdvanced
Parameter is an advanced parameter which should be hidden from users by default.
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 for a property.
Definition qgsproperty.h:46
@ 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 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.