26using namespace Qt::StringLiterals;
30QString QgsDeleteDuplicateGeometriesAlgorithm::name()
const
32 return u
"deleteduplicategeometries"_s;
35QString QgsDeleteDuplicateGeometriesAlgorithm::displayName()
const
37 return QObject::tr(
"Delete duplicate geometries" );
40QStringList QgsDeleteDuplicateGeometriesAlgorithm::tags()
const
42 return QObject::tr(
"drop,remove,same,points,coincident,overlapping,filter" ).split(
',' );
45QString QgsDeleteDuplicateGeometriesAlgorithm::group()
const
47 return QObject::tr(
"Vector general" );
50QString QgsDeleteDuplicateGeometriesAlgorithm::groupId()
const
52 return u
"vectorgeneral"_s;
55void QgsDeleteDuplicateGeometriesAlgorithm::initAlgorithm(
const QVariantMap & )
62 addParameter( duplicatesOutput );
65 addOutput(
new QgsProcessingOutputNumber( u
"DUPLICATE_COUNT"_s, QObject::tr(
"Count of discarded duplicate records" ) ) );
68QString QgsDeleteDuplicateGeometriesAlgorithm::shortHelpString()
const
71 "This algorithm finds duplicated geometries and removes them.\n\nAttributes are not checked, "
72 "so in case two features have identical geometries but different attributes, only one of "
73 "them will be added to the result layer.\n\n"
74 "Optionally, these duplicate features can be saved to a separate output for analysis."
78QString QgsDeleteDuplicateGeometriesAlgorithm::shortDescription()
const
80 return QObject::tr(
"Finds duplicated geometries in a layer and removes them." );
83QgsDeleteDuplicateGeometriesAlgorithm *QgsDeleteDuplicateGeometriesAlgorithm::createInstance()
const
85 return new QgsDeleteDuplicateGeometriesAlgorithm();
90 mSource.reset( parameterAsSource( parameters, u
"INPUT"_s, context ) );
99 QGS_MARK_ALGORITHM_SOURCE
102 std::unique_ptr<QgsFeatureSink> sink( parameterAsSink( parameters, u
"OUTPUT"_s, context, destId, mSource->fields(), mSource->wkbType(), mSource->sourceCrs() ) );
107 std::unique_ptr<QgsFeatureSink> dupesSink( parameterAsSink( parameters, u
"DUPLICATES"_s, context, dupesSinkId, mSource->fields(), mSource->wkbType(), mSource->sourceCrs() ) );
111 double step = mSource->featureCount() > 0 ? 100.0 / mSource->featureCount() : 0;
112 QHash<QgsFeatureId, QgsGeometry> geometries;
113 QSet<QgsFeatureId> nullGeometryFeatures;
121 nullGeometryFeatures.insert( f.
id() );
130 feedback->
setProgress( 0.10 *
static_cast<double>( current ) * step );
137 QHash<QgsFeatureId, QgsGeometry> uniqueFeatures = geometries;
138 QHash<QgsFeatureId, QgsGeometry> duplicateFeatures;
142 for (
auto it = geometries.constBegin(); it != geometries.constEnd(); ++it )
150 if ( !uniqueFeatures.contains( featureId ) )
156 const QList<QgsFeatureId> candidates = index.intersects( geometry.
boundingBox() );
160 if ( candidateId == featureId )
163 if ( !uniqueFeatures.contains( candidateId ) )
171 const QgsGeometry candidateGeom = geometries.value( candidateId );
175 uniqueFeatures.remove( candidateId );
178 duplicateFeatures.insert( candidateId, candidateGeom );
186 feedback->
setProgress( 0.80 *
static_cast<double>( current ) * step + 10 );
191 QSet<QgsFeatureId> outputFeatureIds = qgis::listToSet( uniqueFeatures.keys() );
192 outputFeatureIds.unite( nullGeometryFeatures );
193 step = outputFeatureIds.empty() ? 1 : 100.0 / outputFeatureIds.size();
194 const double stepTime = dupesSink ? 0.05 : 0.10;
205 if ( !nullGeometryFeatures.contains( f.id() ) )
207 f.setGeometry( uniqueFeatures.value( f.id() ) );
215 feedback->
setProgress( stepTime *
static_cast<double>( current ) * step + 90 );
218 feedback->
pushInfo( QObject::tr(
"%n duplicate feature(s) removed",
nullptr, removed ) );
226 QSet<QgsFeatureId> duplicateFeatureIds = qgis::listToSet( duplicateFeatures.keys() );
227 step = duplicateFeatureIds.empty() ? 1 : 100.0 / duplicateFeatureIds.size();
238 f.setGeometry( duplicateFeatures.value( f.id() ) );
245 feedback->
setProgress( 0.05 *
static_cast<double>( current ) * step + 95 );
248 dupesSink->finalize();
253 outputs.insert( u
"OUTPUT"_s, destId );
254 outputs.insert( u
"DUPLICATE_COUNT"_s,
static_cast<long long>( removed ) );
255 outputs.insert( u
"RETAINED_COUNT"_s, outputFeatureIds.size() );
258 outputs.insert( u
"DUPLICATES"_s, dupesSinkId );
@ VectorAnyGeometry
Any vector layer with geometry.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
@ SkipGeometryValidityChecks
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets the feature IDs that should be fetched.
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
bool hasGeometry() const
Returns true if the feature has an associated geometry.
bool isCanceled() const
Tells whether the operation has been canceled already.
void setProgress(double progress)
Sets the current progress for the feedback object.
A geometry is the spatial representation of a feature.
bool isTopologicallyEqual(const QgsGeometry &geometry, Qgis::GeometryBackend backend=Qgis::GeometryBackend::GEOS) const
Compares the geometry with another geometry using the specified backend.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Contains information about the context in which a processing algorithm is executed.
void setCreateByDefault(bool createByDefault)
Sets whether the destination should be created by default.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
void featureAddedToSink(const QString &output)
Reports that a feature was added to the the sink associated with the specified algorithm output.
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
void featureSinkFinalized(const QString &output)
Reports that a feature sink has been finalized.
A numeric output for processing algorithms.
A feature sink output for processing algorithms.
An input feature source (such as vector layers) parameter for processing algorithms.
A spatial index for QgsFeature objects.
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
QList< int > QgsAttributeList