Computing road slope using elevation data

A common geospatial workflow is to assign raster values to a coincident vector layer so that you can style or perform further analysis on the vector layer. This recipe will use this concept to illustrate the steepness of a road using color by mapping values to the road vector from a slope raster.

Getting ready

You will need to download a zipped directory from https://geospatialpython.googlecode.com/svn/road.zip and place the directory, named road, in your qgis_data directory.

How to do it...

We'll start with a DEM and compute its slope. Then, we'll load a road vector layer and break it into interval lengths of 500 meters. Next, we'll load the layer and style it using green, yellow, and red values for each segment to show the range of steepness. We'll overlay this layer on a hillshade of the DEM for a nice visualization. To do this, we need to perform the following steps:

  1. First, we need to import the QGIS processing module, the QGIS constants module, the Qt GUI module, and the os module in the QGIS Python Console:
    from qgis.core import *
    from PyQt4.QtGui import *
    import processing
    
  2. Now, we need to set the coordinate reference system (CRS) of our project to that of our digital elevation model (DEM), which is EPSG code 26910, so we can work with the data in meters instead of decimal degrees:
    myCrs = QgsCoordinateReferenceSystem(26910, QgsCoordinateReferenceSystem.EpsgCrsId)
    iface.mapCanvas().mapRenderer().setDestinationCrs(myCrs)
    iface.mapCanvas().setMapUnits(QGis.Meters)
    iface.mapCanvas().refresh()
    
  3. Now, we'll set the paths of all the layers. For this, we'll use intermediate layers that we create so that we can change them in one place, if needed:
    src_dir = "/Users/joellawhead/qgis_data/road/" 
    dem = os.path.join(src_dir, "dem.asc")
    road = os.path.join(src_dir, "road.shp")
    slope = os.path.join(src_dir, "slope.tif")
    segRoad = os.path.join(src_dir, "segRoad.shp")
    steepness = os.path.join(src_dir, "steepness.shp")
    hillshade = os.path.join(src_dir, "hillshade.tif") 
    
  4. We will load the DEM and road layer so that we can get the extents for the processing algorithms:
    demLyr = QgsRasterLayer(dem, "DEM")
    roadLyr = QgsVectorLayer(road, "Road", "ogr")
    
  5. Now, build a string with the DEM extent using the following code:
    ext = demLyr.extent()
    xmin = ext.xMinimum()
    ymin = ext.yMinimum()
    xmax = ext.xMaximum()
    ymax = ext.yMaximum()
    demBox = "%s,%s,%s,%s" % (xmin,xmax,ymin,ymax)
    
  6. Next, compute the slope grid:
    processing.runalg("grass:r.slope",dem,0,0,1,0,True, demBox,0,slope)
    
  7. Then, we can get the extent of the road layer as a string:
    ext = roadLyr.extent()
    xmin = ext.xMinimum()
    ymin = ext.yMinimum()
    xmax = ext.xMaximum()
    ymax = ext.yMaximum()
    roadBox = "%s,%s,%s,%s" % (xmin,xmax,ymin,ymax)
    
  8. Now, we'll break the road layer into segments of 500 meters to have a meaningful length for the slope valuation:
    processing.runalg("grass:v.split.length",road,500,
    roadBox,-1,0.0001,0,segRoad)
    
  9. Next, we'll add the slope and segmented layer to the map interface for the next algorithm, but we'll keep them hidden from view using the boolean False option in the addMapLayers method:
    slopeLyr = QgsRasterLayer(slope, "Slope")
    segRoadLyr = QgsVectorLayer(segRoad, 
    "Segmented Road", "ogr")
    QgsMapLayerRegistry
    .instance().addMapLayers([ segRoadLyr,slopeLyr], False)
    
  10. Now, we can transfer the slope values to the segmented road layer in order to create the steepness layer:
    processing.runalg("saga:addgridvaluestoshapes", segRoad,slope,0,steepness)
    
  11. Now, we can load the steepness layer:
    steepLyr = QgsVectorLayer(steepness,  "Road Gradient", "ogr")
    
  12. We'll style the steepness layer to use the stoplight red, yellow, and green values, with red being the steepest:
    roadGrade = ( ("Rolling Hill", 0.0, 20.0, "green"), 
    ("Steep", 20.0, 40.0, "yellow"),
    ("Very Steep", 40.0, 90.0, "red"))
    ranges = []
    for label, lower, upper, color in roadGrade:
        sym = QgsSymbolV2.defaultSymbol(steepLyr.geometryType())
        sym.setColor(QColor(color))
        sym.setWidth(3.0)
        rng = QgsRendererRangeV2(lower, upper, sym, label)
        ranges.append(rng)
        
    field = "slope"
    renderer = QgsGraduatedSymbolRendererV2(field, ranges)
    steepLyr.setRendererV2(renderer)
    
  13. Next, we'll create a hillshade from the DEM for visualization and load everything onto the map:
    processing.runalg("saga:analyticalhillshading",dem,
    0,315,45,4,hillshade)
    hs = QgsRasterLayer(hillshade, "Terrain")
    QgsMapLayerRegistry.instance().addMapLayers([steepLyr, hs])
    

How it works...

For each of our 500-meter line segments, the algorithm averages the underlying slope values. This workflow is fairly simple and also provides all the building blocks you need for a more complex version. While performing calculations that involve measurements over a relatively small area, using projected data is the best option. The following image shows how the output looks:

How it works...
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset