tutaj jest pseudo-kod na początek. Mam nadzieję, że to pomoże i że ktoś będzie miał czas na dostarczenie pełnego kodu (obecnie nie mam)
pierwszą rzeczą do zrobienia jest zapętlenie punktu i wybranie linii, które znajdują się w odległości progowej do każdego punktu. Można to zrobić za pomocą QgsSpatialIndex
W ramach pierwszej pętli drugą rzeczą jest zapętlenie wybranych linii i znalezienie najbliższego punktu na linii. Można to zrobić bezpośrednio w oparciu o QgsGeometry :: closestSegmentWithContext
double QgsGeometry :: closestSegmentWithContext (const QgsPoint & point, QgsPoint & minDistPoint, int & afterVertex, double * leftOf = 0, double epsilon = DEFAULT_SEGMENT_EPSILON)
Wyszukuje najbliższy segment geometrii do danego punktu.
Parametry point Określa punkt wyszukiwania
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: Zwraca, jeśli punkt leży po lewej stronie prawej części segmentu (<0 oznacza lewą stronę,> 0 oznacza prawą) epsilon epsilon do przyciągania segmentu (dodany w 1.8)
trzeci krok (w ramach pierwszej pętli) polegałby na zaktualizowaniu geometrii punktu o geometrię minDistPoint o najmniejszej odległości
aktualizacja z pewnym kodem (na 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)