QGIS API Documentation  3.6.0-Noosa (5873452)
qgsalgorithmclip.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmclip.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 "qgsalgorithmclip.h"
19 #include "qgsgeometryengine.h"
20 #include "qgsoverlayutils.h"
21 #include "qgsvectorlayer.h"
22 
24 
25 QString QgsClipAlgorithm::name() const
26 {
27  return QStringLiteral( "clip" );
28 }
29 
30 QgsProcessingAlgorithm::Flags QgsClipAlgorithm::flags() const
31 {
34  return f;
35 }
36 
37 QString QgsClipAlgorithm::displayName() const
38 {
39  return QObject::tr( "Clip" );
40 }
41 
42 QStringList QgsClipAlgorithm::tags() const
43 {
44  return QObject::tr( "clip,intersect,intersection,mask" ).split( ',' );
45 }
46 
47 QString QgsClipAlgorithm::group() const
48 {
49  return QObject::tr( "Vector overlay" );
50 }
51 
52 QString QgsClipAlgorithm::groupId() const
53 {
54  return QStringLiteral( "vectoroverlay" );
55 }
56 
57 void QgsClipAlgorithm::initAlgorithm( const QVariantMap & )
58 {
59  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
60  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "OVERLAY" ), QObject::tr( "Overlay layer" ), QList< int >() << QgsProcessing::TypeVectorPolygon ) );
61 
62  addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Clipped" ) ) );
63 }
64 
65 QString QgsClipAlgorithm::shortHelpString() const
66 {
67  return QObject::tr( "This algorithm clips a vector layer using the features of an additional polygon layer. Only the parts of the features "
68  "in the Input layer that fall within the polygons of the Overlay layer will be added to the resulting layer." )
69  + QStringLiteral( "\n\n" )
70  + QObject::tr( "The attributes of the features are not modified, although properties such as area or length of the features will "
71  "be modified by the clipping operation. If such properties are stored as attributes, those attributes will have to "
72  "be manually updated." );
73 }
74 
75 QgsClipAlgorithm *QgsClipAlgorithm::createInstance() const
76 {
77  return new QgsClipAlgorithm();
78 }
79 
80 bool QgsClipAlgorithm::supportInPlaceEdit( const QgsMapLayer *l ) const
81 {
82  const QgsVectorLayer *layer = qobject_cast< const QgsVectorLayer * >( l );
83  if ( !layer )
84  return false;
85 
86  return layer->isSpatial();
87 }
88 
89 QVariantMap QgsClipAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
90 {
91  std::unique_ptr< QgsFeatureSource > featureSource( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
92  if ( !featureSource )
93  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
94 
95  std::unique_ptr< QgsFeatureSource > maskSource( parameterAsSource( parameters, QStringLiteral( "OVERLAY" ), context ) );
96  if ( !maskSource )
97  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "OVERLAY" ) ) );
98 
99  QString dest;
100  QgsWkbTypes::GeometryType sinkType = QgsWkbTypes::geometryType( featureSource->wkbType() );
101  std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, featureSource->fields(), QgsWkbTypes::multiType( featureSource->wkbType() ), featureSource->sourceCrs() ) );
102 
103  if ( !sink )
104  throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
105 
106  // first build up a list of clip geometries
107  QVector< QgsGeometry > clipGeoms;
108  QgsFeatureIterator it = maskSource->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QList< int >() ).setDestinationCrs( featureSource->sourceCrs(), context.transformContext() ) );
109  QgsFeature f;
110  while ( it.nextFeature( f ) )
111  {
112  if ( f.hasGeometry() )
113  clipGeoms << f.geometry();
114  }
115 
116  QVariantMap outputs;
117  outputs.insert( QStringLiteral( "OUTPUT" ), dest );
118 
119  if ( clipGeoms.isEmpty() )
120  return outputs;
121 
122  // are we clipping against a single feature? if so, we can show finer progress reports
123  bool singleClipFeature = false;
124  QgsGeometry combinedClipGeom;
125  if ( clipGeoms.length() > 1 )
126  {
127  combinedClipGeom = QgsGeometry::unaryUnion( clipGeoms );
128  if ( combinedClipGeom.isEmpty() )
129  {
130  throw QgsProcessingException( QObject::tr( "Could not create the combined clip geometry: %1" ).arg( combinedClipGeom.lastError() ) );
131  }
132  singleClipFeature = false;
133  }
134  else
135  {
136  combinedClipGeom = clipGeoms.at( 0 );
137  singleClipFeature = true;
138  }
139 
140  // use prepared geometries for faster intersection tests
141  std::unique_ptr< QgsGeometryEngine > engine( QgsGeometry::createGeometryEngine( combinedClipGeom.constGet() ) );
142  engine->prepareGeometry();
143 
144  QgsFeatureIds testedFeatureIds;
145 
146  int i = -1;
147  Q_FOREACH ( const QgsGeometry &clipGeom, clipGeoms )
148  {
149  i++;
150  if ( feedback->isCanceled() )
151  {
152  break;
153  }
154  QgsFeatureIterator inputIt = featureSource->getFeatures( QgsFeatureRequest().setFilterRect( clipGeom.boundingBox() ) );
155  QgsFeatureList inputFeatures;
156  QgsFeature f;
157  while ( inputIt.nextFeature( f ) )
158  inputFeatures << f;
159 
160  if ( inputFeatures.isEmpty() )
161  continue;
162 
163  double step = 0;
164  if ( singleClipFeature )
165  step = 100.0 / inputFeatures.length();
166 
167  int current = 0;
168  Q_FOREACH ( const QgsFeature &inputFeature, inputFeatures )
169  {
170  if ( feedback->isCanceled() )
171  {
172  break;
173  }
174 
175  if ( !inputFeature.hasGeometry() )
176  continue;
177 
178  if ( testedFeatureIds.contains( inputFeature.id() ) )
179  {
180  // don't retest a feature we have already checked
181  continue;
182  }
183  testedFeatureIds.insert( inputFeature.id() );
184 
185  if ( !engine->intersects( inputFeature.geometry().constGet() ) )
186  continue;
187 
188  QgsGeometry newGeometry;
189  if ( !engine->contains( inputFeature.geometry().constGet() ) )
190  {
191  QgsGeometry currentGeometry = inputFeature.geometry();
192  newGeometry = combinedClipGeom.intersection( currentGeometry );
193  if ( newGeometry.wkbType() == QgsWkbTypes::Unknown || QgsWkbTypes::flatType( newGeometry.wkbType() ) == QgsWkbTypes::GeometryCollection )
194  {
195  QgsGeometry intCom = inputFeature.geometry().combine( newGeometry );
196  QgsGeometry intSym = inputFeature.geometry().symDifference( newGeometry );
197  newGeometry = intCom.difference( intSym );
198  }
199  }
200  else
201  {
202  // clip geometry totally contains feature geometry, so no need to perform intersection
203  newGeometry = inputFeature.geometry();
204  }
205 
206  if ( !QgsOverlayUtils::sanitizeIntersectionResult( newGeometry, sinkType ) )
207  continue;
208 
209  QgsFeature outputFeature;
210  outputFeature.setGeometry( newGeometry );
211  outputFeature.setAttributes( inputFeature.attributes() );
212  sink->addFeature( outputFeature, QgsFeatureSink::FastInsert );
213 
214 
215  if ( singleClipFeature )
216  feedback->setProgress( current * step );
217  }
218 
219  if ( !singleClipFeature )
220  {
221  // coarse progress report for multiple clip geometries
222  feedback->setProgress( 100.0 * static_cast< double >( i ) / clipGeoms.length() );
223  }
224  }
225 
226  return outputs;
227 }
228 
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:64
QgsGeometry combine(const QgsGeometry &geometry) const
Returns a geometry representing all the points in this geometry and other (a union geometry operation...
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
static Type multiType(Type type)
Returns the multi type for a WKB type.
Definition: qgswkbtypes.h:298
Base class for providing feedback from a processing algorithm.
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:571
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
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:106
void setAttributes(const QgsAttributes &attrs)
Sets the feature&#39;s attributes.
Definition: qgsfeature.cpp:127
QgsGeometry intersection(const QgsGeometry &geometry) const
Returns a geometry representing the points shared by this geometry and other.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:197
bool isSpatial() const FINAL
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
A feature sink output for processing algorithms.
static GeometryType geometryType(Type type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:665
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
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
Vector polygon layers.
Definition: qgsprocessing.h:50
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:138
QString lastError() const
Returns an error string referring to the last error encountered either when this geometry was created...
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.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
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)
QgsGeometry symDifference(const QgsGeometry &geometry) const
Returns a geometry representing the points making up this geometry that do not make up other...
Represents a vector layer which manages a vector based data sets.
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:429
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.
QgsAttributes attributes
Definition: qgsfeature.h:65
QgsGeometry difference(const QgsGeometry &geometry) const
Returns a geometry representing the points making up this geometry that do not make up other...