I want to use PyQGIS in QGIS 2.18 to add a new field to a vector (line) layer and calculate the bearings for each feature as i have been able to do easily in the field calculator using the expression
concat(floor(degrees(azimuth(start_point($geometry), end_point($geometry)))), '° ',
floor(degrees(azimuth(start_point($geometry), end_point($geometry)))*60 % 60), ''' ',
degrees(azimuth(start_point($geometry), end_point($geometry)))*3600 % 60, '''')
The result of this expression is a string that displays the degrees, minute, seconds value
After a little research, i tried to carry out the task with this script which produced an error.(Actually i was able to use this script to create and update a field that shows the length of lines of the layer, using QVariant.Double and $length for the expression)
from PyQt4.QtCore import QVariant
from qgis.core import QgsField, QgsExpression, QgsFeature
vl = iface.activeLayer()
vl.startEditing()
myField = QgsField( 'Bearing', QVariant.String)
vl.dataProvider().addAttributes([myField])
vl.updateFields()
idx = vl.fieldNameIndex('Bearing')
#next step
exp = QgsExpression('
concat(floor(degrees(azimuth(start_point($geometry), end_point($geometry)))), '° ',
floor(degrees(azimuth(start_point($geometry), end_point($geometry)))*60 % 60), ''' ',
degrees(azimuth(start_point($geometry), end_point($geometry)))*3600 % 60, '''')')
exp.prepare( vl.pendingFields() )
for f in vl.getFeatures():
f[idx] = exp.evaluate( f )
vl.updateFeature( f )
vl.commitChanges()
Where am I going wrong?
Answer
You don't need this kind of expression if you want to work directly with PyQGIS. Following code does the same and it is more legible.
from PyQt4.QtCore import QVariant
import math
layer = iface.activeLayer()
myField = QgsField( 'Bearing', QVariant.String)
layer.dataProvider().addAttributes([myField])
layer.updateFields()
idx = layer.fieldNameIndex('Bearing')
layer.startEditing()
for feat in layer.getFeatures():
pt1 = feat.geometry().asPolyline()[0]
pt2 = feat.geometry().asPolyline()[1]
az = pt1.azimuth(pt2)
if az < 0:
az += 360
minutes = az%1.0*60
seconds = minutes%1.0*60
string = str(int(math.floor(az))) + "\xb0 " + str(int(math.floor(minutes))) + "' " + str(seconds) + "''"
feat[idx] = string
layer.updateFeature( feat )
layer.commitChanges()
I tried it out with shapefile of following image where it can be observed, after running above script, that 'with_form' field (calculated with your field expression) and 'Bearing' field are identical.
No comments:
Post a Comment