QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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 "qgsgeometrycollection.h"
21 #include "qgsgeometryengine.h"
22 #include "qgsoverlayutils.h"
23 #include "qgsvectorlayer.h"
24 
26 
27 
28 QString QgsMultiIntersectionAlgorithm::name() const
29 {
30  return QStringLiteral( "multiintersection" );
31 }
32 
33 QString QgsMultiIntersectionAlgorithm::displayName() const
34 {
35  return QObject::tr( "Intersection (multiple)" );
36 }
37 
38 QStringList QgsMultiIntersectionAlgorithm::tags() const
39 {
40  return QObject::tr( "intersection,extract,overlap" ).split( ',' );
41 }
42 
43 QString QgsMultiIntersectionAlgorithm::group() const
44 {
45  return QObject::tr( "Vector overlay" );
46 }
47 
48 QString QgsMultiIntersectionAlgorithm::groupId() const
49 {
50  return QStringLiteral( "vectoroverlay" );
51 }
52 
53 QString 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 
60 QgsProcessingAlgorithm *QgsMultiIntersectionAlgorithm::createInstance() const
61 {
62  return new QgsMultiIntersectionAlgorithm();
63 }
64 
65 void 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 
77 QVariantMap 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 
119  outputFields = QgsProcessingUtils::combineFields(
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 
160  outputFields = QgsProcessingUtils::combineFields(
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 
176  outputFields = QgsProcessingUtils::combineFields(
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 
195  outputFields = QgsProcessingUtils::combineFields(
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 
QgsProcessingUtils::createFeatureSink
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.
Definition: qgsprocessingutils.cpp:792
QgsMapLayerType::VectorLayer
@ VectorLayer
Vector layer.
QgsProcessingFeedback
Base class for providing feedback from a processing algorithm.
Definition: qgsprocessingfeedback.h:37
QgsVectorLayer::featureCount
long long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
Definition: qgsvectorlayer.cpp:812
crs
const QgsCoordinateReferenceSystem & crs
Definition: qgswfsgetfeature.cpp:105
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:44
QgsProcessingUtils::indicesToFields
static QgsFields indicesToFields(const QList< int > &indices, const QgsFields &fields)
Returns a subset of fields based on the indices of desired fields.
Definition: qgsprocessingutils.cpp:1297
QgsFeedback::isCanceled
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:67
QgsProcessingParameterDefinition::FlagAdvanced
@ FlagAdvanced
Parameter is an advanced parameter which should be hidden from users by default.
Definition: qgsprocessingparameters.h:451
QgsProcessingParameterFeatureSource
An input feature source (such as vector layers) parameter for processing algorithms.
Definition: qgsprocessingparameters.h:3057
QgsWkbTypes::Type
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:69
QgsWkbTypes::multiType
static Type multiType(Type type) SIP_HOLDGIL
Returns the multi type for a WKB type.
Definition: qgswkbtypes.h:304
QgsProcessingParameterMultipleLayers
A parameter for processing algorithms which accepts multiple map layers.
Definition: qgsprocessingparameters.h:2097
QgsProcessingUtils::combineFields
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).
Definition: qgsprocessingutils.cpp:1238
QgsProcessingParameterFeatureSink
A feature sink output for processing algorithms.
Definition: qgsprocessingparameters.h:3219
QgsVectorLayer::fields
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Definition: qgsvectorlayer.cpp:3436
qgsgeometryengine.h
QgsProcessingMultiStepFeedback
Processing feedback object for multi-step operations.
Definition: qgsprocessingfeedback.h:166
QgsProcessingContext
Contains information about the context in which a processing algorithm is executed.
Definition: qgsprocessingcontext.h:46
QgsProcessingUtils::fieldNamesToIndices
static QList< int > fieldNamesToIndices(const QStringList &fieldNames, const QgsFields &fields)
Returns a list of field indices parsed from the given list of field names.
Definition: qgsprocessingutils.cpp:1274
qgsalgorithmmultiintersection.h
QgsProcessing::TypeVectorAnyGeometry
@ TypeVectorAnyGeometry
Any vector layer with geometry.
Definition: qgsprocessing.h:48
QgsFeatureSink::RegeneratePrimaryKey
@ RegeneratePrimaryKey
This flag indicates, that a primary key field cannot be guaranteed to be unique and the sink should i...
Definition: qgsfeaturesink.h:55
QgsCoordinateReferenceSystem
This class represents a coordinate reference system (CRS).
Definition: qgscoordinatereferencesystem.h:211
qgsvectorlayer.h
QgsProcessingAlgorithm
Abstract base class for processing algorithms.
Definition: qgsprocessingalgorithm.h:52
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:391
QgsMapLayer
Base class for all map layer types. This is the base class for all map layer types (vector,...
Definition: qgsmaplayer.h:72
qgsgeometrycollection.h
QgsProcessingUtils::mapLayerFromString
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.
Definition: qgsprocessingutils.cpp:376
qgsoverlayutils.h
QgsProcessingException
Custom exception class for processing related exceptions.
Definition: qgsexception.h:82