# Aligning multiple points to line in QGIS?

I would like to align multiple points to a line, or lines within a layer, using a specified tolerance or buffer around the line objects. Please refer to the sample sketch attached.

For the sake of this example, the points closest to the line in the BEFORE picture are within 5 map units of the line, while the outermost points are over 10 map units away. I would like to snap the closest points onto the nearest line, using a tolerance of 5 map units to achieve the result in the AFTER picture.

• So the point needs to be 0 map units laterally of the line, but do you care about where the point ends up longitudinally of the line with respect to the point's original location?
– LHo
Commented Apr 19, 2017 at 1:00
• The ideal scenario would be to move the points using a perpendicular path to the line. However, the intention is to use fairly small tolerances. If the points are moved longitudinally or latitudinally, towards the line, it wont offset the points that much from a preferable perpendicular position. Commented Apr 19, 2017 at 1:18
• Not sure if this is the best way, but one way I can think of is to write some python code to analyse the two datasets and produce some point coordinates. If this is what you think you want, then let me know and i can provide an answer for you. E.g. for every point, if the absolute value of lat dist from line <= 5 units, then lateral distance = 0. You'd have to import a gdal library to convert the x,y values into coords. See comments in: gis.stackexchange.com/questions/185445/…
– LHo
Commented Apr 19, 2017 at 2:13
• With PyQGIS, it can be produced a memory layer where points are snapped according to previously considered tolerance of 5 map units and a perpendicular path to the line. See my answer. Commented Jul 4, 2017 at 3:35

There's a built-in tool to do this in the (unreleased) QGIS 3.0 version. You can get a nightly snapshot from the QGIS website to test this in advance.

To do this:

1. Run the "Snap geometries to layer" processing algorithm
2. Select your points layer as the "input layer"
3. Select the line layer as the "reference layer"
4. Enter a suitable tolerance (maximum distance to move points while snapping)
5. Change the behavior to "Prefer closest point"

Here's the result, showing the original points as "x", and the snapped points as green dots. I've used a tolerance here so that only some of the input points are snapped.

• This is exactly what I need. Unfortunately my employer only installs LTR versions of QGIS and we are all restricted from downloading and installing test versions. (sigh) I guess it's a matter of waiting. Is this a standard/built in function or a plug-in? Commented Apr 19, 2017 at 3:02
• Standard functionality relying on changes in the c++ classes - there's no way to manually copy this to an older version. You could potentially try installing using OSGEO4W on a different machine, and then copying the osgeo4w folder to a USB stick to run on your workstation. I've had luck with that approach in the past. Commented Apr 19, 2017 at 3:23
• For old version have a look on this plugin. docs.qgis.org/2.14/en/docs/user_manual/plugins/… Commented Apr 27, 2017 at 8:07
• it seems the plugin does not support points' layers. Commented Apr 27, 2017 at 12:07

This can be afforded with PyQGIS. For next situation:

following code, considering a tolerance of 5 map units, was ran at the Python Console of QGIS:

``````from math import sqrt

registry = QgsMapLayerRegistry.instance()

points = registry.mapLayersByName('points')
line = registry.mapLayersByName('line')

feat_points = [ feat for feat in points[0].getFeatures() ]
feat_line = line[0].getFeatures().next()

new_points = []

for feat in feat_points:
pt = feat.geometry().asPoint()
sqrdist, point, vertex = feat_line.geometry().closestSegmentWithContext(pt)
if sqrt(sqrdist) <= 5:
new_points.append(point)
else:
new_points.append(pt)

epsg = points[0].crs().postgisSrid()

uri = "Point?crs=epsg:" + str(epsg) + "&field=id:integer""&index=yes"

mem_layer = QgsVectorLayer(uri,
'new_points',
'memory')

prov = mem_layer.dataProvider()

feats = [ QgsFeature() for i in range(len(new_points)) ]

for i, feat in enumerate(feats):
feat.setAttributes([i])
feat.setGeometry(QgsGeometry.fromPoint(new_points[i]))

`closest_point(geom_from_wkt(geomdistance('snap_lines','\$geometry',10)) , \$geometry)`