hier ist ein pseudocode zum starten. Ich hoffe, dass dies hilft und dass jemand Zeit hat, vollständigen Code bereitzustellen (ich habe im Moment keinen).
Zunächst müssen Sie eine Schleife um den Punkt ausführen und die Linien auswählen, die sich innerhalb des Schwellenabstands zu jedem Punkt befinden. Dies kann mit QgsSpatialIndex erfolgen
In der ersten Schleife müssen Sie als zweites die ausgewählten Linien durchlaufen und den nächstgelegenen Punkt auf der Linie finden. Dies kann direkt basierend auf QgsGeometry :: closerSegmentWithContext erfolgen
double QgsGeometry :: closerSegmentWithContext (const QgsPoint & point, QgsPoint & minDistPoint, int & afterVertex, double * leftOf = 0, double epsilon = DEFAULT_SEGMENT_EPSILON)
Sucht nach dem Geometriesegment, das dem angegebenen Punkt am nächsten liegt.
Parameter point Gibt den Punkt für die Suche an
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: Gibt zurück, ob der Punkt links oder rechts vom Segment liegt (<0 bedeutet links,> 0 bedeutet rechts). Epsilon epsilon für Segmentfang (hinzugefügt in 1.8)
Der dritte Schritt (innerhalb der ersten Schleife) würde darin bestehen, die Geometrie des Punkts mit der Geometrie des minDistPoint mit dem geringsten Abstand zu aktualisieren
Update mit etwas Code (auf 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)