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.
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 -
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
update with some code (on QGIS3)
pointlayer = QgsProject.instance().mapLayersByName('point') #iface.mapCanvas().layer(0)
lineLayer = QgsProject.instance().mapLayersByName('lines') # iface.mapCanvas().layer(1)
epsg = pointlayer.crs().postgisSrid()
uri = "Point?crs=epsg:" + str(epsg) + "&field=id:integer&field=distance:double(20,2)&field=left:integer&index=yes"
snapped = QgsVectorLayer(uri,'snapped', 'memory')
prov = snapped.dataProvider()
testIndex = QgsSpatialIndex(lineLayer)
for p in pointlayer.getFeatures():
mindist = 10000.
near_ids = testIndex.nearestNeighbor(p.geometry().asPoint(),4) #nearest neighbor works with bounding boxes, so I need to take more than one closest results and further check all of them.
features = lineLayer.getFeatures(QgsFeatureRequest().setFilterFids(near_ids))
for tline in features:
closeSegResult = tline.geometry().closestSegmentWithContext(p.geometry().asPoint())
if mindist > closeSegResult:
closePoint = closeSegResult
mindist = closeSegResult
side = closeSegResult
feat = QgsFeature()