26QString QgsDeleteDuplicateGeometriesAlgorithm::name()
const
28 return QStringLiteral(
"deleteduplicategeometries" );
31QString QgsDeleteDuplicateGeometriesAlgorithm::displayName()
const
33 return QObject::tr(
"Delete duplicate geometries" );
36QStringList QgsDeleteDuplicateGeometriesAlgorithm::tags()
const
38 return QObject::tr(
"drop,remove,same,points,coincident,overlapping,filter" ).split(
',' );
41QString QgsDeleteDuplicateGeometriesAlgorithm::group()
const
43 return QObject::tr(
"Vector general" );
46QString QgsDeleteDuplicateGeometriesAlgorithm::groupId()
const
48 return QStringLiteral(
"vectorgeneral" );
51void QgsDeleteDuplicateGeometriesAlgorithm::initAlgorithm(
const QVariantMap & )
58 addParameter( duplicatesOutput );
60 addOutput(
new QgsProcessingOutputNumber( QStringLiteral(
"RETAINED_COUNT" ), QObject::tr(
"Count of retained records" ) ) );
61 addOutput(
new QgsProcessingOutputNumber( QStringLiteral(
"DUPLICATE_COUNT" ), QObject::tr(
"Count of discarded duplicate records" ) ) );
64QString QgsDeleteDuplicateGeometriesAlgorithm::shortHelpString()
const
66 return QObject::tr(
"This algorithm finds duplicated geometries and removes them.\n\nAttributes are not checked, "
67 "so in case two features have identical geometries but different attributes, only one of "
68 "them will be added to the result layer.\n\n"
69 "Optionally, these duplicate features can be saved to a separate output for analysis." );
72QString QgsDeleteDuplicateGeometriesAlgorithm::shortDescription()
const
74 return QObject::tr(
"Finds duplicated geometries in a layer and removes them." );
77QgsDeleteDuplicateGeometriesAlgorithm *QgsDeleteDuplicateGeometriesAlgorithm::createInstance()
const
79 return new QgsDeleteDuplicateGeometriesAlgorithm();
84 mSource.reset( parameterAsSource( parameters, QStringLiteral(
"INPUT" ), context ) );
94 std::unique_ptr<QgsFeatureSink> sink( parameterAsSink( parameters, QStringLiteral(
"OUTPUT" ), context, destId, mSource->fields(), mSource->wkbType(), mSource->sourceCrs() ) );
99 std::unique_ptr<QgsFeatureSink> dupesSink( parameterAsSink( parameters, QStringLiteral(
"DUPLICATES" ), context, dupesSinkId, mSource->fields(), mSource->wkbType(), mSource->sourceCrs() ) );
103 double step = mSource->featureCount() > 0 ? 100.0 / mSource->featureCount() : 0;
104 QHash<QgsFeatureId, QgsGeometry> geometries;
105 QSet<QgsFeatureId> nullGeometryFeatures;
113 nullGeometryFeatures.insert( f.
id() );
122 feedback->
setProgress( 0.10 *
static_cast<double>( current ) * step );
129 QHash<QgsFeatureId, QgsGeometry> uniqueFeatures = geometries;
130 QHash<QgsFeatureId, QgsGeometry> duplicateFeatures;
134 for (
auto it = geometries.constBegin(); it != geometries.constEnd(); ++it )
142 if ( !uniqueFeatures.contains( featureId ) )
148 const QList<QgsFeatureId> candidates = index.intersects( geometry.
boundingBox() );
152 if ( candidateId == featureId )
155 if ( !uniqueFeatures.contains( candidateId ) )
163 const QgsGeometry candidateGeom = geometries.value( candidateId );
167 uniqueFeatures.remove( candidateId );
170 duplicateFeatures.insert( candidateId, candidateGeom );
178 feedback->
setProgress( 0.80 *
static_cast<double>( current ) * step + 10 );
183 QSet<QgsFeatureId> outputFeatureIds = qgis::listToSet( uniqueFeatures.keys() );
184 outputFeatureIds.unite( nullGeometryFeatures );
185 step = outputFeatureIds.empty() ? 1 : 100.0 / outputFeatureIds.size();
186 const double stepTime = dupesSink ? 0.05 : 0.10;
197 if ( !nullGeometryFeatures.contains( f.id() ) )
199 f.setGeometry( uniqueFeatures.value( f.id() ) );
205 feedback->
setProgress( stepTime *
static_cast<double>( current ) * step + 90 );
208 feedback->
pushInfo( QObject::tr(
"%n duplicate feature(s) removed",
nullptr, removed ) );
215 QSet<QgsFeatureId> duplicateFeatureIds = qgis::listToSet( duplicateFeatures.keys() );
216 step = duplicateFeatureIds.empty() ? 1 : 100.0 / duplicateFeatureIds.size();
227 f.setGeometry( duplicateFeatures.value( f.id() ) );
229 throw QgsProcessingException( writeFeatureError( dupesSink.get(), parameters, QStringLiteral(
"DUPLICATES" ) ) );
232 feedback->
setProgress( 0.05 *
static_cast<double>( current ) * step + 95 );
235 dupesSink->finalize();
239 outputs.insert( QStringLiteral(
"OUTPUT" ), destId );
240 outputs.insert( QStringLiteral(
"DUPLICATE_COUNT" ),
static_cast<long long>( removed ) );
241 outputs.insert( QStringLiteral(
"RETAINED_COUNT" ), outputFeatureIds.size() );
244 outputs.insert( QStringLiteral(
"DUPLICATES" ), 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.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
bool isGeosEqual(const QgsGeometry &) const
Compares the geometry with another geometry using GEOS.
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.
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
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