# How to add Direction and Distance to attribute table?

anyone who can help. i just want to add direction (Bearing: i.e N 25 35 E) and Distance (Length: 125 meters) as my new field in polyline/line data. is there a plug-in to generate these fields? i tried to used "export/add geometry columns" in my line data, but only "Length" value was added.

Thanks

-
So far I can use the mmqgis plugin to give me distance. Am exploring the direction problem. –  Willy Apr 28 '12 at 10:03
What does your polyline data look like? Distance is relatively easy to calculate - however, 'bearing' may change over the length of a polyline. Are you looking for bearing from start point to endpoint? –  Simbamangu Apr 28 '12 at 14:07
Yes, im looking for bearing from start point to end point... thanks –  arzandia Apr 29 '12 at 8:52
Do you want straight-line distance from startpoint to endpoint, or length of line following the path of the line? These could vary widely if the line segment has intermediate curves or other changes of direction. –  RyanDalton Apr 30 '12 at 15:09

You can calculate bearing in the Field Calculator in QGIS 1.9; the xat(n) function doesn't seem to be working in 1.7.x at the moment. This works in UTM (metric) coordinates over small distances (hundreds of km), but something more sophisticated would be needed for large distances or for decimal degrees.

Open the attribute table for your line layer, toggle editing, and click the Field Calculator button to open the dialog:

Create a new field as decimal with 1 or 2 precision.

Paste this code into the "Expression" box, and click "OK": (atan((xat(-1)-xat(0))/(yat(-1)-yat(0)))) * 180/3.14159 + (180 *(((yat(-1)-yat(0)) < 0) + (((xat(-1)-xat(0)) < 0 AND (yat(-1) - yat(0)) >0)*2)))

The first part calculates the inverse tangent of the x and y differences and converts it to degrees (180/pi). The second part adds either 180 or 360 to the resulting figure to give a bearing from 0-360°.

-
A most elegant solution, thanks. I'd mention that if you need to determine the bearing for each segment of a polyline you can do this by splitting the line shapefile with the 'Split Feature' plug-in. Then load the new (split) shapefile and follow the above procedure. –  nhopton Apr 29 '12 at 11:17
@arzandia - note that you MUST be using QGIS 1.9 (see the home page for beta downloads) as the xat() and yat() functions don't work in 1.7, which you are using! –  Simbamangu Apr 29 '12 at 11:31
i already used the plug in you have mentioned. as you can see the image, the layer's name is "splitted"... –  arzandia Apr 29 '12 at 12:10
@nhopton - i appreciate the comment re split feature, I needed that! –  Willy Apr 30 '12 at 9:13
I think the questioner(?) should mark this as the answer. –  Willy Apr 30 '12 at 9:14

You do not need a plugin. Everything is in the class QgsPoint of PyQGIS

If you examine the contents of a QGIS point class with the Python built-in function dir() in the Python Console.

dir(point])
['__class__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__'
, '__getitem__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__module__',
'__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__', 'azimuth',
'multiply', 'set', 'setX', 'setY', 'sqrDist', 'sqrDistToSegment', 'toDegreesMinutesSeconds', 'toString', 'wellKnownText', 'x', 'y']


You can see there are azimuth and sqrDist functions and after a few tries:

- xy[0].azimuth(xy[1]) or xy[1].azimuth(xy[0]) gives the azimuth direction between two points(in degrees, +/- 180°)
- xy[0].sqrDist(xy[1]) give the square distance between two points (in the unit of the project)


The problem

So in the Python console

def select_all(layer):
layer.select([])
layer.setSelectedFeatures([obj.id() for obj in layer])

myline = qgis.utils.iface.activeLayer()
select_all(myline)
for elem in myline.selectedFeatures():
xy = elem.geometry().asPolyline()


now xy contains all the nodes (points) of the line

# first point
print "x=%2d y=%2d" % (xy[0].x(),xy[0].y())
x=112935 y=117784
# and others...


Using all node points of the line:

1) azimuth point i to point i + 1 (+/- 180°) (nodes of a line)

for i in range(len(xy)-1):
print "x=%2d y=%2d azim=%6.1f azim2=%6.1f" % (xy[i].x(), xy[i].y(), xy[i].azimuth(xy[i+1]), xy[i+1].azimuth(xy[i]))

x=112935 y=117784 azim= 168.4 azim2= -11.6
x=113032 y=117312 azim=-167.5 azim2=  12.5
x=112926 y=116835 azim= 177.3 azim2=  -2.7
x=112943 y=116472 azim= 145.1 azim2= -34.9
[...]


2) euclidean distance between point i and point i + 1

for i in range(len(xy)-1):
print "x=%2d y=%2d dist=%6.1f" % (xy[i].x(), xy[i].y(), xy[i].sqrDist(xy[i+1]))

x=112935 y=117784 dist=232533.9
x=113032 y=117311 dist=238243.6
x=112926 y=116835 dist=131839.8
x=112943 y=116472 dist=209268.1
[...]


After, it is not very difficult to add these values to the attribute table.

I use this technique to analyze the lineaments (geology) with matplotlib and the Script Runner plugin

-
+1 - Nice solution! Must ... learn ... Python ... –  Simbamangu May 1 '12 at 4:08