QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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
21#include "qgsgeometryengine.h"
22#include "qgsoverlayutils.h"
23#include "qgsvectorlayer.h"
24
26
27
28QString QgsMultiIntersectionAlgorithm::name() const
29{
30 return QStringLiteral( "multiintersection" );
31}
32
33QString QgsMultiIntersectionAlgorithm::displayName() const
34{
35 return QObject::tr( "Intersection (multiple)" );
36}
37
38QStringList QgsMultiIntersectionAlgorithm::tags() const
39{
40 return QObject::tr( "intersection,extract,overlap" ).split( ',' );
41}
42
43QString QgsMultiIntersectionAlgorithm::group() const
44{
45 return QObject::tr( "Vector overlay" );
46}
47
48QString QgsMultiIntersectionAlgorithm::groupId() const
49{
50 return QStringLiteral( "vectoroverlay" );
51}
52
53QString QgsMultiIntersectionAlgorithm::shortHelpString() const
54{
55 return QObject::tr( "This algorithm extracts the overlapping portions of features in the Input and all Overlay layers. "
56 "Features in the output layer are assigned the attributes of the overlapping features "
57 "from both the Input and Overlay layers." );
58}
59
60QgsProcessingAlgorithm *QgsMultiIntersectionAlgorithm::createInstance() const
61{
62 return new QgsMultiIntersectionAlgorithm();
63}
64
65void QgsMultiIntersectionAlgorithm::initAlgorithm( const QVariantMap & )
66{
67 addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
68 addParameter( new QgsProcessingParameterMultipleLayers( QStringLiteral( "OVERLAYS" ), QObject::tr( "Overlay layers" ), QgsProcessing::TypeVectorAnyGeometry ) );
69
70 std::unique_ptr< QgsProcessingParameterString > prefix = std::make_unique< QgsProcessingParameterString >( QStringLiteral( "OVERLAY_FIELDS_PREFIX" ), QObject::tr( "Overlay fields prefix" ), QString(), false, true );
71 prefix->setFlags( prefix->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
72 addParameter( prefix.release() );
73
74 addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Intersection" ) ) );
75}
76
77QVariantMap QgsMultiIntersectionAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
78{
79 std::unique_ptr< QgsFeatureSource > sourceA( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
80 if ( !sourceA )
81 throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
82
83 const QList< QgsMapLayer * > layers = parameterAsLayerList( parameters, QStringLiteral( "OVERLAYS" ), context );
84
85 // loop through overlay layers and check whether they are vectors
86 long totalLayerCount = 0;
87 for ( QgsMapLayer *layer : layers )
88 {
89 if ( feedback->isCanceled() )
90 break;
91
92 if ( !layer )
93 throw QgsProcessingException( QObject::tr( "Error retrieving map layer." ) );
94
95 if ( layer->type() != QgsMapLayerType::VectorLayer )
96 throw QgsProcessingException( QObject::tr( "All layers must be vector layers!" ) );
97
98 totalLayerCount++;
99 }
100
101 const QString overlayFieldsPrefix = parameterAsString( parameters, QStringLiteral( "OVERLAY_FIELDS_PREFIX" ), context );
102
103 const QgsWkbTypes::Type geometryType = QgsWkbTypes::multiType( sourceA->wkbType() );
104 const QgsCoordinateReferenceSystem crs = sourceA->sourceCrs();
105 std::unique_ptr< QgsFeatureSink > sink;
106 long count = 0;
107 QVariantMap outputs;
108
109 QList<int> fieldIndicesA, fieldIndicesB;
110 QgsFields outputFields;
111
112 if ( totalLayerCount == 1 )
113 {
114 QgsVectorLayer *overlayLayer = qobject_cast< QgsVectorLayer * >( layers.at( 0 ) );
115
116 fieldIndicesA = QgsProcessingUtils::fieldNamesToIndices( QStringList(), sourceA->fields() );
117 fieldIndicesB = QgsProcessingUtils::fieldNamesToIndices( QStringList(), overlayLayer->fields() );
118
120 QgsProcessingUtils::indicesToFields( fieldIndicesA, sourceA->fields() ),
121 QgsProcessingUtils::indicesToFields( fieldIndicesB, overlayLayer->fields() ),
122 overlayFieldsPrefix );
123
124 QString dest;
125 sink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, outputFields, geometryType, crs, QgsFeatureSink::RegeneratePrimaryKey ) );
126 if ( !sink )
127 throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
128
129 outputs.insert( QStringLiteral( "OUTPUT" ), dest );
130
131 const long total = sourceA->featureCount();
132 QgsOverlayUtils::intersection( *sourceA, *overlayLayer, *sink, context, feedback, count, total, fieldIndicesA, fieldIndicesB );
133 }
134 else
135 {
136 QgsProcessingMultiStepFeedback multiStepFeedback( totalLayerCount, feedback );
137 QgsVectorLayer *intersectionLayer = nullptr;
138
139 long i = 0;
140 for ( QgsMapLayer *layer : layers )
141 {
142 if ( feedback->isCanceled() )
143 break;
144
145 multiStepFeedback.setCurrentStep( i );
146
147 if ( !layer )
148 continue;
149
150 QgsVectorLayer *overlayLayer = qobject_cast< QgsVectorLayer * >( layer );
151 if ( !overlayLayer )
152 continue;
153
154 count = 0;
155 if ( i == 0 )
156 {
157 fieldIndicesA = QgsProcessingUtils::fieldNamesToIndices( QStringList(), sourceA->fields() );
158 fieldIndicesB = QgsProcessingUtils::fieldNamesToIndices( QStringList(), overlayLayer->fields() );
159
161 QgsProcessingUtils::indicesToFields( fieldIndicesA, sourceA->fields() ),
162 QgsProcessingUtils::indicesToFields( fieldIndicesB, overlayLayer->fields() ),
163 overlayFieldsPrefix );
164
165 QString id = QStringLiteral( "memory:" );
166 sink.reset( QgsProcessingUtils::createFeatureSink( id, context, outputFields, geometryType, crs ) );
167 QgsOverlayUtils::intersection( *sourceA, *overlayLayer, *sink, context, &multiStepFeedback, count, sourceA->featureCount(), fieldIndicesA, fieldIndicesB );
168
169 intersectionLayer = qobject_cast< QgsVectorLayer * >( QgsProcessingUtils::mapLayerFromString( id, context ) );
170 }
171 else if ( i == totalLayerCount - 1 )
172 {
173 fieldIndicesA = QgsProcessingUtils::fieldNamesToIndices( QStringList(), intersectionLayer->fields() );
174 fieldIndicesB = QgsProcessingUtils::fieldNamesToIndices( QStringList(), overlayLayer->fields() );
175
177 QgsProcessingUtils::indicesToFields( fieldIndicesA, intersectionLayer->fields() ),
178 QgsProcessingUtils::indicesToFields( fieldIndicesB, overlayLayer->fields() ),
179 overlayFieldsPrefix );
180
181 QString dest;
182 std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, outputFields, geometryType, crs ) );
183 if ( !sink )
184 throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
185
186 outputs.insert( QStringLiteral( "OUTPUT" ), dest );
187
188 QgsOverlayUtils::intersection( *intersectionLayer, *overlayLayer, *sink, context, &multiStepFeedback, count, intersectionLayer->featureCount(), fieldIndicesA, fieldIndicesB );
189 }
190 else
191 {
192 fieldIndicesA = QgsProcessingUtils::fieldNamesToIndices( QStringList(), intersectionLayer->fields() );
193 fieldIndicesB = QgsProcessingUtils::fieldNamesToIndices( QStringList(), overlayLayer->fields() );
194
196 QgsProcessingUtils::indicesToFields( fieldIndicesA, intersectionLayer->fields() ),
197 QgsProcessingUtils::indicesToFields( fieldIndicesB, overlayLayer->fields() ),
198 overlayFieldsPrefix );
199
200 QString id = QStringLiteral( "memory:" );
201 sink.reset( QgsProcessingUtils::createFeatureSink( id, context, outputFields, geometryType, crs ) );
202 QgsOverlayUtils::intersection( *intersectionLayer, *overlayLayer, *sink, context, &multiStepFeedback, count, intersectionLayer->featureCount(), fieldIndicesA, fieldIndicesB );
203
204 intersectionLayer = qobject_cast< QgsVectorLayer * >( QgsProcessingUtils::mapLayerFromString( id, context ) );
205 }
206
207 i++;
208 }
209 }
210
211 return outputs;
212}
213
This class 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 SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
Container of fields for a vector layer.
Definition: qgsfields.h:45
Base class for all map layer types.
Definition: qgsmaplayer.h:73
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.
Definition: qgsexception.h:83
Base class for providing feedback from a processing algorithm.
Processing feedback object for multi-step operations.
@ FlagAdvanced
Parameter is an advanced parameter which should be hidden from users by default.
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 QgsFeatureSink * createFeatureSink(QString &destination, QgsProcessingContext &context, const QgsFields &fields, QgsWkbTypes::Type 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 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 QgsMapLayer * mapLayerFromString(const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers=true, QgsProcessingUtils::LayerHint typeHint=QgsProcessingUtils::LayerHint::UnknownType)
Interprets a string as a map layer within the supplied context.
@ TypeVectorAnyGeometry
Any vector layer with geometry.
Definition: qgsprocessing.h:48
Represents a vector layer which manages a vector based data sets.
long long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
static Type multiType(Type type) SIP_HOLDGIL
Returns the multi type for a WKB type.
Definition: qgswkbtypes.h:304
@ VectorLayer
Vector layer.
const QgsCoordinateReferenceSystem & crs