1

I am trying to create python code to iterate through points on 1 layer and find the closest point on another layer (Road Chainages) based on attribute values. I need to limit the search to < 20m maximum distance between both matching attribute values.

I utilised code from Find the closest segment to a point which contains the same attribute and amended to suit point layers but i get stuck at the nearestNeighbor code. I believe i need to try to implement something similar to whats on this website Finding nearest line to point in QGIS? and somehow include the QgsSpatialIndex.nearestNeighbor (QgsPoint point, int neighbors)

I am using QGIS 2.18, but will look to update code to 3+ once i improve my skills.

#Based on 
#https://gis.stackexchange.com/questions/250528/find-the-closest-segment-to-a-point-which-contains-the-same-attribute

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

##in development=group
##points=vector point
##point_attribute_to_match=field points
##Chainages=vector point
##Chainage_attribute_to_match=field Chainages
##Chainage_attribute_to_transfer=field Chainages
##tolerance=number 50

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

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

#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 = 1000
    sourceId = -1
    for c in linksLayer.getFeatures(QgsFeatureRequest().setFilterRect(s.geometry().buffer(tolerance,5).boundingBox())):


       # print c.attribute(Chainage_attribute_to_match)  -  Research why this is failing.

        # Tried sDist = c.QgsSpatialIndex.nearestNeighbor(sGeometry,1) 
        # Tried sDist = c.geometry().nearestNeighbor(sGeometry,1)  .
        # Tried sDist = c.nearestNeighbor(sGeometry,1)  
        sDist = p.nearestNeighbor(sGeometry.asPoint(),1)

       if sDist < sDistMin and s.attribute(point_attribute_to_match) == c.attribute(Chainage_attribute_to_match):
                    sDistMin = sDist
                    sourceId = p.attribute(Chainage_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()

In my log i get { 'QgsFeature' object has no attribute 'nearestNeighbor' See log for more details }. see below.

2019-01-18T08:47:13 2   Uncaught error while executing algorithm
            Traceback (most recent call last):
              File "C:/PROGRA~1/QGIS2~1.18/apps/qgis-ltr/./python/plugins\processing\core\GeoAlgorithm.py", line 203, in execute
                self.processAlgorithm(progress)
              File "C:/PROGRA~1/QGIS2~1.18/apps/qgis-ltr/./python/plugins\processing\script\ScriptAlgorithm.py", line 381, in processAlgorithm
                exec((script), ns)
              File "<string>", line 50, in <module>
            AttributeError: 'QgsFeature' object has no attribute 'nearestNeighbor'



1
  • 1
    that specific error refers to a (pretty common) syntax error; Pythons whole code block definition is based on indentation. outdent sDist = ... to match the if sDist ... line. note that I have not checked your code for anything else!
    – geozelot
    Commented Jan 17, 2019 at 14:56

1 Answer 1

2

Your error message relates to the fact that you are trying to call the nearestNeighbor method of a QGSFeature object, which does not exist. Even if try to call the same method of the geometry object that also does not exist.

Instead, try calling the distance method of the geometry object. The check for sDist < sDistMin takes care of the 'nearest' part.

sDist = p.geometry().distance(sGeometry)

3
  • Also - your Chainage_attribute_to_match object in instance of QGSField. You need to pass a string to c.attribute(), so try c.attribute( Chainage_attribute_to_match.name() ) Commented Jan 18, 2019 at 10:31
  • QGIS returns this error to me, File "<string>", line 50, in <module> TypeError: QgsGeometry.distance(QgsGeometry): argument 1 has unexpected type 'QgsPoint'. I am having troubles understanding this error. In the geometry section it checks that their is a point feature in the source file, in the sDist = p.geometry()... measures the distance between features. Am i missing something with this code?
    – Pat
    Commented Jan 18, 2019 at 13:06
  • 1
    my bad, try: sDist = p.geometry().distance( s.geometry() ) Commented Jan 18, 2019 at 16:11

Your Answer

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

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