diff --git a/python/plugins/processing/algs/qgis/DeleteDuplicateGeometries.py b/python/plugins/processing/algs/qgis/DeleteDuplicateGeometries.py index 122f420df2a..cc533b5cdd5 100644 --- a/python/plugins/processing/algs/qgis/DeleteDuplicateGeometries.py +++ b/python/plugins/processing/algs/qgis/DeleteDuplicateGeometries.py @@ -76,11 +76,16 @@ class DeleteDuplicateGeometries(QgisAlgorithm): total = 100.0 / source.featureCount() if source.featureCount() else 0 geoms = dict() + null_geom_features = set() index = QgsSpatialIndex() for current, f in enumerate(features): if feedback.isCanceled(): break + if not f.hasGeometry(): + null_geom_features.add(f.id()) + continue + geoms[f.id()] = f.geometry() index.addFeature(f) @@ -115,17 +120,20 @@ class DeleteDuplicateGeometries(QgisAlgorithm): current += 1 feedback.setProgress(int(0.80 * current * total) + 10) # takes about 80% of time - total = 100.0 / len(unique_features) if unique_features else 1 - # now, fetch all the feature attributes for the unique features only # be super-smart and don't re-fetch geometries - request = QgsFeatureRequest().setFilterFids(list(unique_features.keys())).setFlags(QgsFeatureRequest.NoGeometry) + distinct_geoms = set(unique_features.keys()) + output_feature_ids = distinct_geoms.union(null_geom_features) + total = 100.0 / len(output_feature_ids) if output_feature_ids else 1 + + request = QgsFeatureRequest().setFilterFids(list(output_feature_ids)).setFlags(QgsFeatureRequest.NoGeometry) for current, f in enumerate(source.getFeatures(request)): if feedback.isCanceled(): break # use already fetched geometry - f.setGeometry(unique_features[f.id()]) + if f.id() not in null_geom_features: + f.setGeometry(unique_features[f.id()]) sink.addFeature(f, QgsFeatureSink.FastInsert) feedback.setProgress(int(0.10 * current * total) + 90) # takes about 10% of time diff --git a/python/plugins/processing/tests/testdata/expected/delete_duplicates_with_nulls.gml b/python/plugins/processing/tests/testdata/expected/delete_duplicates_with_nulls.gml new file mode 100644 index 00000000000..7610daf5ed6 --- /dev/null +++ b/python/plugins/processing/tests/testdata/expected/delete_duplicates_with_nulls.gml @@ -0,0 +1,48 @@ + + + + + -1-3 + 115 + + + + + + 6,2 9,2 9,3 11,5 + + + + + -1,-1 1,-1 + + + + + 2,0 2,2 3,2 3,3 + + + + + 3,1 5,1 + + + + + 7,-3 10,-3 + + + + + 6,-3 10,1 + + + + + + + diff --git a/python/plugins/processing/tests/testdata/expected/delete_duplicates_with_nulls.xsd b/python/plugins/processing/tests/testdata/expected/delete_duplicates_with_nulls.xsd new file mode 100644 index 00000000000..1bedff81946 --- /dev/null +++ b/python/plugins/processing/tests/testdata/expected/delete_duplicates_with_nulls.xsd @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml index 1ef6a52172c..73ad4010cc9 100755 --- a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml +++ b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml @@ -6396,5 +6396,16 @@ tests: name: expected/split_linez_by_length.shp type: vector + - algorithm: qgis:deleteduplicategeometries + name: Delete Duplicates with null geometries + params: + INPUT: + name: lines.gml|layername=lines + type: vector + results: + OUTPUT: + name: expected/delete_duplicates_with_nulls.gml + type: vector + # See ../README.md for a description of the file format