QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
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
20#include "qgsgeometryengine.h"
21#include "qgsoverlayutils.h"
22#include "qgsvectorlayer.h"
23
25
26QString QgsClipAlgorithm::name() const
27{
28 return QStringLiteral( "clip" );
29}
30
31Qgis::ProcessingAlgorithmFlags QgsClipAlgorithm::flags() const
32{
35 return f;
36}
37
38QString QgsClipAlgorithm::displayName() const
39{
40 return QObject::tr( "Clip" );
41}
42
43QStringList QgsClipAlgorithm::tags() const
44{
45 return QObject::tr( "clip,intersect,intersection,mask" ).split( ',' );
46}
47
48QString QgsClipAlgorithm::group() const
49{
50 return QObject::tr( "Vector overlay" );
51}
52
53QString QgsClipAlgorithm::groupId() const
54{
55 return QStringLiteral( "vectoroverlay" );
56}
57
58void QgsClipAlgorithm::initAlgorithm( const QVariantMap & )
59{
60 addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
61 addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "OVERLAY" ), QObject::tr( "Overlay layer" ), QList<int>() << static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon ) ) );
62
63 addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Clipped" ) ) );
64}
65
66QString QgsClipAlgorithm::shortHelpString() const
67{
68 return QObject::tr( "This algorithm clips a vector layer using the features of an additional polygon layer. Only the parts of the features "
69 "in the Input layer that fall within the polygons of the Overlay layer will be added to the resulting layer." )
70 + QStringLiteral( "\n\n" )
71 + QObject::tr( "The attributes of the features are not modified, although properties such as area or length of the features will "
72 "be modified by the clipping operation. If such properties are stored as attributes, those attributes will have to "
73 "be manually updated." );
74}
75
76QString QgsClipAlgorithm::shortDescription() const
77{
78 return QObject::tr( "Clips a vector layer using the features of an additional polygon layer." );
79}
80
81QgsClipAlgorithm *QgsClipAlgorithm::createInstance() const
82{
83 return new QgsClipAlgorithm();
84}
85
86bool QgsClipAlgorithm::supportInPlaceEdit( const QgsMapLayer *l ) const
87{
88 const QgsVectorLayer *layer = qobject_cast<const QgsVectorLayer *>( l );
89 if ( !layer )
90 return false;
91
92 return layer->isSpatial();
93}
94
95QVariantMap QgsClipAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
96{
97 std::unique_ptr<QgsFeatureSource> featureSource( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
98 if ( !featureSource )
99 throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
100
101 std::unique_ptr<QgsFeatureSource> maskSource( parameterAsSource( parameters, QStringLiteral( "OVERLAY" ), context ) );
102 if ( !maskSource )
103 throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "OVERLAY" ) ) );
104
105 if ( featureSource->hasSpatialIndex() == Qgis::SpatialIndexPresence::NotPresent )
106 feedback->pushWarning( QObject::tr( "No spatial index exists for input layer, performance will be severely degraded" ) );
107
108 QString dest;
109 const Qgis::GeometryType sinkType = QgsWkbTypes::geometryType( featureSource->wkbType() );
110 std::unique_ptr<QgsFeatureSink> sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, featureSource->fields(), QgsWkbTypes::promoteNonPointTypesToMulti( featureSource->wkbType() ), featureSource->sourceCrs() ) );
111
112 if ( !sink )
113 throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
114
115 // first build up a list of clip geometries
116 QVector<QgsGeometry> clipGeoms;
117 QgsFeatureIterator it = maskSource->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QList<int>() ).setDestinationCrs( featureSource->sourceCrs(), context.transformContext() ) );
118 QgsFeature f;
119 while ( it.nextFeature( f ) )
120 {
121 if ( f.hasGeometry() )
122 clipGeoms << f.geometry();
123 }
124
125 QVariantMap outputs;
126 outputs.insert( QStringLiteral( "OUTPUT" ), dest );
127
128 if ( clipGeoms.isEmpty() )
129 return outputs;
130
131 // are we clipping against a single feature? if so, we can show finer progress reports
132 bool singleClipFeature = false;
133 QgsGeometry combinedClipGeom;
134 if ( clipGeoms.length() > 1 )
135 {
136 combinedClipGeom = QgsGeometry::unaryUnion( clipGeoms );
137 if ( combinedClipGeom.isEmpty() )
138 {
139 throw QgsProcessingException( QObject::tr( "Could not create the combined clip geometry: %1" ).arg( combinedClipGeom.lastError() ) );
140 }
141 singleClipFeature = false;
142 }
143 else
144 {
145 combinedClipGeom = clipGeoms.at( 0 );
146 singleClipFeature = true;
147 }
148
149 // use prepared geometries for faster intersection tests
150 std::unique_ptr<QgsGeometryEngine> engine( QgsGeometry::createGeometryEngine( combinedClipGeom.constGet() ) );
151 engine->prepareGeometry();
152
153 QgsFeatureIds testedFeatureIds;
154
155 int i = -1;
156 const auto constClipGeoms = clipGeoms;
157 for ( const QgsGeometry &clipGeom : constClipGeoms )
158 {
159 i++;
160 if ( feedback->isCanceled() )
161 {
162 break;
163 }
164 QgsFeatureIterator inputIt = featureSource->getFeatures( QgsFeatureRequest().setFilterRect( clipGeom.boundingBox() ) );
165 QgsFeatureList inputFeatures;
166 QgsFeature f;
167 while ( inputIt.nextFeature( f ) )
168 inputFeatures << f;
169
170 if ( inputFeatures.isEmpty() )
171 continue;
172
173 double step = 0;
174 if ( singleClipFeature )
175 step = 100.0 / inputFeatures.length();
176
177 const int current = 0;
178 const auto constInputFeatures = inputFeatures;
179 for ( const QgsFeature &inputFeature : constInputFeatures )
180 {
181 if ( feedback->isCanceled() )
182 {
183 break;
184 }
185
186 if ( !inputFeature.hasGeometry() )
187 continue;
188
189 if ( testedFeatureIds.contains( inputFeature.id() ) )
190 {
191 // don't retest a feature we have already checked
192 continue;
193 }
194 testedFeatureIds.insert( inputFeature.id() );
195
196 if ( !engine->intersects( inputFeature.geometry().constGet() ) )
197 continue;
198
199 QgsGeometry newGeometry;
200 if ( !engine->contains( inputFeature.geometry().constGet() ) )
201 {
202 const QgsGeometry currentGeometry = inputFeature.geometry();
203 newGeometry = combinedClipGeom.intersection( currentGeometry );
205 {
206 const QgsGeometry intCom = inputFeature.geometry().combine( newGeometry );
207 const QgsGeometry intSym = inputFeature.geometry().symDifference( newGeometry );
208 newGeometry = intCom.difference( intSym );
209 }
210 }
211 else
212 {
213 // clip geometry totally contains feature geometry, so no need to perform intersection
214 newGeometry = inputFeature.geometry();
215 }
216
217 if ( !QgsOverlayUtils::sanitizeIntersectionResult( newGeometry, sinkType, QgsOverlayUtils::SanitizeFlag::DontPromotePointGeometryToMultiPoint ) )
218 continue;
219
220 QgsFeature outputFeature;
221 outputFeature.setGeometry( newGeometry );
222 outputFeature.setAttributes( inputFeature.attributes() );
223 if ( !sink->addFeature( outputFeature, QgsFeatureSink::FastInsert ) )
224 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
225
226
227 if ( singleClipFeature )
228 feedback->setProgress( current * step );
229 }
230
231 if ( !singleClipFeature )
232 {
233 // coarse progress report for multiple clip geometries
234 feedback->setProgress( 100.0 * static_cast<double>( i ) / clipGeoms.length() );
235 }
236 }
237
238 sink->finalize();
239
240 return outputs;
241}
242
@ VectorPolygon
Vector polygon layers.
Definition qgis.h:3536
@ NotPresent
No spatial index exists for the source.
Definition qgis.h:560
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
Definition qgis.h:358
QFlags< ProcessingAlgorithmFlag > ProcessingAlgorithmFlags
Flags indicating how and when an algorithm operates and should be exposed to users.
Definition qgis.h:3609
@ Unknown
Unknown.
Definition qgis.h:278
@ GeometryCollection
GeometryCollection.
Definition qgis.h:286
@ SupportsInPlaceEdits
Algorithm supports in-place editing.
Definition qgis.h:3590
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
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:58
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
QgsGeometry geometry
Definition qgsfeature.h:69
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:53
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:61
A geometry is the spatial representation of a feature.
QgsGeometry difference(const QgsGeometry &geometry, const QgsGeometryParameters &parameters=QgsGeometryParameters()) const
Returns a geometry representing the points making up this geometry that do not make up other.
QString lastError() const
Returns an error string referring to the last error encountered either when this geometry was created...
QgsGeometry combine(const QgsGeometry &geometry, const QgsGeometryParameters &parameters=QgsGeometryParameters()) const
Returns a geometry representing all the points in this geometry and other (a union geometry operation...
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QgsGeometry intersection(const QgsGeometry &geometry, const QgsGeometryParameters &parameters=QgsGeometryParameters()) const
Returns a geometry representing the points shared by this geometry and other.
QgsGeometry symDifference(const QgsGeometry &geometry, const QgsGeometryParameters &parameters=QgsGeometryParameters()) const
Returns a geometry representing the points making up this geometry that do not make up other.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
static QgsGeometry unaryUnion(const QVector< QgsGeometry > &geometries, const QgsGeometryParameters &parameters=QgsGeometryParameters())
Compute the unary union on a list of geometries.
Qgis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.).
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry, double precision=0.0, Qgis::GeosCreationFlags flags=Qgis::GeosCreationFlag::SkipEmptyInteriorRings)
Creates and returns a new geometry engine representing the specified geometry using precision on a gr...
Base class for all map layer types.
Definition qgsmaplayer.h:80
virtual Qgis::ProcessingAlgorithmFlags flags() const
Returns the flags indicating how and when the algorithm operates and should be exposed to users.
Contains information about the context in which a processing algorithm is executed.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
virtual void pushWarning(const QString &warning)
Pushes a warning informational message from the algorithm.
A feature sink output for processing algorithms.
An input feature source (such as vector layers) parameter for processing algorithms.
Represents a vector layer which manages a vector based dataset.
bool isSpatial() const final
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
static Qgis::WkbType promoteNonPointTypesToMulti(Qgis::WkbType type)
Promotes a WKB geometry type to its multi-type equivalent, with the exception of point geometry types...
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
QList< QgsFeature > QgsFeatureList
QSet< QgsFeatureId > QgsFeatureIds