[GIS] Moving points onto lines (~neighborhood)

linepointqgisvector

I do have two vector layer, of which
one is a point layer based on "events" by remote sensing
and the second one is a line layer from local research.

In my case these are earthquakes and tectonic faults, but
I guess one could simply choose "car-accidents and roads"
as a general example.

So what I'd like to do is move/copy the points onto
the closest point of the lines, as long as its within a
tolerance distance (say 1-2km or 0.0xx°), with the new
point layer (+attr moved y/n).

Any ideas ?

Linux, QGIS 1.8

Best Answer

Posted a code snippet(tested in python console) that doest the below

  1. Use QgsSpatialIndex to find the nearest line feature to a point
  2. Find the nearest point on this line to the point. I used shapely package as a shortcut for this. I found the QGis methods for this as insufficient(or most probably i do not understand them properly)
  3. Added rubberbands to the snap locations
from shapely.wkt import *
from shapely.geometry import *
from qgis.gui import *
from PyQt4.QtCore import Qt
lineLayer = iface.mapCanvas().layer(0)
pointLayer =  iface.mapCanvas().layer(1)
canvas =  iface.mapCanvas()
spIndex = QgsSpatialIndex() #create spatial index object
lineIter =  lineLayer.getFeatures()
for lineFeature in lineIter:
    spIndex.insertFeature(lineFeature)        
pointIter =  pointLayer.getFeatures()
for feature in pointIter:
    ptGeom = feature.geometry()
    pt = feature.geometry().asPoint()
    nearestIds = spIndex.nearestNeighbor(pt,1) # we need only one neighbour
    featureId = nearestIds[0]
    nearestIterator = lineLayer.getFeatures(QgsFeatureRequest().setFilterFid(featureId))
    nearFeature = QgsFeature()
    nearestIterator.nextFeature(nearFeature)
    shplyLineString = shapely.wkt.loads(nearFeature.geometry().exportToWkt())
    shplyPoint = shapely.wkt.loads(ptGeom.exportToWkt())
    #nearest distance from point to line
    dist = shplyLineString.distance(shplyPoint)
    print dist
    #the point on the road where the point should snap
    shplySnapPoint = shplyLineString.interpolate(shplyLineString.project(shplyPoint))
    #add rubber bands to the new points
    snapGeometry = QgsGeometry.fromWkt(shapely.wkt.dumps(shplySnapPoint))
    r = QgsRubberBand(canvas,QGis.Point)
    r.setColor(Qt.red)
    r.setToGeometry(snapGeometry,pointLayer)

Edit: Just now found that @radouxju method using closestSegmentWithContext gives the same results in less lines of code. I wonder why they came up with this weird method name? should have been something like closestPointOnGeometry.

So we can avoid shapely and do like,

nearFeature = QgsFeature()
nearestIterator.nextFeature(nearFeature)   

closeSegResult = nearFeature.geometry().closestSegmentWithContext(ptGeom.asPoint())
closePoint = closeSegResult[1]
snapGeometry = QgsGeometry.fromPoint(QgsPoint(closePoint[0],closePoint[1])) 

p1 = ptGeom.asPoint()
p2 = snapGeometry.asPoint()

dist = math.hypot(p2.x() - p1.x(), p2.y() - p1.y())
print dist
Related Question