ecco uno pseudo-codice per cominciare. Spero che questo aiuti e che qualcuno abbia il tempo di fornire il codice completo (non ho al momento)
la prima cosa da fare è fare un ciclo sul punto e selezionare le linee che si trovano all'interno della distanza di soglia per ciascun punto. Questo può essere fatto con QgsSpatialIndex
All'interno del primo ciclo, la seconda cosa da fare è fare un ciclo sulle linee selezionate e trovare il punto più vicino sulla linea. Questo può essere fatto direttamente sulla base di QgsGeometry :: latestSegmentWithContext
double QgsGeometry :: latestSegmentWithContext (const QgsPoint & point, QgsPoint & minDistPoint, int & afterVertex, double * leftOf = 0, double epsilon = DEFAULT_SEGMENT_EPSILON)
Cerca il segmento di geometria più vicino a un determinato punto.
Parametri point Specifica il punto per la ricerca
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: restituisce se il punto si trova sulla sinistra del lato destro del segmento (<0 significa sinistra,> 0 significa destra) epsilon epsilon per lo snap a segmenti (aggiunto in 1.8)
il terzo passo (all'interno del primo ciclo) consisterebbe nell'aggiornamento della geometria del punto con la geometria del minDistPoint con la distanza minima
aggiornamento con un po 'di codice (su QGIS3)
pointlayer = QgsProject.instance().mapLayersByName('point')[0] #iface.mapCanvas().layer(0)
lineLayer = QgsProject.instance().mapLayersByName('lines')[0] # 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)
i=0
feats=[]
for p in pointlayer.getFeatures():
i+=1
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[0]:
closePoint = closeSegResult[1]
mindist = closeSegResult[0]
side = closeSegResult[3]
feat = QgsFeature()
feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(closePoint[0],closePoint[1])))
feat.setAttributes([i,mindist,side])
feats.append(feat)
prov.addFeatures(feats)
QgsProject.instance().addMapLayer(snapped)