QGIS API Documentation  3.2.0-Bonn (bc43194)
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 
22 
23 QString QgsClipAlgorithm::name() const
24 {
25  return QStringLiteral( "clip" );
26 }
27 
28 QString QgsClipAlgorithm::displayName() const
29 {
30  return QObject::tr( "Clip" );
31 }
32 
33 QStringList QgsClipAlgorithm::tags() const
34 {
35  return QObject::tr( "clip,intersect,intersection,mask" ).split( ',' );
36 }
37 
38 QString QgsClipAlgorithm::group() const
39 {
40  return QObject::tr( "Vector overlay" );
41 }
42 
43 QString QgsClipAlgorithm::groupId() const
44 {
45  return QStringLiteral( "vectoroverlay" );
46 }
47 
48 void QgsClipAlgorithm::initAlgorithm( const QVariantMap & )
49 {
50  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
51  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "OVERLAY" ), QObject::tr( "Clip layer" ), QList< int >() << QgsProcessing::TypeVectorPolygon ) );
52 
53  addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Clipped" ) ) );
54 }
55 
56 QString QgsClipAlgorithm::shortHelpString() const
57 {
58  return QObject::tr( "This algorithm clips a vector layer using the polygons of an additional polygons layer. Only the parts of the features "
59  "in the input layer that falls within the polygons of the clipping layer will be added to the resulting layer.\n\n"
60  "The attributes of the features are not modified, although properties such as area or length of the features will "
61  "be modified by the clipping operation. If such properties are stored as attributes, those attributes will have to "
62  "be manually updated." );
63 }
64 
65 QgsClipAlgorithm *QgsClipAlgorithm::createInstance() const
66 {
67  return new QgsClipAlgorithm();
68 }
69 
70 QVariantMap QgsClipAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
71 {
72  std::unique_ptr< QgsFeatureSource > featureSource( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
73  if ( !featureSource )
74  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
75 
76  std::unique_ptr< QgsFeatureSource > maskSource( parameterAsSource( parameters, QStringLiteral( "OVERLAY" ), context ) );
77  if ( !maskSource )
78  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "OVERLAY" ) ) );
79 
80  QString dest;
81  std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, featureSource->fields(), QgsWkbTypes::multiType( featureSource->wkbType() ), featureSource->sourceCrs() ) );
82 
83  if ( !sink )
84  throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
85 
86  // first build up a list of clip geometries
87  QVector< QgsGeometry > clipGeoms;
88  QgsFeatureIterator it = maskSource->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QList< int >() ).setDestinationCrs( featureSource->sourceCrs(), context.transformContext() ) );
89  QgsFeature f;
90  while ( it.nextFeature( f ) )
91  {
92  if ( f.hasGeometry() )
93  clipGeoms << f.geometry();
94  }
95 
96  QVariantMap outputs;
97  outputs.insert( QStringLiteral( "OUTPUT" ), dest );
98 
99  if ( clipGeoms.isEmpty() )
100  return outputs;
101 
102  // are we clipping against a single feature? if so, we can show finer progress reports
103  bool singleClipFeature = false;
104  QgsGeometry combinedClipGeom;
105  if ( clipGeoms.length() > 1 )
106  {
107  combinedClipGeom = QgsGeometry::unaryUnion( clipGeoms );
108  if ( combinedClipGeom.isEmpty() )
109  {
110  throw QgsProcessingException( QObject::tr( "Could not create the combined clip geometry: %1" ).arg( combinedClipGeom.lastError() ) );
111  }
112  singleClipFeature = false;
113  }
114  else
115  {
116  combinedClipGeom = clipGeoms.at( 0 );
117  singleClipFeature = true;
118  }
119 
120  // use prepared geometries for faster intersection tests
121  std::unique_ptr< QgsGeometryEngine > engine( QgsGeometry::createGeometryEngine( combinedClipGeom.constGet() ) );
122  engine->prepareGeometry();
123 
124  QgsFeatureIds testedFeatureIds;
125 
126  int i = -1;
127  Q_FOREACH ( const QgsGeometry &clipGeom, clipGeoms )
128  {
129  i++;
130  if ( feedback->isCanceled() )
131  {
132  break;
133  }
134 
135  QgsFeatureIterator inputIt = featureSource->getFeatures( QgsFeatureRequest().setFilterRect( clipGeom.boundingBox() ) );
136  QgsFeatureList inputFeatures;
137  QgsFeature f;
138  while ( inputIt.nextFeature( f ) )
139  inputFeatures << f;
140 
141  if ( inputFeatures.isEmpty() )
142  continue;
143 
144  double step = 0;
145  if ( singleClipFeature )
146  step = 100.0 / inputFeatures.length();
147 
148  int current = 0;
149  Q_FOREACH ( const QgsFeature &inputFeature, inputFeatures )
150  {
151  if ( feedback->isCanceled() )
152  {
153  break;
154  }
155 
156  if ( !inputFeature.hasGeometry() )
157  continue;
158 
159  if ( testedFeatureIds.contains( inputFeature.id() ) )
160  {
161  // don't retest a feature we have already checked
162  continue;
163  }
164  testedFeatureIds.insert( inputFeature.id() );
165 
166  if ( !engine->intersects( inputFeature.geometry().constGet() ) )
167  continue;
168 
169  QgsGeometry newGeometry;
170  if ( !engine->contains( inputFeature.geometry().constGet() ) )
171  {
172  QgsGeometry currentGeometry = inputFeature.geometry();
173  newGeometry = combinedClipGeom.intersection( currentGeometry );
174  if ( newGeometry.wkbType() == QgsWkbTypes::Unknown || QgsWkbTypes::flatType( newGeometry.wkbType() ) == QgsWkbTypes::GeometryCollection )
175  {
176  QgsGeometry intCom = inputFeature.geometry().combine( newGeometry );
177  QgsGeometry intSym = inputFeature.geometry().symDifference( newGeometry );
178  newGeometry = intCom.difference( intSym );
179  }
180  }
181  else
182  {
183  // clip geometry totally contains feature geometry, so no need to perform intersection
184  newGeometry = inputFeature.geometry();
185  }
186 
187  QgsFeature outputFeature;
188  outputFeature.setGeometry( newGeometry );
189  outputFeature.setAttributes( inputFeature.attributes() );
190  sink->addFeature( outputFeature, QgsFeatureSink::FastInsert );
191 
192 
193  if ( singleClipFeature )
194  feedback->setProgress( current * step );
195  }
196 
197  if ( !singleClipFeature )
198  {
199  // coarse progress report for multiple clip geometries
200  feedback->setProgress( 100.0 * static_cast< double >( i ) / clipGeoms.length() );
201  }
202  }
203 
204  return outputs;
205 }
206 
QgsFeatureId id
Definition: qgsfeature.h:71
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...
QgsGeometry combine(const QgsGeometry &geometry) const
Returns a geometry representing all the points in this geometry and other (a union geometry operation...
static Type multiType(Type type)
Returns the multi type for a WKB type.
Definition: qgswkbtypes.h:296
Base class for providing feedback from a processing algorithm.
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:544
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:549
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
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:104
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:62
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:190
A feature sink output for processing algorithms.
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
QgsGeometry geometry() const
Returns the geometry associated with this feature.
Definition: qgsfeature.cpp:101
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.
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
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...
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:427
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:72
QgsGeometry difference(const QgsGeometry &geometry) const
Returns a geometry representing the points making up this geometry that do not make up other...