Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

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

share|improve this question
3  
There would be a PostGIS solution: PostGIS : nearest point on a linestring to a given point –  underdark Jan 3 '13 at 23:23
    
Are you looking for a totally automated function to do this, or would some sort of snapping tool to do it by hand be OK? –  Simbamangu Aug 25 '13 at 8:01
    
I asked a similar question, I was trying to snap line to points but never found an easy solution. gis.stackexchange.com/questions/52232/… –  GreyHippo Sep 18 '13 at 13:42
    
What about triangulation and distance matching? –  huckfinn Jan 29 at 21:14
    
I found this question about a method that works in ArcGIS using Near. Went searching for QGIS Near equivalent and found this forum post where someone suggested GRASS v.distance. That lead me to this tutorial that may identify a method. Perhaps somewhere in there someone has written a plugin by now? –  Chris W Apr 26 at 23:39
show 2 more comments

2 Answers 2

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
share|improve this answer
    
running into nightmare trying to format this python code..argh!! –  vinayan Apr 29 at 9:04
add comment

here is a pseudo-code to start with. I hope this helps and that someone will have time to provide full code (I don't have at the moment)

first thing to do is to loop on the point and select the lines that are located within the threshold distance to each point. Thi can be done with QgsSpatialIndex

Within the first loop, the second thing to do is to loop on the selected lines and find the closest point on the line. This can be done directly based on QgsGeometry::closestSegmentWithContext

double QgsGeometry::closestSegmentWithContext ( const QgsPoint & point, QgsPoint & minDistPoint, int & afterVertex, double * leftOf = 0, double epsilon = DEFAULT_SEGMENT_EPSILON )

Searches for the closest segment of geometry to the given point.

Parameters point Specifies the point for search

minDistPoint  Receives the nearest point on the segment

afterVertex   Receives index of the vertex after the closest segment. The vertex before the closest segment is always afterVertex -

1 leftOf Out: Returns if the point lies on the left of right side of the segment ( < 0 means left, > 0 means right ) epsilon epsilon for segment snapping (added in 1.8)

the third step (within the first loop) would consist in updating the geometry of the point with the geometry of the minDistPoint with the smallest distance

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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