Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I am trying to create points (new layer) at specific distance along the road (existing layer) in QGIS. Creating Regular points every meter at county level using ArcGIS Desktop? gives solution for ArcGIS. How to achieve this in QGIS? Adding points to point vector layer using QGIS? explains how to create points but does not do anything about the distance.


(I applied the proposed solutions with different measures of lengths for I did not know the conversion) @Nathans's solution worked to some extent, I got...

enter image description here. Here, the projection of these equidistant points is different from the original line.

With @underdark's suggestion, I got

this image where the points does not seem to be equidistant. I guess there is some projection issue with both of these which I am not understanding.

share|improve this question
1  
2  
A couple of points. Firstly, the line has to be in a projected CRS (not lat/lon). Secondly, is your line a true polyline? I don't think any method will work properly on a line comprising a string of individual lines. Nick. – nhopton Jun 10 '12 at 18:01
    
Also with my code, you don't need to call the import locate line more then once. Just call it once then you can call locate.pointsAlongLine(30) as much as you need – Nathan W Jun 11 '12 at 8:27
    
Another method (given that Sextant as suggested by some answers here is QGIS <2.0 only), is also to use the plugin called QChainage. – andy Jun 19 '14 at 13:30

Note: There is now a QGIS plugin QChainage. It does all this and more. The code below is out of date with QGIS 2.0 and above.

Here is some Python code that you can stick in a file and use inside QGIS:

QGIS does have a method in it API to do liner referencing however I couldn't get it to work correctly, but I will contact the author of the code and see if I was doing something wrong.

For now you will need the shapely Python library, which you should install anyway because it's handy to have around. It also has great documentation at http://toblerity.github.com/shapely/manual.html

This is the section I am using in the following example http://toblerity.github.com/shapely/manual.html#interoperation.

Most of the following code is QGIS boilerplate code just creating the features, layers, converting from wkb and wkt and back. The core bit is the point = line.interpolate(currentdistance) which returns a point at a distance along a line. We just wrap this in a loop until we run out of line.

import qgis
from qgis.core import *
from PyQt4.QtCore import QVariant
from shapely.wkb import loads
from shapely.wkt import dumps

vl = None
pr = None

def createPointsAt(distance, geom):
    if distance > geom.length():
        print "No Way Man!"
        return

    length = geom.length()
    currentdistance = distance
    feats = []  

    while currentdistance < length: 
        line = loads(geom.asWkb())
        point = line.interpolate(currentdistance)
        fet = QgsFeature()
        fet.setAttributeMap( { 0 : currentdistance } )
        qgsgeom = QgsGeometry.fromWkt(dumps(point))
        fet.setGeometry(qgsgeom)
        feats.append(fet)
        currentdistance = currentdistance + distance

    pr.addFeatures(feats)
    vl.updateExtents()

def pointsAlongLine(distance):
    global vl
    vl = QgsVectorLayer("Point", "distance nodes", "memory")
    global pr
    pr = vl.dataProvider()  
    pr.addAttributes( [ QgsField("distance", QVariant.Int) ] )
    layer = qgis.utils.iface.mapCanvas().currentLayer()
    for feature in layer.selectedFeatures():
        geom = feature.geometry()
        createPointsAt(distance, geom)

    QgsMapLayerRegistry.instance().addMapLayer(vl)

Copy and paste the above code into file, I called my locate.py, in ~./qgis/python directory (because it is in the Python path) and just do the this in the Python console inside QGIS.

 import locate
 locate.pointsAlongLine(30)

That will create a new point layer with points at every 30 meters along the selected lines, like so:

enter image description here

Note: Code is pretty rough and might need some clean up.

EDIT: The lastest QGIS dev build can now do this natively.

Change the while loop in createPointsAt to:

 while currentdistance < length: 
    point = geom.interpolate(distance)
    fet = QgsFeature()
    fet.setAttributeMap( { 0 : currentdistance } )
    fet.setGeometry(point)
    feats.append(fet)
    currentdistance = currentdistance + distance

and you can remove the

from shapely.wkb import loads
from shapely.wkt import dumps
share|improve this answer
    
Thanks @Nathan. I could not get the Shapely package for my python. I installed python 2.7 but Shapely installer says that python 2.7 is not in my registry. Is there another way to install Shapely. – Stat-R Jun 9 '12 at 18:23
    
