1

I have a point layer and a polygon layer (representing buildings). I created a buffer around the points and extracted those polygons which intersect the buffer.

Example

The points contain an attribute with a certain value (e.g. 100). The polygons also contain an attribute with varying values (e.g. 5.5, 7.9 etc.).

What I would like to do is to iterate the intersected polygons in terms of distance to the point (i.e. the polygon closest to the point would be first, the polygon second closest would be second etc.). And each time, the polygon value would subtract the point value until it can no longer be subtracted (it cannot be less than 0) in which case it should stop iterating.

If possible, it would also be ideal where if a polygon has been iterated over, a new field would contain a boolean value 1 and all those which have not been iterated over contain 0.

I'm hoping the result would look similar to this:

Result

How could this be achieved by either SQL (virtual layer) or PyQGIS?


The following are pieces of code which only extracts the intersected polygons at 200m from the points:

  • SQL

    SELECT * FROM 
    Buildings d, 
    point c
    WHERE ST_INTERSECTS(d.geometry, ST_BUFFER(c.geometry,200))
    

  • PyQGIS

    def func(point_layer, polygon_layer, spacing):
        # Create buffer
        buffer_layer = QgsVectorLayer("Polygon?crs=epsg:27700", 'Buffers' , "memory")
        with edit(buffer_layer):
            buffer_layer.addAttribute(QgsField('ID', QVariant.Int))
            feat_list = []
            for f in point_layer.getFeatures():
                poly = QgsFeature()
                f_buffer = f.geometry().buffer((spacing), 99)
                poly.setAttributes([1])
                poly.setGeometry(f_buffer)
                feat_list.append(poly)
            buffer_layer.addFeatures(feat_list)
        buffer_layer.updateExtents()
        buffer_layer.updateFields()
        QgsMapLayerRegistry.instance().addMapLayers(buffer_layer)
        # Intersect with polygon
        features = [feat for feat in polygon_layer.getFeatures()]
        ids = []
        for buffers in buffer_layer.getFeatures():
            for polygons in polygon_layer.getFeatures():
                if buffers.geometry().intersects(polygons.geometry()):
                    ids.append(polygons)
        intersect_layer = QgsVectorLayer("Polygon?crs=epsg:27700", 'Intersect', "memory")
        intersect_layer.dataProvider().addAttributes(polygon_layer.fields())
        with edit(intersect_layer):
            for feat in ids:
                feature = QgsFeature()
                feature.setGeometry(feat.geometry())
                feature.setAttributes(feat.attributes())
                intersect_layer.addFeature(feature)
        QgsMapLayerRegistry.instance().addMapLayer(intersect_layer)
    
    func(point_layer, polygon_layer, 200)
    
  • subtraction aside, when you say "The points contain an attribute with a certain value (e.g. 100)" does that mean this point you want the first 100 closest features in a 200 foot area? is the buffer around the point always the same? – ziggy Dec 5 '17 at 14:28
  • @ziggy - Apologies, the value does not mean the number of features. In reality, it's an electric supply/demand value (point = supply; polygons = demand). The buffer can change to any size defined by the user. Hope this makes it slightly clearer :) – Joseph Dec 5 '17 at 14:36
0

Managed to find a solution using PyQGIS with the following workflow:

  1. Iterate through the points and calculate the distance between point and polygons;
  2. If distance is within 200m, store the polygon feature and distance in a dictionary;
  3. Sort dictionary by values (i.e. distance) and store in a list;
  4. Iterate through the list and subtract the point value (100 ) with each polygon attribute value whilst adding a boolean value 1 in a new field;
  5. When the point value is 0 or less, add a boolean value of 0.

Code used:

with edit(intersect_layer):
    field_name = 'Result'
    idx = intersect_layer.fieldNameIndex(field_name)
    if idx != -1:
        intersect_layer.addAttribute(QgsField('Result', QVariant.Int))
    for point in point_layer.getFeatures():
        distance_dict = {}
        polygon_list = []
        point_value = 100
        for polygon in intersect_layer.getFeatures():
            distance = point.geometry().distance(polygon.geometry())
            if distance < 200:
                distance_dict[polygon] = distance
        distance_list = sorted(distance_dict.iterkeys(), key=(lambda key: distance_dict[key]))
        for feat in distance_list:
            point_value -= feat['Values']
            if point_value >= 0:
                feat['Result'] = 1
                intersect_layer.updateFeature(feat)
            else:
                feat['Result'] = 0
                intersect_layer.updateFeature(feat)

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.