ось псевдокод для початку. Я сподіваюся, що це допоможе, і що хтось встигне надати повний код (у мене зараз немає)
Перше, що потрібно зробити, це зробити цикл на точці та вибрати лінії, які знаходяться в межах порогової відстані до кожної точки. Це можна зробити за допомогою QgsSpatialIndex
У межах першого циклу, друге, що потрібно зробити, - це циклічити вибрані лінії та знайти найближчу точку на лінії. Це можна зробити безпосередньо на основі QgsGeometry :: najbližeSegmentWithContext
подвійний QgsGeometry :: найближчийSegmentWithContext (const QgsPoint & point, QgsPoint & minDistPoint, int & afterVertex, подвійний * leftOf = 0, подвійний epsilon = DEFAULT_SEGMENT_EPSILON)
Пошук найближчого відрізка геометрії до заданої точки.
Параметри точки Вказує точку пошуку
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 зліва Outf: Повертається, якщо точка лежить з правого боку відрізка (<0 означає ліворуч,> 0 означає праворуч) epsilon epsilon для оснащення сегмента (додано в 1,8)
третій крок (у межах першого циклу) полягав би в оновленні геометрії точки з геометрією minDistPoint з найменшою відстані
оновлення деяким кодом (на 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)