QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
Loading...
Searching...
No Matches
qgsalgorithmmultiintersection.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmmultiintersection.cpp
3 ------------------
4 begin : December 2021
5 copyright : (C) 2021 by Alexander Bruy
6 email : alexander dot bruy 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
19
20#include "qgsoverlayutils.h"
21#include "qgsvectorlayer.h"
22
23#include <QString>
24
25using namespace Qt::StringLiterals;
26
28
29
30QString QgsMultiIntersectionAlgorithm::name() const
31{
32 return u"multiintersection"_s;
33}
34
35QString QgsMultiIntersectionAlgorithm::displayName() const
36{
37 return QObject::tr( "Intersection (multiple)" );
38}
39
40QStringList QgsMultiIntersectionAlgorithm::tags() const
41{
42 return QObject::tr( "intersection,extract,overlap" ).split( ',' );
43}
44
45QString QgsMultiIntersectionAlgorithm::group() const
46{
47 return QObject::tr( "Vector overlay" );
48}
49
50QString QgsMultiIntersectionAlgorithm::groupId() const
51{
52 return u"vectoroverlay"_s;
53}
54
55QString QgsMultiIntersectionAlgorithm::shortHelpString() const
56{
57 return QObject::tr(
58 "This algorithm extracts the overlapping portions of features in the Input and all Overlay layers. "
59 "Features in the output layer are assigned the attributes of the overlapping features "
60 "from both the Input and Overlay layers."
61 );
62}
63
64QString QgsMultiIntersectionAlgorithm::shortDescription() const
65{
66 return QObject::tr( "Extracts portions of input features that overlap features from all other layers." );
67}
68
69Qgis::ProcessingAlgorithmDocumentationFlags QgsMultiIntersectionAlgorithm::documentationFlags() const
70{
72}
73
74QgsProcessingAlgorithm *QgsMultiIntersectionAlgorithm::createInstance() const
75{
76 return new QgsMultiIntersectionAlgorithm();
77}
78
79void QgsMultiIntersectionAlgorithm::initAlgorithm( const QVariantMap & )
80{
81 addParameter( new QgsProcessingParameterFeatureSource( u"INPUT"_s, QObject::tr( "Input layer" ) ) );
82 addParameter( new QgsProcessingParameterMultipleLayers( u"OVERLAYS"_s, QObject::tr( "Overlay layers" ), Qgis::ProcessingSourceType::VectorAnyGeometry ) );
83
84 auto prefix = std::make_unique<QgsProcessingParameterString>( u"OVERLAY_FIELDS_PREFIX"_s, QObject::tr( "Overlay fields prefix" ), QString(), false, true );
85 prefix->setFlags( prefix->flags() | Qgis::ProcessingParameterFlag::Advanced );
86 addParameter( prefix.release() );
87
88 addParameter( new QgsProcessingParameterFeatureSink( u"OUTPUT"_s, QObject::tr( "Intersection" ) ) );
89}
90
91QVariantMap QgsMultiIntersectionAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
92{
93 std::unique_ptr<QgsFeatureSource> sourceA( parameterAsSource( parameters, u"INPUT"_s, context ) );
94 if ( !sourceA )
95 throw QgsProcessingException( invalidSourceError( parameters, u"INPUT"_s ) );
96
97 const QList<QgsMapLayer *> layers = parameterAsLayerList( parameters, u"OVERLAYS"_s, context );
98
99 // loop through overlay layers and check whether they are vectors
100 long totalLayerCount = 0;
101 for ( QgsMapLayer *layer : layers )
102 {
103 if ( feedback->isCanceled() )
104 break;
105
106 if ( !layer )
107 throw QgsProcessingException( QObject::tr( "Error retrieving map layer." ) );
108
109 if ( layer->type() != Qgis::LayerType::Vector )
110 throw QgsProcessingException( QObject::tr( "All layers must be vector layers!" ) );
111
112 totalLayerCount++;
113 }
114
115 const QString overlayFieldsPrefix = parameterAsString( parameters, u"OVERLAY_FIELDS_PREFIX"_s, context );
116
117 const Qgis::WkbType geometryType = QgsWkbTypes::multiType( sourceA->wkbType() );
118 const QgsCoordinateReferenceSystem crs = sourceA->sourceCrs();
119 std::unique_ptr<QgsFeatureSink> sink;
120 long count = 0;
121 QVariantMap outputs;
122
123 QList<int> fieldIndicesA, fieldIndicesB;
124 QgsFields outputFields;
125
126 if ( totalLayerCount == 1 )
127 {
128 QgsVectorLayer *overlayLayer = qobject_cast<QgsVectorLayer *>( layers.at( 0 ) );
129
130 fieldIndicesA = QgsProcessingUtils::fieldNamesToIndices( QStringList(), sourceA->fields() );
131 fieldIndicesB = QgsProcessingUtils::fieldNamesToIndices( QStringList(), overlayLayer->fields() );
132
133 outputFields = QgsProcessingUtils::
134 combineFields( QgsProcessingUtils::indicesToFields( fieldIndicesA, sourceA->fields() ), QgsProcessingUtils::indicesToFields( fieldIndicesB, overlayLayer->fields() ), overlayFieldsPrefix );
135
136 QString dest;
137 sink.reset( parameterAsSink( parameters, u"OUTPUT"_s, context, dest, outputFields, geometryType, crs, QgsFeatureSink::RegeneratePrimaryKey ) );
138 if ( !sink )
139 throw QgsProcessingException( invalidSinkError( parameters, u"OUTPUT"_s ) );
140
141 outputs.insert( u"OUTPUT"_s, dest );
142
143 const long total = sourceA->featureCount();
144 QgsOverlayUtils::intersection( *sourceA, *overlayLayer, *sink, context, feedback, count, total, fieldIndicesA, fieldIndicesB );
145
146 sink->finalize();
147 }
148 else
149 {
150 QgsProcessingMultiStepFeedback multiStepFeedback( totalLayerCount, feedback );
151 QgsVectorLayer *intersectionLayer = nullptr;
152
153 long i = 0;
154 for ( QgsMapLayer *layer : layers )
155 {
156 if ( feedback->isCanceled() )
157 break;
158
159 multiStepFeedback.setCurrentStep( i );
160
161 if ( !layer )
162 continue;
163
164 QgsVectorLayer *overlayLayer = qobject_cast<QgsVectorLayer *>( layer );
165 if ( !overlayLayer )
166 continue;
167
168 count = 0;
169 if ( i == 0 )
170 {
171 fieldIndicesA = QgsProcessingUtils::fieldNamesToIndices( QStringList(), sourceA->fields() );
172 fieldIndicesB = QgsProcessingUtils::fieldNamesToIndices( QStringList(), overlayLayer->fields() );
173
174 outputFields = QgsProcessingUtils::
175 combineFields( QgsProcessingUtils::indicesToFields( fieldIndicesA, sourceA->fields() ), QgsProcessingUtils::indicesToFields( fieldIndicesB, overlayLayer->fields() ), overlayFieldsPrefix );
176
177 QString id = u"memory:"_s;
178 sink.reset( QgsProcessingUtils::createFeatureSink( id, context, outputFields, geometryType, crs ) );
179 QgsOverlayUtils::intersection( *sourceA, *overlayLayer, *sink, context, &multiStepFeedback, count, sourceA->featureCount(), fieldIndicesA, fieldIndicesB );
180
181 intersectionLayer = qobject_cast<QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( id, context ) );
182 }
183 else if ( i == totalLayerCount - 1 )
184 {
185 fieldIndicesA = QgsProcessingUtils::fieldNamesToIndices( QStringList(), intersectionLayer->fields() );
186 fieldIndicesB = QgsProcessingUtils::fieldNamesToIndices( QStringList(), overlayLayer->fields() );
187
188 outputFields = QgsProcessingUtils::
189 combineFields( QgsProcessingUtils::indicesToFields( fieldIndicesA, intersectionLayer->fields() ), QgsProcessingUtils::indicesToFields( fieldIndicesB, overlayLayer->fields() ), overlayFieldsPrefix );
190
191 QString dest;
192 std::unique_ptr<QgsFeatureSink> sink( parameterAsSink( parameters, u"OUTPUT"_s, context, dest, outputFields, geometryType, crs ) );
193 if ( !sink )
194 throw QgsProcessingException( invalidSinkError( parameters, u"OUTPUT"_s ) );
195
196 outputs.insert( u"OUTPUT"_s, dest );
197
198 QgsOverlayUtils::intersection( *intersectionLayer, *overlayLayer, *sink, context, &multiStepFeedback, count, intersectionLayer->featureCount(), fieldIndicesA, fieldIndicesB );
199 }
200 else
201 {
202 fieldIndicesA = QgsProcessingUtils::fieldNamesToIndices( QStringList(), intersectionLayer->fields() );
203 fieldIndicesB = QgsProcessingUtils::fieldNamesToIndices( QStringList(), overlayLayer->fields() );
204
205 outputFields = QgsProcessingUtils::
206 combineFields( QgsProcessingUtils::indicesToFields( fieldIndicesA, intersectionLayer->fields() ), QgsProcessingUtils::indicesToFields( fieldIndicesB, overlayLayer->fields() ), overlayFieldsPrefix );
207
208 QString id = u"memory:"_s;
209 sink.reset( QgsProcessingUtils::createFeatureSink( id, context, outputFields, geometryType, crs ) );
210 QgsOverlayUtils::intersection( *intersectionLayer, *overlayLayer, *sink, context, &multiStepFeedback, count, intersectionLayer->featureCount(), fieldIndicesA, fieldIndicesB );
211
212 intersectionLayer = qobject_cast<QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( id, context ) );
213 }
214
215 i++;
216 }
217 }
218
219 return outputs;
220}
221
@ VectorAnyGeometry
Any vector layer with geometry.
Definition qgis.h:3647
@ RegeneratesPrimaryKey
Algorithm always drops any existing primary keys or FID values and regenerates them in outputs.
Definition qgis.h:3734
@ Vector
Vector layer.
Definition qgis.h:207
QFlags< ProcessingAlgorithmDocumentationFlag > ProcessingAlgorithmDocumentationFlags
Flags describing algorithm behavior for documentation purposes.
Definition qgis.h:3745
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:294
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
Definition qgis.h:3880
Represents a coordinate reference system (CRS).
@ RegeneratePrimaryKey
This flag indicates, that a primary key field cannot be guaranteed to be unique and the sink should i...
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:56
Container of fields for a vector layer.
Definition qgsfields.h:46
Base class for all map layer types.
Definition qgsmaplayer.h:83
Abstract base class for processing algorithms.
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
Processing feedback object for multi-step operations.
A feature sink output for processing algorithms.
An input feature source (such as vector layers) parameter for processing algorithms.
A parameter for processing algorithms which accepts multiple map layers.
static QgsFields indicesToFields(const QList< int > &indices, const QgsFields &fields)
Returns a subset of fields based on the indices of desired fields.
static QList< int > fieldNamesToIndices(const QStringList &fieldNames, const QgsFields &fields)
Returns a list of field indices parsed from the given list of field names.
static QgsFields combineFields(const QgsFields &fieldsA, const QgsFields &fieldsB, const QString &fieldsBPrefix=QString())
Combines two field lists, avoiding duplicate field names (in a case-insensitive manner).
static QgsFeatureSink * createFeatureSink(QString &destination, QgsProcessingContext &context, const QgsFields &fields, Qgis::WkbType geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &createOptions=QVariantMap(), const QStringList &datasourceOptions=QStringList(), const QStringList &layerOptions=QStringList(), QgsFeatureSink::SinkFlags sinkFlags=QgsFeatureSink::SinkFlags(), QgsRemappingSinkDefinition *remappingDefinition=nullptr)
Creates a feature sink ready for adding features.
static QgsMapLayer * mapLayerFromString(const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers=true, QgsProcessingUtils::LayerHint typeHint=QgsProcessingUtils::LayerHint::UnknownType, QgsProcessing::LayerOptionsFlags flags=QgsProcessing::LayerOptionsFlags())
Interprets a string as a map layer within the supplied context.
Represents a vector layer which manages a vector based dataset.
long long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
static Qgis::WkbType multiType(Qgis::WkbType type)
Returns the multi type for a WKB type.