QGIS API Documentation 4.3.0-Master (d3b565c628d)
Loading...
Searching...
No Matches
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
23#include <QString>
24
25using namespace Qt::StringLiterals;
26
28
29
30QString QgsMultiDifferenceAlgorithm::name() const
31{
32 return u"multidifference"_s;
33}
34
35QString QgsMultiDifferenceAlgorithm::displayName() const
36{
37 return QObject::tr( "Difference (multiple)" );
38}
39
40QStringList QgsMultiDifferenceAlgorithm::tags() const
41{
42 return QObject::tr( "difference,erase,not overlap" ).split( ',' );
43}
44
45QString QgsMultiDifferenceAlgorithm::group() const
46{
47 return QObject::tr( "Vector overlay" );
48}
49
50QString QgsMultiDifferenceAlgorithm::groupId() const
51{
52 return u"vectoroverlay"_s;
53}
54
55QString QgsMultiDifferenceAlgorithm::shortHelpString() const
56{
57 return QObject::tr(
58 "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). "
59 "For each overlay layer the difference is calculated between the result of all previous difference operations and this overlay layer. "
60 "Input layer features that partially overlap feature(s) in the Overlay layers are split along those features' boundary "
61 "and only the portions outside the Overlay layer features are retained."
62 )
63 + u"\n\n"_s
64 + QObject::tr(
65 "Attributes are not modified, although properties such as area or length of the features will "
66 "be modified by the difference operation. If such properties are stored as attributes, those attributes will have to "
67 "be manually updated."
68 );
69}
70
71QString QgsMultiDifferenceAlgorithm::shortDescription() const
72{
73 return QObject::tr( "Extracts features from a layer that fall completely outside or only partially overlap the features from other layer(s)." );
74}
75
76QgsProcessingAlgorithm *QgsMultiDifferenceAlgorithm::createInstance() const
77{
78 return new QgsMultiDifferenceAlgorithm();
79}
80
81void QgsMultiDifferenceAlgorithm::initAlgorithm( const QVariantMap & )
82{
83 addParameter( new QgsProcessingParameterFeatureSource( u"INPUT"_s, QObject::tr( "Input layer" ) ) );
84 addParameter( new QgsProcessingParameterMultipleLayers( u"OVERLAYS"_s, QObject::tr( "Overlay layers" ), Qgis::ProcessingSourceType::VectorAnyGeometry ) );
85 addParameter( new QgsProcessingParameterFeatureSink( u"OUTPUT"_s, QObject::tr( "Difference" ) ) );
86}
87
88
89QVariantMap QgsMultiDifferenceAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
90{
91 QGS_MARK_ALGORITHM_SOURCE
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 Qgis::WkbType geometryType = QgsWkbTypes::multiType( sourceA->wkbType() );
116 const QgsCoordinateReferenceSystem crs = sourceA->sourceCrs();
117 std::unique_ptr<QgsFeatureSink> sink;
118 long count = 0;
119 QVariantMap outputs;
120
121 if ( totalLayerCount == 1 )
122 {
123 QString dest;
124 sink.reset( parameterAsSink( parameters, u"OUTPUT"_s, context, dest, sourceA->fields(), geometryType, crs ) );
125 if ( !sink )
126 throw QgsProcessingException( invalidSinkError( parameters, u"OUTPUT"_s ) );
127
128 outputs.insert( u"OUTPUT"_s, dest );
129
130 QgsVectorLayer *overlayLayer = qobject_cast<QgsVectorLayer *>( layers.at( 0 ) );
131
132 const long total = sourceA->featureCount();
133 QgsOverlayUtils::difference( *sourceA, *overlayLayer, *sink, u"OUTPUT"_s, context, feedback, count, total, QgsOverlayUtils::OutputA );
134 sink->finalize();
135 feedback->featureSinkFinalized( u"OUTPUT"_s );
136 }
137 else
138 {
139 QgsProcessingMultiStepFeedback multiStepFeedback( totalLayerCount, feedback );
140 QgsVectorLayer *differenceLayer = nullptr;
141
142 long i = 0;
143 for ( QgsMapLayer *layer : layers )
144 {
145 if ( feedback->isCanceled() )
146 break;
147
148 multiStepFeedback.setCurrentStep( i );
149
150 if ( !layer )
151 continue;
152
153 QgsVectorLayer *overlayLayer = qobject_cast<QgsVectorLayer *>( layer );
154 if ( !overlayLayer )
155 continue;
156
157 count = 0;
158 if ( i == 0 )
159 {
160 QString id = u"memory:"_s;
161 sink.reset( QgsProcessingUtils::createFeatureSink( id, context, sourceA->fields(), geometryType, crs ) );
162 QgsOverlayUtils::difference( *sourceA, *overlayLayer, *sink, QString(), context, &multiStepFeedback, count, sourceA->featureCount(), QgsOverlayUtils::OutputA );
163
164 differenceLayer = qobject_cast<QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( id, context ) );
165 }
166 else if ( i == totalLayerCount - 1 )
167 {
168 QString dest;
169 std::unique_ptr<QgsFeatureSink> sink( parameterAsSink( parameters, u"OUTPUT"_s, context, dest, differenceLayer->fields(), geometryType, crs ) );
170 if ( !sink )
171 throw QgsProcessingException( invalidSinkError( parameters, u"OUTPUT"_s ) );
172
173 outputs.insert( u"OUTPUT"_s, dest );
174
175 QgsOverlayUtils::difference( *differenceLayer, *overlayLayer, *sink, u"OUTPUT"_s, context, &multiStepFeedback, count, differenceLayer->featureCount(), QgsOverlayUtils::OutputA );
176 sink->finalize();
177 feedback->featureSinkFinalized( u"OUTPUT"_s );
178 }
179 else
180 {
181 QString id = u"memory:"_s;
182 sink.reset( QgsProcessingUtils::createFeatureSink( id, context, differenceLayer->fields(), geometryType, crs ) );
183 QgsOverlayUtils::difference( *differenceLayer, *overlayLayer, *sink, QString(), context, &multiStepFeedback, count, differenceLayer->featureCount(), QgsOverlayUtils::OutputA );
184
185 differenceLayer = qobject_cast<QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( id, context ) );
186 }
187
188 i++;
189 }
190 }
191
192 return outputs;
193}
194
@ VectorAnyGeometry
Any vector layer with geometry.
Definition qgis.h:3749
@ Vector
Vector layer.
Definition qgis.h:207
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:294
Represents a coordinate reference system (CRS).
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:56
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.
void featureSinkFinalized(const QString &output)
Reports that a feature sink has been finalized.
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 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.