I followed stackoverflow.com/questions/3652625/… and typed the above two lines for calling locate and using it but still I did not get the equidistant points. Also, I am a neophyte in Python so I did not understand where to run the code (1) python in qgis directory or (2) that at C:\Python27\? – Stat-R Jun 9 '12 at 21:34
    
What OS are you on? – Nathan W Jun 9 '12 at 21:51
    
Windows 7 Professional – Stat-R Jun 9 '12 at 21:58
    
create the python file in C:\Users\{you user name}\.qgis\python then restart QGIS if open, and go to ` Plugins-> Python Console. Load a line layer, select a line a call import locate` and locate.pointsAlongLine(30) – Nathan W Jun 9 '12 at 22:56

You could use the QGIS GRASS plugin v.to.points tool to create points along lines at regular intervals

# convert line to points; dmax = distance between points
v.to.points -i -v -t in=road out=road_pts type=line dmax=90
share|improve this answer
    
I used dmax as 100 and the resultant projections for each is as follows. (I do not know how the CRS is getting assigned by itself. ) CRS of Original Shape file, the line = EPSG:26915 - NAD83 / UTM zone 15N, CRS of Grass line vector obtained using v.in.ogr = EPSG:4269 - NAD83, CRS of Grass points vector obtained using v.to.points = EPSG:4326 - WGS 84 – Stat-R Jun 10 '12 at 18:20
    
Now also like this: QGIS -> Sextante -> GRASS -> v.to.points – markusN Sep 11 '12 at 15:03

If you want to plot the chainage at fixed intervals along a road line you could use the 'Profile from line' plug-in to do this. You need a DEM under the road line layer, but the procedure is quick and very simple. Nick.

enter image description here

share|improve this answer
    
this is a pretty good and easy method too, thanks! – Shepherdjo Jul 30 '12 at 9:50

Beware that the Shapely (Python) / GEOS (C++) data model is defined in a plane. So if your points consist of GPS positions (latitude, longitude) using the shapely.geometry.LineString.interpolate(distance) method will output a GPS position at the euclidean distance along the given LineString.

Shapely's interpolate() is based on GEOS' geos::linearref::LengthIndexedLine class using the extractPoint method.

Supposedly the equally spaced interpolation in the latitude-longitude-plane is sufficient for applications considering relatively small distances. In general, however, one should consider the distance on a sphere for GIS applications (as defined in WGS84).

I can think of two workarounds using the Shapely module:

  • LineString properties are all given points and linearly-interpolated curves along them. Perhaps you can write a member which accesses the interpolated curves and implement the following line integral substituting the euclidean distance. I fancy this approach because using the piece-wise continuous curve the desired points can be obtained by calculating the intersections of adjacent circles along the curve with the radius r = radian_measure(arc_length) = arc_length / R, where R equals Earths' radius at the given position.
  • code your own interpolation method (without touching Shapely code) using an appropriate distance function (eg. haversine formula).

To achieve this I would like refer to the following StackOverflow question and this answer in particular:

It IS possible to generate equidistant points along the curve. But there must be more definition of what you want for a real answer. Sorry, but the code I've written for this task is in MATLAB, but I can describe the general ideas. There are three possibilities.

First, are the points to be truly equidistant from the neighbors in terms of a simple Euclidean distance? To do so would involve finding the intersection at any point on the curve with a circle of a fixed radius. Then just step along the curve.

Next, if you intend distance to mean distance along the curve itself, if the curve is a piecewise linear one, the problem is again easy to do. Just step along the curve, since distance on a line segment is easy to measure.

Finally, if you intend for the curve to be a cubic spline, again this is not incredibly difficult, but is a bit more work. Here the trick is to:

  • Compute the piecewise linear arclength from point to point along the curve. Call it t. Generate a pair of cubic splines, x(t), y(t).

  • Differentiate x and y as functions of t. Since these are cubic segments, this is easy. The derivative functions will be piecewise
    quadratic.

  • Use an ode solver to move along the curve, integrating the differential arclength function. In MATLAB, ODE45 worked nicely.

Thus, one integrates

sqrt((x')^2 + (y')^2)

Again, in MATLAB, ODE45 can be set to identify those locations where the function crosses certain specified points.

If your MATLAB skills are up to the task, you can look at the code in interparc for more explanation. It is reasonably well commented code.

3: http://www.mathworks.com/matlabcentral/fileexchange/34874-interparc

share|improve this answer

Sextante has a tool that might work for you. Sextante can be downloaded from the Qgis plugin repository.

Look for:
"Tools for Line Layers"
"Lines to equispaced points"

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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