[GIS] How to create equidistant points in QGIS along a polygon

pythonqgis

I am looking for a solution to distribute with a python script equidistant points in QGIS along a polygon. I tried to use the following code example:

http://nathanw.net/2012/08/05/generating-chainage-distance-nodes-in-qgis/

Using it in my example (running over each polygon from a polygon shape file):

# Reading a polygon layer
pp_layer = QgsVectorLayer("poly.shp" , "polylyr", "ogr")

# create layer to store result"
pntl = QgsVectorLayer("Point", "name", "memory") 
pr = pntl.dataProvider()  

for feature in pp_layer.selectedFeatures():
   geom = feature.geometry()

   currentdistance = self.distance
   feats = []    
   # geom.asPolyline()
   while currentdistance < length: 
      point = geom.interpolate(currentdistance)
      print point
      fet = QgsFeature()
      fet.setGeometry(point)
      feats.append(fet)
      currentdistance = currentdistance + self.distance
   pr.addFeatures(feats)

However, when running the code, if fails. I got an error message in the python console

Traceback (most recent call last):
File "<input>", line 1, in <module>
File "/home2/fun.py", line 92, in run_fun
fet.setGeometry(point)
TypeError: QgsFeature.setGeometry(QgsGeometry): argument 1 has unexpected type 'NoneType'

an I got an errormessage from qgis

    ERROR 1: IllegalArgumentException: LinearIterator only supports lineal geometry components

Does anyone has an idea, if i have an error in my code or is it not possible to solve the question with this approach? I am using QGIS 2.0.1.

Best Answer

You cannot use interpolate() with polygons:

If you have a polygon:

geom.exportToGeoJSON()
u'{ "type": "Polygon", "coordinates": [ [ [167546.39129160347511061, 156935.60758662305306643], [167464.55340823522419669, 154998.77768024150282145], [169183.148958968144143, 154698.70544122465071268], [167901.02211953248479404, 153498.41648515724227764], [167109.92258030621451326, 152734.59624038706533611], [165364.04773511723033153, 154725.98473568074405193], [167546.39129160347511061, 156935.60758662305306643] ] ] }'  
geom.asPolygon()
[[(167546,156936), (167465,154999), (169183,154699), (167901,153498), (167110,152735), (165364,154726), (167546,156936)]]
# interpolate
geom.interpolate(100).asPoint()
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'asPoint'

The LinearRing of the Polygon is:

LinearRing = QgsGeometry.fromPolyline(geom.asPolygon()[0])
LinearRing.exportToGeoJSON()
u'{ "type": "LineString", "coordinates": [ [167546.39129160347511061, 156935.60758662305306643], [167464.55340823522419669, 154998.77768024150282145], [169183.148958968144143, 154698.70544122465071268], [167901.02211953248479404, 153498.41648515724227764], [167109.92258030621451326, 152734.59624038706533611], [165364.04773511723033153, 154725.98473568074405193], [167546.39129160347511061, 156935.60758662305306643] ] }'
# interpolate
LinearRing.interpolate(100).asPoint()
(167542,156836)

Polygons:
enter image description here

Part of a class to create memory layers from the Python console:

class Crea_layer(object):
   def __init__(self,nom,type):
        self.type=type
        self.name = nom
        self.layer =  QgsVectorLayer(self.type, self.name , "memory")
        self.pr =self.layer.dataProvider() 
   def create_point(self,geometry):
        self.seg = QgsFeature()
        self.seg.setGeometry(QgsGeometry.fromPoint(geometry))
        self.pr.addFeatures([self.seg])
        self.layer.updateExtents()
   @property
   def show_layer(self):
        QgsMapLayerRegistry.instance().addMapLayers([self.layer])

Creation of the equidistant points (step = 100m)

polys = qgis.utils.iface.activeLayer()
points = Crea_layer("equidistant", "Point")
for feat in polys.getFeatures():
    geom = feat.geometry()
    line = QgsGeometry.fromPolyline(geom.asPolygon()[0])
    for distance in xrange(0,line.length(),100):
         point = line.interpolate(distance)
         point = point.asPoint()
         point.create_point(QgsPoint(point.x(),point.y()))

 points.show_layer

Result:

enter image description here