8

I have point layer and a network (segments) stored in a GeoPackage and using QGIS. The number of points and their ids are always different.

enter image description here

What I need is to get a route from first to last points but through several stops in a specific order.

I am thinking in a script or algorithm where to select an order column and then do the shortest path between first and last points setting the rest of it as stops ordered and get a single layer with the entire path.

I've tried the Analysis tools of QGIS and plugins but I can't find a tool with this functionality.

I have also tried the v.net.salesman that computes a route through all the points but it isn't what I need, It can't assign an order to the stops and the route should not be cycle.

Is there any way, using QGIS or PyQGIS, to do that?

4
  • Maybe you should add more information. So in the screenshot above, your route should start at point 1, than go to 3, than to 4, to 5, to 6 and on to 7, 8, 9, 10 and finally to 11? So in principle, if you would do a simple shortest path analysis for each step (1 to 3 ; 3 to 4 ; 4 to 5 and so on), this would finally add up to the path you are interested in? Or is it something more sophisticated?
    – Babel
    Dec 1, 2020 at 20:49
  • The number of points and their id are always different, so I thought in a script or algorithm where I can select an order column and then do the shortest path beteeen first and last points setting the rest of it as stops ordered to get a single layer with the entire path, but I didn't think about doing it like you propose. I'm going to try it. Thanks @babel. Dec 2, 2020 at 9:45
  • 1
    I suggest to add the information from you comment to the original question. There have been similar questions with no answer here, so it seems to be a problem that deserves attention: gis.stackexchange.com/questions/360726/…
    – Babel
    Dec 2, 2020 at 9:58
  • Ok, I just do that. Thanks @babel. Dec 2, 2020 at 10:16

1 Answer 1

6
+50

The solution requires some basic usage of PyQGIS. This code computes paths for every subsequent pair of points using the order specified in the "order" field. Then all the paths are merged into a single layer.

Add an order column, change your input variables and run this as a script in QGIS 3.

###input###
networkLayerName = 'prg_ulice'
pointLayerName = 'pkt_adresowe'
orderColumnName = 'order'
output = '/home/lpowalka/Documents/dane/geopackage/path.gpkg'
###input###

networkLayer = QgsProject.instance().mapLayersByName(networkLayerName)[0]
pointLayer = QgsProject.instance().mapLayersByName(pointLayerName)[0]

expr = '"{column}" is not null'.format(column=orderColumnName)
pointLayer.selectByExpression(expr)

stops = []
for feat in pointLayer.selectedFeatures():
    stops.append((feat['order'], feat.geometry().asPoint()))

#sort by order column
stops.sort(key=lambda x: x[0])
paths = []
for i, (order, point) in enumerate(stops[0:-1]):
    endPoint = stops[i + 1][1]
    print('Order: ', order)
    print('From {} to {} \n'.format(point, endPoint))
    parameters = {'INPUT': networkLayer,
                'STRATEGY': 0,
                'DIRECTION_FIELD': '',
                'VALUE_FORWARD': '',
                'VALUE_BACKWARD': '',
                'VALUE_BOTH': '',
                'DEFAULT_DIRECTION': 2,
                'SPEED_FIELD': '',
                'DEFAULT_SPEED': 50.0,
                'TOLERANCE': 20.0,
                'START_POINT': point,
                'END_POINT': endPoint,
                'OUTPUT': 'memory:'}


    path = processing.run('qgis:shortestpathpointtopoint', parameters)['OUTPUT']
    paths.append(path)

params = {'LAYERS': paths, 'OUTPUT': output}
pathsMerged = processing.run('qgis:mergevectorlayers', params)['OUTPUT']
vlayer = QgsVectorLayer(pathsMerged, 'result', 'ogr')
QgsProject.instance().addMapLayer(vlayer)

enter image description here

5
  • Impressive! Fajne)
    – Taras
    Dec 3, 2020 at 12:09
  • It works great although with some issues, but I think it is related with the algorithm (imgur.com/delete/zmd3ezuIZ5cFOSV). Thanks Leon. Dec 3, 2020 at 16:17
  • I'm testing the script and it works great, but I have a doubt (curiosity). If the values of the order field are the same in every row, what order would the script follow? Dec 3, 2020 at 19:27
  • Regarding 1st comment: yes. I had some issues as well. Try testing different parameters for the shortest path algorithm or cleaning your road data. Dec 4, 2020 at 6:36
  • Regarding 2nd comment: i used Python sort and then iterate over everything regardless. So the code will work, but the order amongst same values will probably be random. If you want to dig deeper then this is the algorithm under sort : en.wikipedia.org/wiki/Timsort Dec 4, 2020 at 6:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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