3

QGIS version 2.18

I am trying to code a function that creates some multi ring buffer. The algorithm is as below:

  1. Take a feature
  2. Buffer it by a set of distances
  3. Do a difference of the buffer geometry minus the feature's geometry to keep the "ring" only
  4. Replace the initial feature by the "ring" and start again

the code is below throw works fine during the first buffer but then fall into error

def addRing(feature): 
    distances = [5,10,15]
    geom = feature.geometry()
    buffer_features = []
    for distance in distances:
        buffer = geom.buffer(distance,10)
        new_feature = QgsFeature()
        new_feature.setGeometry(buffer)

        new_feature_geom = new_feature.geometry()
        new_feature_clipped = new_feature_geom.difference(geom)

        new_buffer = QgsFeature()
        new_buffer.setGeometry(new_feature_clipped)
        #Add some fields and attribute data to the ring
        buffer_features.append(new_buffer)

        geom = new_feature.geometry()
    return buffer_features

The first ring is created but then I get the error:

QgsFeature.setGeometry(QgsGeometry): argument 1 has unexpected type 'NoneType'

Why? What is the correct way?

3

You shouldn't return features because you're working with geometries. It's totally redundant to create new features for setting same geometries. It's preferable to return geometries in WKT format. You can handle them easily later. I assume that next code matches your requirement:

layer = iface.activeLayer()

feature = layer.getFeatures().next()

def addRing(feature):

    distances = [5,10,15]

    rings = [ feature.geometry().buffer(distance,-1).difference(feature.geometry()).exportToWkt() 
              for distance in distances ]

    return rings

rings = addRing(feature)

for ring in rings:
    print ring

After running it at the Python Console of QGIS with next shapefile:

enter image description here

I visualized at Map Canvas the first ring printed at Python Console with the help of QuickWKT plugin.

enter image description here

Editing Note:

This is original Blue code's where were fixed all issues:

layer = iface.activeLayer()

feature = layer.getFeatures().next()

def addRing(feature): 
    distances = [5,10,15]

    buffer_features = []

    for distance in distances:
        buffer = feature.geometry().buffer(distance,10)
        new_feature = QgsFeature()
        new_feature.setGeometry(buffer)

        new_feature_geom = new_feature.geometry()
        new_feature_clipped = new_feature_geom.difference(feature.geometry())

        new_buffer = QgsFeature()
        new_buffer.setGeometry(new_feature_clipped)
        #Add some fields and attribute data to the ring
        buffer_features.append(new_buffer)

    return buffer_features

buffer_features = addRing(feature)

print buffer_features[0].geometry().exportToWkt()

After running above code at Python Console of QGIS it's obtained this equivalent result:

enter image description here

10
  • I am using features because for each ring I would like to add some distance information in an attribute field. Your answer is elegant but doesn t work in my case.
    – Blue
    Jul 11 '17 at 12:48
  • Your code doesn't work and it wont work if you insist to use a wrong approach. Distance information is gotten from geometric object. For this reason you first convert features in geometries. It's totally redundant to create new features for setting same geometries.
    – xunilk
    Jul 11 '17 at 13:15
  • I agree that it redundant to create a new feature and set the same geometry. How would you go about creating rings which have attribute of type texte? For example I have 100 features that I want "ring buffered" and each ring need to have a specific text attribute that way I can merge them down the track. I don't see why I couldn t return a list of features?
    – Blue
    Jul 11 '17 at 13:23
  • I don't completely understand your question. Are you referring to WKT format?
    – xunilk
    Jul 11 '17 at 13:30
  • Yes, you can return a list of features. I'll see later why your code doesn't work.
    – xunilk
    Jul 11 '17 at 13:40
1

Here is the working code:

def addRing(feature): 
    distances = [5,10,15]
    buffer_features = []
    for distance in distances:
        buffer = feature.geometry().buffer(distance,10)
        new_feature = QgsFeature()
        new_feature.setGeometry(buffer)

        new_feature_clipped = 
        new_feature.geometry().difference(feature.geometry() ) 
        feature.setGeometry(buffer)

        new_buffer = QgsFeature()
        new_buffer.setGeometry(new_feature_clipped)
        #Add some fields and attribute data to the ring

    return buffer_features

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.