QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsalgorithmmultidifference.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmmultidifference.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 
24 
25 
26 QString QgsMultiDifferenceAlgorithm::name() const
27 {
28  return QStringLiteral( "multidifference" );
29 }
30 
31 QString QgsMultiDifferenceAlgorithm::displayName() const
32 {
33  return QObject::tr( "Difference (multiple)" );
34 }
35 
36 QStringList QgsMultiDifferenceAlgorithm::tags() const
37 {
38  return QObject::tr( "difference,erase,not overlap" ).split( ',' );
39 }
40 
41 QString QgsMultiDifferenceAlgorithm::group() const
42 {
43  return QObject::tr( "Vector overlay" );
44 }
45 
46 QString QgsMultiDifferenceAlgorithm::groupId() const
47 {
48  return QStringLiteral( "vectoroverlay" );
49 }
50 
51 QString QgsMultiDifferenceAlgorithm::shortHelpString() const
52 {
53  return QObject::tr( "This algorithm extracts features from the Input layer that fall completely outside or only partially overlap the features from any of the Overlay layer(s). "
54  "For each overlay layer the difference is calculated between the result of all previous difference operations and this overlay layer. "
55  "Input layer features that partially overlap feature(s) in the Overlay layers are split along those features' boundary "
56  "and only the portions outside the Overlay layer features are retained." )
57  + QStringLiteral( "\n\n" )
58  + QObject::tr( "Attributes are not modified, although properties such as area or length of the features will "
59  "be modified by the difference operation. If such properties are stored as attributes, those attributes will have to "
60  "be manually updated." );
61 }
62 
63 QgsProcessingAlgorithm *QgsMultiDifferenceAlgorithm::createInstance() const
64 {
65  return new QgsMultiDifferenceAlgorithm();
66 }
67 
68 void QgsMultiDifferenceAlgorithm::initAlgorithm( const QVariantMap & )
69 {
70  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
71  addParameter( new QgsProcessingParameterMultipleLayers( QStringLiteral( "OVERLAYS" ), QObject::tr( "Overlay layers" ), QgsProcessing::TypeVectorAnyGeometry ) );
72  addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Difference" ) ) );
73 }
74 
75 
76 QVariantMap QgsMultiDifferenceAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
77 {
78  std::unique_ptr< QgsFeatureSource > sourceA( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
79  if ( !sourceA )
80  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
81 
82  const QList< QgsMapLayer * > layers = parameterAsLayerList( parameters, QStringLiteral( "OVERLAYS" ), context );
83 
84  // loop through overlay layers and check whether they are vectors
85  long totalLayerCount = 0;
86  for ( QgsMapLayer *layer : layers )
87  {
88  if ( feedback->isCanceled() )
89  break;
90 
91  if ( !layer )
92  throw QgsProcessingException( QObject::tr( "Error retrieving map layer." ) );
93 
94  if ( layer->type() != QgsMapLayerType::VectorLayer )
95  throw QgsProcessingException( QObject::tr( "All layers must be vector layers!" ) );
96 
97  totalLayerCount++;
98  }
99 
100  const QgsWkbTypes::Type geometryType = QgsWkbTypes::multiType( sourceA->wkbType() );
101  const QgsCoordinateReferenceSystem crs = sourceA->sourceCrs();
102  std::unique_ptr< QgsFeatureSink > sink;
103  long count = 0;
104  QVariantMap outputs;
105 
106  if ( totalLayerCount == 1 )
107  {
108  QString dest;
109  sink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, sourceA->fields(), geometryType, crs ) );
110  if ( !sink )
111  throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
112 
113  outputs.insert( QStringLiteral( "OUTPUT" ), dest );
114 
115  QgsVectorLayer *overlayLayer = qobject_cast< QgsVectorLayer * >( layers.at( 0 ) );
116 
117  const long total = sourceA->featureCount();
118  QgsOverlayUtils::difference( *sourceA, *overlayLayer, *sink, context, feedback, count, total, QgsOverlayUtils::OutputA );
119  }
120  else
121  {
122  QgsProcessingMultiStepFeedback multiStepFeedback( totalLayerCount, feedback );
123  QgsVectorLayer *differenceLayer = nullptr;
124 
125  long i = 0;
126  for ( QgsMapLayer *layer : layers )
127  {
128  if ( feedback->isCanceled() )
129  break;
130 
131  multiStepFeedback.setCurrentStep( i );
132 
133  if ( !layer )
134  continue;
135 
136  QgsVectorLayer *overlayLayer = qobject_cast< QgsVectorLayer * >( layer );
137  if ( !overlayLayer )
138  continue;
139 
140  count = 0;
141  if ( i == 0 )
142  {
143  QString id = QStringLiteral( "memory:" );
144  sink.reset( QgsProcessingUtils::createFeatureSink( id, context, sourceA->fields(), geometryType, crs ) );
145  QgsOverlayUtils::difference( *sourceA, *overlayLayer, *sink, context, &multiStepFeedback, count, sourceA->featureCount(), QgsOverlayUtils::OutputA );
146 
147  differenceLayer = qobject_cast< QgsVectorLayer * >( QgsProcessingUtils::mapLayerFromString( id, context ) );
148  }
149  else if ( i == totalLayerCount - 1 )
150  {
151  QString dest;
152  std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, differenceLayer->fields(), geometryType, crs ) );
153  if ( !sink )
154  throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
155 
156  outputs.insert( QStringLiteral( "OUTPUT" ), dest );
157 
158  QgsOverlayUtils::difference( *differenceLayer, *overlayLayer, *sink, context, &multiStepFeedback, count, differenceLayer->featureCount(), QgsOverlayUtils::OutputA );
159  }
160  else
161  {
162  QString id = QStringLiteral( "memory:" );
163  sink.reset( QgsProcessingUtils::createFeatureSink( id, context, differenceLayer->fields(), geometryType, crs ) );
164  QgsOverlayUtils::difference( *differenceLayer, *overlayLayer, *sink, context, &multiStepFeedback, count, differenceLayer->featureCount(), QgsOverlayUtils::OutputA );
165 
166  differenceLayer = qobject_cast< QgsVectorLayer * >( QgsProcessingUtils::mapLayerFromString( id, context ) );
167  }
168 
169  i++;
170  }
171  }
172 
173  return outputs;
174 }
175 
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
QgsFeedback::isCanceled
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:67
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
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
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
QgsProcessing::TypeVectorAnyGeometry
@ TypeVectorAnyGeometry
Any vector layer with geometry.
Definition: qgsprocessing.h:48
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
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
qgsalgorithmmultidifference.h
QgsProcessingException
Custom exception class for processing related exceptions.
Definition: qgsexception.h:82