1

I have a shapefile of road volumes as polylines, and want to be able to show the sum of the volumes for polylines that are spatially the same/similar but are for travel in opposite directions. For e.g. one polyline for traffic travelling North may have a volume of 8000, while the equivalent polyline that is for traffic going South has a volume of 6000. I need to be able to locate each of these polylines and sum their volume values, and show this as a separate layer. Note that some polylines within the dataset are along one-way streets and therefore don't have an equivalent polyline that travels in the opposite direction.

I've been able to distinguish each line pair in the attribute table by generating the xmin and xmax, however I'm not keen on selecting each pair manually and calculating the sum of volumes given there are a few thousand. I've tried spatial join (MMQGIS plugin) and union in QGIS but haven't had any luck. I've also toyed with the QGIS Field Calculator a bit but I'm not very familiar with how to use some of the geometry commands for this type of analysis.

  • Can you comment on how "same/similar" the polylines in opposite directions are? For example, would a buffer of 1 meter around 1 line always contain the line in the opposite direction? Does your check for xmin and xmax always catch the line pairs? – Micha Apr 14 '15 at 5:45
  • Thanks for the reply Micha. From what I can see the xmin and xmax always match for each of the polylines that have a duplicate line in another direction. There may be some exceptions but not many. – Christine Apr 14 '15 at 6:23
  • 1
    Thanks for that dof1985. I gave it a shot and it appears to have worked, so thank you! Your help is much appreciated :) – ChristineJS Apr 15 '15 at 23:02
2

EDIT: as mentioned below, the code I suggest here is my first one, thus may be inefficient. I posted it in code-review SE, so whoever wishes might follow the post, to either correct the code, or to obtain a better, more-efficient version of it.

So this is my first PyQGIS code, which is aimed to do what you asked for, namely to find those pairs of lines (or roads) that share the same geometry, and sum the values of a chosen field (i.e. volume).

The output is a tmp. layer with 3 columns: ID, IDsub stand for FID of the features being merges, and ValueSum. Features with no other features with shared geometries, will get their original value in the ValueSum field, and -99 (i.e. no match) in the IDsub field.

Image of an output is below:

Example

The code is attached as well. Feel free to modify it to your exact needs. Note that it may be in-efficient (for it is my fisrt code here), also make sure to define the path to your shapefile and the name of the field to be summed at the top.

path='D:/Documents/qgis/lines_same/Lines.shp'  # Enter your SHP file path
Val='Value'                      # Enter the field name you would like to summarize
from PyQt4.QtCore import *
layer = QgsVectorLayer(path,'Lines', 'ogr')
tmp = QgsVectorLayer("LineString", "tmp_output", "memory")
dp = tmp.dataProvider()
tmp.startEditing()
dp.addAttributes ( [ QgsField("ID", QVariant.Int),
        QgsField("IDsub", QVariant.Int),
        QgsField("ValueSum", QVariant.Int) ] )
iter = layer.getFeatures()
for feature in iter:
    CreateVerify = 0
    geom = feature.geometry()
    geom = geom.asPolyline()
    ID = feature.id()
    Value = feature[Val]
    iterSub = layer.getFeatures()
    for featureSub in iterSub:
        geomSub = featureSub.geometry()
        geomSub = geomSub.asPolyline()
        IDsub = featureSub.id()
        ValueSub = featureSub[Val]
        if (geom==geomSub and ID!=IDsub):
            CheckExist = tmp.getFeatures()
            Exist = 0
            for exs in CheckExist:
                if (exs.geometry().asPolyline() == geom):
                    Exist = Exist + 1
            if (CreateVerify == 0 and Exist == 0):
                CreateVerify = 1
                New = QgsFeature()
                New.setGeometry (QgsGeometry.fromPolyline(geom))
                New.setAttributes([ID, IDsub, Value + ValueSub])
                dp.addFeatures([ New ])
                tmp.commitChanges()
            elif (Exist > 0):
                CreateVerify = 1                            
    if (CreateVerify == 0):
        New = QgsFeature()
        New.setGeometry (QgsGeometry.fromPolyline(geom))
        New.setAttributes([ID,-99, Value])
        dp.addFeatures([ New ])
        tmp.commitChanges()
    QgsMapLayerRegistry.instance().addMapLayer(tmp) 
0

Just for completeness, I'd like to add another solution based on using spatial SQL queries. Suppose you have a roads layer in a Spatialite database, for example. I'll assume this roads table has a column 'id' and a columm 'volume'. To get those linestrings that are duplicates (end points are equal), together with the sum of the volumes you could do:

SELECT r1.id, r1.volume+r2.volume AS "Total volume"
FROM roads AS r1, roads r2
WHERE r1.id<>r2.id AND
StartPoint(r1.geometry) = EndPoint(r2.geometry) AND
EndPoint(r1.geometry) = StartPoint(r2.geometry);

This is based on the end points of each linestring being exactly the same. But often computer (floating point) rounding errors, or digitizing mistakes leave end points slightly off. So a better option is to query for one endpoint to be within a buffer around the other line's endpoint. That would be (taking a 2 meter buffer):

SELECT r1.id, r1.volume+r2.volume AS "Total volume"
FROM roads AS r1, roads r2
WHERE r1.id<>r2.id AND
ST_Contains(ST_Buffer(EndPoint(r2.geometry),2), StartPoint(r1.geometry)) AND
ST_Contains(ST_Buffer(StartPoint(r2.geometry),2), EndPoint(r1.geometry))

BTW, This only works if the linestrings are truely in opposite topological directions. If you have the two traffic directions digitized in the same line direction, the above won't work. The STartPoint of one of the duplicates must be at the EndPoint of it's duplicate pair. Hope that's clear...

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.