[GIS] Finding closest segment to point which contains same attribute using NNJoin plugin of QGIS

qgis

I'm using QGIS 2.18

I have a point layer with the 4405 address positions of a municipality, as well as a road layer with road segments.

I would like to join the attribute information of the closest road segment to each point UNDER THE CONDITION that the attribute "street name" in the road layer has the same value as the attribute "street name" in the address point layer.
In other words, the tool should look for the closest road segment which has the same street name and join the attribute values of this road segment to the point.

Using the NNJoin plugin in QGIS does the job for the first part of my question, but I'm not able to include my condition (as a consequence, for 302 points the attribute values of a road segment are joined for which the street name is not the same as the one indicated in the point).

Is there some kind of extended plugin of NNJoin which could do the job?

Best Answer

It just so happens that I've just made a script to do this exact operation. In the processing toolbox, click Tools > Create new script, then copy and past the below code (tested on version 2.18). Double click to run it and fill in the form. Most fields are self explanatory but the "tolerance" field specifies a distance within which to search for a segment with matching attributes.

from qgis.core import *
from PyQt4.QtCore import QVariant

##in development=group
##points=vector point
##point_attribute_to_match=field points
##roads=vector line
##road_attribute_to_match=field roads
##road_attribute_to_transfer=field roads
##tolerance=number 500

#get source and target objects
sources = processing.getObject(points)
linksLayer = processing.getObject(roads)

#add new field
sources.startEditing()
newField = QgsField('road_id', QVariant.Int)
sources.addAttribute(newField)    
sources.updateFields()
sourceIndex = sources.fieldNameIndex('road_id')

#variables for progress bar
percentMax = sources.featureCount()
p = 1

for s in sources.getFeatures():   

    #get geometry 
    if s.geometry():
        sGeometry = s.geometry().asPoint()
        if sGeometry == [0,0]:
            sGeometry = s.geometry().asMultiPoint()[0]

    else:
        progress.setText("no geometry found")

    #get nearest feature and write source attribute out
    sDistMin = 99999999999999
    sourceId = -1
    for l in linksLayer.getFeatures(QgsFeatureRequest().setFilterRect(s.geometry().buffer(tolerance,5).boundingBox())):

        print l.attribute(road_attribute_to_match)

        sDist = l.geometry().closestSegmentWithContext(sGeometry)[0]

        if sDist < sDistMin and s.attribute(point_attribute_to_match) == l.attribute(road_attribute_to_match):
                    sDistMin = sDist
                    sourceId = l.attribute(road_attribute_to_transfer)

    progress.setText("Marker")
    if sourceId != -1:    
        sources.changeAttributeValue(s.id(), sourceIndex, sourceId)
        sourceId = -1

    else:
        progress.setText("no matching source found for: " + point_attribute_to_match)

    #set progress
    progress.setPercentage(p/(float(percentMax))*100)
    p += 1   

sources.commitChanges()
Related Question