2

The end goal is to add a point which will represent a mast/pylon of x height and for QGIS to generate polygons for the surrounding area which will have direct visibility of the top of the structure from ground level. (I'm using version 2.18.5). Woodland and buildings could make things more complicated, so to simplify we can just stick to the terrain/topography which leads to impeding visibility and tackle woodland at a later stage.

The image below is a perfect example of what I'm attempting to accomplish. It shows a nuclear power plant planned for the west coast of England in Cumbria. The highlighted yellow areas are zones of potential visibility. Is QGIS capable of such a thing? Browsing through the figures released for the power plant, it seemed they were all created in GIS software. The OS mini greyscale map being used as their base map in this case.

enter image description here

1

2 Answers 2

2

The task could be easily performed using the r.viewshed GRASS module available from the Processing Toolbox.

From its Documentation:

r.viewshed is a module that computes the viewshed of a point on a raster terrain. That is, given an elevation raster, and the location of an observer, it generates a raster output map showing which cells are visible from the given location. The algorithm underlying r.viewshed minimizes both the CPU operations and the transfer of data between main memory and disk; as a result r.viewshed runs fast on very large rasters.

For running the analysis, you only need a Digital Terrain Model and the coordinates of one point. This is an example of a possible output (the output is a raster):

enter image description here

If you want to programmatically perform the task for a point vector layer and using PyQGIS, you may simply use the following code as a reference, running it from the Python Console (it is available from Plugins >> Python Console):

import processing

rasterLayer =QgsRasterLayer('C:/path/to/point/layer/raster_layer.tif', 'raster')
pointLayer=QgsVectorLayer('C:/path/to/point/layer/point_layer.shp', 'points' , 'ogr')

# Get the extent from the raster layer
extent = rasterLayer.extent()
xmin = extent.xMinimum()
xmax = extent.xMaximum()
ymin = extent.yMinimum()
ymax = extent.yMaximum()
region_extent = "%f,%f,%f,%f" %(xmin, xmax, ymin, ymax) # set the extent for the output, which is equal to the extent of the input raster

i=0
for feat in pointLayer.getFeatures():
    point = feat.geometry().asPoint() # get the geometry for the current point feature
    coordStr = '%d,%d' % (point.x(),point.y()) # get the coordinates and store them in a string

    # set the path for the output raster
    outputViewshed = 'C:/path/to/the/output/output_raster_%i.tif' %(i)

    #running viewshed with observer elevation set at 20 m, target elevetion set to 0 m and a max distance of 800 m
    output = processing.runalg('grass7:r.viewshed', rasterLayer, coordStr, '20', '0', '800', 0.14286, 500, False, False, False, False, region_extent, 0, outputViewshed)
    i += 1

The outputs returned is a number of rasters that is equal to the number of the features from the point layer.

For knowing the syntax required by the r.viewshed module, you may simply run this code from the Python Console:

import processing
processing.alghelp('grass7:r.viewshed')

and you will obtain a brief description of each parameter (for a deeper understanding and the complete description of them, please refer to the documentation):

ALGORITHM: r.viewshed - Computes the viewshed of a point on an elevation raster map.
    input <ParameterRaster>
    coordinates <ParameterPoint>
    observer_elevation <ParameterString>
    target_elevation <ParameterString>
    max_distance <ParameterString>
    refraction_coeff <ParameterNumber>
    memory <ParameterNumber>
    -c <ParameterBoolean>
    -r <ParameterBoolean>
    -b <ParameterBoolean>
    -e <ParameterBoolean>
    GRASS_REGION_PARAMETER <ParameterExtent>
    GRASS_REGION_CELLSIZE_PARAMETER <ParameterNumber>
    output <OutputRaster>
1

you have three options ;-) which one is right for you will depend on size of raster and your specific requirements

  • grass r.viewshed . Limited to one point. Use via processing
  • Viewshed Analysis plugin . This allows multiple points, cumulative visibility, and intervisibility vectors for point layers.
  • saga visibility, via processing. Also allows multiple points and adds an option to set visible cells to the distance.

I find the plugin is the most flexible and is fairly fast. It's also got very good documentation.

6
  • Thanks for the suggestion. Will the plugin allow me to set a height to the point as well? If so that's it cracked
    – James B
    May 8, 2017 at 17:41
  • @JamesB Using r.viewshed, you can set the height for both the observer elevation and the target elevation.
    – mgri
    May 8, 2017 at 18:14
  • @mgri Thanks for the tip. I've never used GRASS or python before. Is there an 'idiots' guide to get started you might be able to recommend?
    – James B
    May 8, 2017 at 18:40
  • @JamesB Are you starting from a point layer? It is really simple doing your task through PyQGIS and I can provide a sample code according to your answer. However, r.viewshed returns one map for each point, while the plugin suggested by Steven Kay should produce cumulative maps.
    – mgri
    May 8, 2017 at 19:01
  • @mgri If I had a preference to which method I use it would be the plugin. However being a GIS technician, I really aught to explore GRASS and PyQGIS at some point. The most important thing is to specify a height above ground for the point. Applying this to multiple points at once will be handy indeed. That would be extremely kind of you to provide the code necessary, if I could just request you summarise 'what means what' as I have little coding experience. I have however delved into CSS and html whilst designing websites.
    – James B
    May 8, 2017 at 19:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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