QGIS API Documentation  3.0.2-Girona (307d082)
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( QObject::tr( "Could not load source layer for INPUT" ) );
75 
76  std::unique_ptr< QgsFeatureSource > maskSource( parameterAsSource( parameters, QStringLiteral( "OVERLAY" ), context ) );
77  if ( !maskSource )
78  throw QgsProcessingException( QObject::tr( "Could not load source layer for 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( QObject::tr( "Could not create destination layer for 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  singleClipFeature = false;
109  }
110  else
111  {
112  combinedClipGeom = clipGeoms.at( 0 );
113  singleClipFeature = true;
114  }
115 
116  // use prepared geometries for faster intersection tests
117  std::unique_ptr< QgsGeometryEngine > engine( QgsGeometry::createGeometryEngine( combinedClipGeom.constGet() ) );
118  engine->prepareGeometry();
119 
120  QgsFeatureIds testedFeatureIds;
121 
122  int i = -1;
123  Q_FOREACH ( const QgsGeometry &clipGeom, clipGeoms )
124  {
125  i++;
126  if ( feedback->isCanceled() )
127  {
128  break;
129  }
130 
131  QgsFeatureIterator inputIt = featureSource->getFeatures( QgsFeatureRequest().setFilterRect( clipGeom.boundingBox() ) );
132  QgsFeatureList inputFeatures;
133  QgsFeature f;
134  while ( inputIt.nextFeature( f ) )
135  inputFeatures << f;
136 
137  if ( inputFeatures.isEmpty() )
138  continue;
139 
140  double step = 0;
141  if ( singleClipFeature )
142  step = 100.0 / inputFeatures.length();
143 
144  int current = 0;
145  Q_FOREACH ( const QgsFeature &inputFeature, inputFeatures )
146  {
147  if ( feedback->isCanceled() )
148  {
149  break;
150  }
151 
152  if ( !inputFeature.hasGeometry() )
153  continue;
154 
155  if ( testedFeatureIds.contains( inputFeature.id() ) )
156  {
157  // don't retest a feature we have already checked
158  continue;
159  }
160  testedFeatureIds.insert( inputFeature.id() );
161 
162  if ( !engine->intersects( inputFeature.geometry().constGet() ) )
163  continue;
164 
165  QgsGeometry newGeometry;
166  if ( !engine->contains( inputFeature.geometry().constGet() ) )
167  {
168  QgsGeometry currentGeometry = inputFeature.geometry();
169  newGeometry = combinedClipGeom.intersection( currentGeometry );
170  if ( newGeometry.wkbType() == QgsWkbTypes::Unknown || QgsWkbTypes::flatType( newGeometry.wkbType() ) == QgsWkbTypes::GeometryCollection )
171  {
172  QgsGeometry intCom = inputFeature.geometry().combine( newGeometry );
173  QgsGeometry intSym = inputFeature.geometry().symDifference( newGeometry );
174  newGeometry = intCom.difference( intSym );
175  }
176  }
177  else
178  {
179  // clip geometry totally contains feature geometry, so no need to perform intersection
180  newGeometry = inputFeature.geometry();
181  }
182 
183  QgsFeature outputFeature;
184  outputFeature.setGeometry( newGeometry );
185  outputFeature.setAttributes( inputFeature.attributes() );
186  sink->addFeature( outputFeature, QgsFeatureSink::FastInsert );
187 
188 
189  if ( singleClipFeature )
190  feedback->setProgress( current * step );
191  }
192 
193  if ( !singleClipFeature )
194  {
195  // coarse progress report for multiple clip geometries
196  feedback->setProgress( 100.0 * static_cast< double >( i ) / clipGeoms.length() );
197  }
198  }
199 
200  return outputs;
201 }
202 
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:111
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.
Vector polygon layers.
Definition: qgsprocessing.h:51
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.
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...