QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 
24 QString QgsBufferAlgorithm::name() const
25 {
26  return QStringLiteral( "buffer" );
27 }
28 
29 QString QgsBufferAlgorithm::displayName() const
30 {
31  return QObject::tr( "Buffer" );
32 }
33 
34 QStringList QgsBufferAlgorithm::tags() const
35 {
36  return QObject::tr( "buffer,grow,fixed,variable,distance" ).split( ',' );
37 }
38 
39 QString QgsBufferAlgorithm::group() const
40 {
41  return QObject::tr( "Vector geometry" );
42 }
43 
44 QString QgsBufferAlgorithm::groupId() const
45 {
46  return QStringLiteral( "vectorgeometry" );
47 }
48 
49 void QgsBufferAlgorithm::initAlgorithm( const QVariantMap & )
50 {
51  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
52 
53  auto bufferParam = qgis::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  addParameter( new QgsProcessingParameterNumber( QStringLiteral( "SEGMENTS" ), QObject::tr( "Segments" ), QgsProcessingParameterNumber::Integer, 5, false, 1 ) );
59 
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  addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Buffered" ), QgsProcessing::TypeVectorPolygon ) );
66 }
67 
68 QString QgsBufferAlgorithm::shortHelpString() const
69 {
70  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"
71  "The segments parameter controls the number of line segments to use to approximate a quarter circle when creating rounded offsets.\n\n"
72  "The end cap style parameter controls how line endings are handled in the buffer.\n\n"
73  "The join style parameter specifies whether round, miter or beveled joins should be used when offsetting corners in a line.\n\n"
74  "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." );
75 }
76 
77 QgsBufferAlgorithm *QgsBufferAlgorithm::createInstance() const
78 {
79  return new QgsBufferAlgorithm();
80 }
81 
82 QVariantMap QgsBufferAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
83 {
84  std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
85  if ( !source )
86  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
87 
88  QString dest;
89  std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(), QgsWkbTypes::MultiPolygon, source->sourceCrs() ) );
90  if ( !sink )
91  throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
92 
93  // fixed parameters
94  bool dissolve = parameterAsBoolean( parameters, QStringLiteral( "DISSOLVE" ), context );
95  int segments = parameterAsInt( parameters, QStringLiteral( "SEGMENTS" ), context );
96  QgsGeometry::EndCapStyle endCapStyle = static_cast< QgsGeometry::EndCapStyle >( 1 + parameterAsInt( parameters, QStringLiteral( "END_CAP_STYLE" ), context ) );
97  QgsGeometry::JoinStyle joinStyle = static_cast< QgsGeometry::JoinStyle>( 1 + parameterAsInt( parameters, QStringLiteral( "JOIN_STYLE" ), context ) );
98  double miterLimit = parameterAsDouble( parameters, QStringLiteral( "MITER_LIMIT" ), context );
99  double bufferDistance = parameterAsDouble( parameters, QStringLiteral( "DISTANCE" ), context );
100  bool dynamicBuffer = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DISTANCE" ) );
101  QgsExpressionContext expressionContext = createExpressionContext( parameters, context, source.get() );
102  QgsProperty bufferProperty;
103  if ( dynamicBuffer )
104  {
105  bufferProperty = parameters.value( QStringLiteral( "DISTANCE" ) ).value< QgsProperty >();
106  }
107 
108  long count = source->featureCount();
109 
110  QgsFeature f;
111  // buffer doesn't care about invalid features, and buffering can be used to repair geometries
113 
114  double step = count > 0 ? 100.0 / count : 1;
115  int current = 0;
116 
117  QVector< QgsGeometry > bufferedGeometriesForDissolve;
118  QgsAttributes dissolveAttrs;
119 
120  while ( it.nextFeature( f ) )
121  {
122  if ( feedback->isCanceled() )
123  {
124  break;
125  }
126  if ( dissolveAttrs.isEmpty() )
127  dissolveAttrs = f.attributes();
128 
129  QgsFeature out = f;
130  if ( out.hasGeometry() )
131  {
132  double distance = bufferDistance;
133  if ( dynamicBuffer )
134  {
135  expressionContext.setFeature( f );
136  distance = bufferProperty.valueAsDouble( expressionContext, bufferDistance );
137  }
138 
139  QgsGeometry outputGeometry = f.geometry().buffer( distance, segments, endCapStyle, joinStyle, miterLimit );
140  if ( outputGeometry.isNull() )
141  {
142  QgsMessageLog::logMessage( QObject::tr( "Error calculating buffer for feature %1" ).arg( f.id() ), QObject::tr( "Processing" ), Qgis::Warning );
143  }
144  if ( dissolve )
145  bufferedGeometriesForDissolve << outputGeometry;
146  else
147  {
148  outputGeometry.convertToMultiType();
149  out.setGeometry( outputGeometry );
150  }
151  }
152 
153  if ( !dissolve )
154  sink->addFeature( out, QgsFeatureSink::FastInsert );
155 
156  feedback->setProgress( current * step );
157  current++;
158  }
159 
160  if ( dissolve )
161  {
162  QgsGeometry finalGeometry = QgsGeometry::unaryUnion( bufferedGeometriesForDissolve );
163  finalGeometry.convertToMultiType();
164  QgsFeature f;
165  f.setGeometry( finalGeometry );
166  f.setAttributes( dissolveAttrs );
167  sink->addFeature( f, QgsFeatureSink::FastInsert );
168  }
169 
170  QVariantMap outputs;
171  outputs.insert( QStringLiteral( "OUTPUT" ), dest );
172  return outputs;
173 }
174 
175 QgsProcessingAlgorithm::Flags QgsBufferAlgorithm::flags() const
176 {
177  Flags f = QgsProcessingAlgorithm::flags();
179  return f;
180 }
181 
182 bool QgsBufferAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const
183 {
184  const QgsVectorLayer *vlayer = qobject_cast< const QgsVectorLayer * >( layer );
185  if ( !vlayer )
186  return false;
187  //Only Polygons
188  return vlayer->wkbType() == QgsWkbTypes::Type::Polygon || vlayer->wkbType() == QgsWkbTypes::Type::MultiPolygon;
189 }
190 
A boolean parameter for processing algorithms.
QgsFeatureId id
Definition: qgsfeature.h:64
Wrapper for iterator of features from vector data provider or vector layer.
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
Base class for all map layer types.
Definition: qgsmaplayer.h:78
Base class for providing feedback from a processing algorithm.
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:63
virtual Flags flags() const
Returns the flags indicating how and when the algorithm operates and should be exposed to users...
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:111
void setAttributes(const QgsAttributes &attrs)
Sets the feature&#39;s attributes.
Definition: qgsfeature.cpp:127
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...
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...
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
EndCapStyle
End cap styles for buffers.
Definition: qgsgeometry.h:1051
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:197
A feature sink output for processing algorithms.
An enum based parameter for processing algorithms, allowing for selection from predefined values...
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
This class wraps a request for features to a vector layer (or directly its vector data provider)...
Custom exception class for processing related exceptions.
Definition: qgsexception.h:82
Vector polygon layers.
Definition: qgsprocessing.h:50
A store for object properties.
Definition: qgsproperty.h:229
Double value (including negative values)
Definition: qgsproperty.h:57
A numeric parameter for processing algorithms.
Definition for a property.
Definition: qgsproperty.h:46
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
An input feature source (such as vector layers) parameter for processing algorithms.
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:137
QgsGeometry geometry
Definition: qgsfeature.h:67
bool nextFeature(QgsFeature &f)
JoinStyle
Join styles for buffers.
Definition: qgsgeometry.h:1060
A vector of attributes.
Definition: qgsattributes.h:57
Represents a vector layer which manages a vector based data sets.
Contains information about the context in which a processing algorithm is executed.
static QgsGeometry unaryUnion(const QVector< QgsGeometry > &geometries)
Compute the unary union on a list of geometries.
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...
QgsAttributes attributes
Definition: qgsfeature.h:65