1

I'm trying to join (to the rectangle) values from multiple polygons intersecting for this rectangle.

I've tried to use some Reference functions in Field Calculator like geomintersects() but it joins only one value.

Is there some possibility to iterate somehow this function to add all intersecting polygon values to the target column?

For egzample: smaller polygons have numbers like 1,2,3... Is there option to add to the target rectangle layer values of all intersecting polygons separated by comma?

I think it is possible in Python but I have little experience in this..

gminy

  • I don't know if the QGIS Spatial Join tool has the same functionality as the ArcGIS Spatial Join tool, but in ArcGIS I can use the Spatial Join tool with the One to One option. I can right click each attribute in a field list window and set the merge type to use the Join option. That option creates a list of attribute values from all features. I also have to change the field output type to a text field and set the length of the field to 255 characters. I also can set the delimiter, such as a comma or semi-colon. The list is unsorted with duplicates, so I recalc it to another field to sort – Richard Fairhurst Nov 6 '15 at 19:00
  • I realize my comment may not help QGIS users, but it does help ArcGIS desktop users that may read this trying to figure out how to solve a similar problem. – Richard Fairhurst Nov 6 '15 at 19:04
1

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('[]')}})

example

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

example_2

  • It worked fine, but in result column i got "u" character before every recorded match. I looks like this: u'2212092', u'2215052', u'2215042', u'2215082', u'2211062'. I Was wondering if it would be possible to do it on non-regular objects (not rectangles, squares)? – Jakub O Nov 9 '15 at 22:30
  • You got the u because your fids are stored as string encoded in UTF. To avoid this you can cast the string to integer when they are integers. Write in the forelast line int(feat['fid']). To use non-rect polygons you must write an inner loop over features of poly_lyr and check r.geometry().intersects(another_geometry()) – Detlev Nov 10 '15 at 17:55
  • I don't know python as much as it is necessary for this. But I'm learning! Please tell me more about this inner loop. What with this line then: searchRect = QgsRectangle(r.geometry().boundingBox())? – Jakub O Nov 10 '15 at 23:28
  • @JakubO I have improved the answer to honor your further question. – Detlev Nov 11 '15 at 10:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.