The following Python code iterates over all features in search_lyr
looking for intersecting features in poly_lyr
. Assuming that poly_lyr
has an attribut fid, a comma separated list of fid
will be written to a field fids
of the search feature.
search_lyr = QgsMapLayerRegistry.instance().mapLayersByName('kklip')[0]
# poly_lyr has an attribut fid with numbers
poly_lyr = QgsMapLayerRegistry.instance().mapLayersByName('gminy')[0]
# get fieldnames and their indices
prov = search_lyr.dataProvider()
fnm = prov.fieldNameMap()
# get fieldindex
fni = search_lyr.fieldNameIndex('fids')
for r in search_lyr.getFeatures():
# get the rectangular search area; it is assumed for simplicity that the
# search geometry is a rect and is equal to its bounding box
searchRect = QgsRectangle(r.geometry().boundingBox())
request = QgsFeatureRequest().setFilterRect(searchRect)
# write fids of selected features to a list, add save list to field fids
selection = [feat['fid'] for feat in poly_lyr.getFeatures(request)]
prov.changeAttributeValues({r.id(): {fni: str(selection).strip('[]')}})

If your search features are of arbitrary shape use the following loop:
# holds the attributes to update with
attributes = {}
# loop over search features
for r in search_lyr.getFeatures():
selection = []
# loop over the features to search in
for feat in poly_lyr.getFeatures():
# when geometries are intersecting append fid to the list
if r.geometry().intersects(feat.geometry()):
selection.append(feat['fid'])
# add the list of selected id's to the dict
attributes[r.id()] = {fni: str(selection).strip('[]')}
# finally write attributes
prov.changeAttributeValues(attributes)
When you have many polygons with complex shape this code is not very efficient, because many complex comparisons are made with disjoint features as well. One way to overcome this would be to create a temporary memory layer holding the bounding boxes of the features to search in, and check, as in the first code snipped above, if the bounding boxes are intersecting. If so, then go into details and check (according the second code snipped), if the real geometries are intersecting.
For this version replace the for-loop with this code:
# define QGIS layer to hold bounding boxes and original feature ids
box_lyr = QgsVectorLayer('Polygon?crs=EPSG:4326&field=oid:int', 'boxes', 'memory')
box_prov = box_lyr.dataProvider()
boxes = []
# create and write bounding boxes to memory layer
for feat in poly_lyr.getFeatures():
box = QgsFeature()
box.setGeometry(QgsGeometry.fromRect(feat.geometry().boundingBox()))
box.setAttributes([feat.id()])
boxes.append(box)
box_prov.addFeatures(boxes)
# now run a first quick search using the bounding boxes
for r in search_lyr.getFeatures():
searchRect = QgsRectangle(r.geometry().boundingBox())
request = QgsFeatureRequest().setFilterRect(searchRect)
preselection = [feat['oid'] for feat in box_lyr.getFeatures(request)]
# select all feature whose bounding boxes intersects
poly_lyr.setSelectedFeatures(preselection)
# and check if the real geometry also intersects
selection = [feat['fid'] for feat in poly_lyr.selectedFeatures() if r.geometry().intersects(feat.geometry())]
attributes[r.id()] = {fni: str(selection).strip('[]')}
# write list of ids to attribute
prov.changeAttributeValues(attributes)
poly_lyr.triggerRepaint()
# clean references
box_prov = None
box_lyr = None
