I'm creating lines by selecting two features from various layers. When I create a line a form pops up. In this form I want to display data from the start and end features of the line. What I'm currently doing is retrieving the vertices as point :
geom = feature.geometry ()
line = geom.asPolyline ()
pointFather = ligne[0]
pointChild = ligne[-1]
then I get the coordinates of each point :
xf = pointFather.x()
yf = pointFather.y()
and then I look into each possible layer to find the features with the same coordinates, just to retrieve the features I just clicked on !
for layer in layerList:
provider = layer.dataProvider()
iter = provider.getFeatures()
for feature in iter:
geom = feature.geometry().asPoint()
if geom.x() == xf and geom.y() == yf:
It must be something easier to do to directly retrieve the start and end features, isn't it ?
EDIT 1 :
here is my try after PCamargo first answer :
def retrieve_feature_from_xy(geom,point,layerList):
for layer in layerList:
index = QgsSpatialIndex()
iter = layer.getFeatures()
for feat in iter:
index.insertFeature(feat)
ids = index.intersects(geom.boundingBox())
request = QgsFeatureRequest()
request.setFilterFids(ids)
iter = layer.getFeatures(request)
for feat in iter:
geom2 = feat.geometry().asPoint()
if geom2.x() == point.x() and geom2.y() == point.y():
return feat
EDIT 2 :
Here is my try after PCamargo second comment :
def retrieve_feature_from_xy2(geom,point,layerList):
allfeatures = {}
indexes=[]
ids=[]
for layer in layerList:
index = QgsSpatialIndex()
iter = layer.getFeatures()
for feat in iter:
index.insertFeature(feat)
allfeatures[feat.id()]=feat
indexes.append(index)
for index in indexes:
intersect_ids = index.intersects(geom.boundingBox())
ids.append(intersect_ids)
for id in ids:
for i in id:
feat=allfeatures[i]
geom2=feat.geometry().asPoint()
if geom2.x() == point.x() and geom2.y() == point.y():
return feat
EDIT 3
Here is my try after PCamargo third comment :
def retrieve_feature_from_xy3(geom,point,layerList):
allfeatures = {}
indexes=[]
ids=[]
indexDict = {}
intersectsIdsDict = {}
for layer in layerList:
index = QgsSpatialIndex()
iter = layer.getFeatures()
for feat in iter:
index.insertFeature(feat)
allfeatures[layer,feat.id()]=feat
indexes.append(index)
indexDict[layer]=index
for layer, index in indexDict.items():
intersectsIds = index.intersects(geom.boundingBox())
intersectsIdsDict[layer]=intersectsIds
for layer, index in intersectsIdsDict.items():
for id in index:
feat = allfeatures[layer,id]
geom2=feat.geometry().asPoint()
if geom2.x() == point.x() and geom2.y() == point.y():
return feat
Chris,
You can definitely improve the look for similar coordinates (Third part of the code).
Instead of looping through all features in each layer, create a spatial index (https://docs.qgis.org/2.2/en/docs/pyqgis_developer_cookbook/vector.html#using-spatial-index) for each link and use nearestNeighbor.
It would be something like this:
Now that we have the indexes, we can use faster geographic search.
intersect_ids is a smaller list of features that are candidates to be equivalent, so you can compare only these features with the feature you selected.
You need to organize this a bit more, but that is the idea