From 82c13bdde0ef447280cc299b6c48bbd4c83a7306 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 14 Dec 2018 12:09:29 +1000 Subject: [PATCH] [processing] Fix error when running delete duplicate geometries and some input features have null geometries Fixes #20788 --- .../algs/qgis/DeleteDuplicateGeometries.py | 16 +++++-- .../expected/delete_duplicates_with_nulls.gml | 48 +++++++++++++++++++ .../expected/delete_duplicates_with_nulls.xsd | 23 +++++++++ .../tests/testdata/qgis_algorithm_tests.yaml | 11 +++++ 4 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 python/plugins/processing/tests/testdata/expected/delete_duplicates_with_nulls.gml create mode 100644 python/plugins/processing/tests/testdata/expected/delete_duplicates_with_nulls.xsd 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