I am trying to find all points in a vector layer that do not have a duplicate point.
To do this, for each point I create a list of features that intersect its bounding box ('candidates') then check if any candidate is an exact geometry match. I've included the exact code below.
However, no matter how I tweak the code I don't end up with any duplicate points. I know for a fact there are many duplicate points (various topology checks and knowledge of dataset) so there's something wrong.
Is this an issue with using the bounding box, or another part of my code?
I'm using Python because every existing tool I've found only flags duplicates, but tool suggestions are fine too.
Working with QGIS 3.4x64 and Python 3.7 on Windows 10.
geoms = {} # { vertex id : geom }
for v in point_layer.getFeatures():
if not v.hasGeometry():
continue
geoms[v.id()] = v.geometry()
index = QgsSpatialIndex()
no_dup = [] #list of vertex IDs with no duplicates
for v_id, geometry in geoms.items():
candidates = index.intersects(geometry.boundingBox())
duplicates = []
for candidate_id in candidates:
if geometry.isGeosEqual(geoms[candidate_id]):
duplicates.append(v_id)
if len(duplicates) == 1: #only one point in location
no_dup.append(v_id)
Note: I considered creating a buffer instead of using the boundary box but I have over 100k features and would prefer not to create another layer
2 Answers 2
Solved: I hadn't populated the QgsSpatialIndex properly.
index = QgsSpatialIndex()
geoms = {} # { vertex id : geom }
for v in point_layer.getFeatures():
if not v.hasGeometry():
continue
geoms[v.id()] = v.geometry() #pop vertex geoms dict
index.addFeature(v)
You could use equals() :
geoms = {}
point_layer = iface.activeLayer()
for v in point_layer.getFeatures():
if not v.hasGeometry():
continue
geoms[v.id()] = v.geometry()
no_dup = []
for v_id1, geom1 in geoms.items():
i = 0
for v_id2, geom2 in geoms.items():
if v_id1 != v_id2 and geom1.equals(geom2):
i += 1
if i == 0:
no_dup.append(v_id)
print('nb {}'.format(len(no_dup)))
-
You can replace geom1.equals(geom2) by geom1.intersects(geom1.buffer(10, 12))) if you want to check equality within a 10 meters buffer (without creating any layer). Check QGIS API to discover available QgsGeometry methods : qgis.org/api/classQgsGeometry.htmlsigeal– sigeal2019年02月12日 19:58:40 +00:00Commented Feb 12, 2019 at 19:58
-
1I need to compare 100k+ points, if I use .equals() on so many features QGIS crashes.evilpie– evilpie2019年02月12日 20:12:15 +00:00Commented Feb 12, 2019 at 20:12