여기에 의사 코드가 있습니다. 이것이 도움이되고 누군가가 전체 코드를 제공 할 시간이 있기를 바랍니다 (현재는 없습니다)
가장 먼저 할 일은 점을 반복하고 각 점까지의 임계 거리 내에있는 선을 선택하는 것입니다. QgsSpatialIndex로 할 수 있습니다
첫 번째 루프 내에서 두 번째로해야 할 일은 선택한 선을 반복하고 해당 선에서 가장 가까운 점을 찾는 것입니다. 이는 QgsGeometry :: closestSegmentWithContext를 기반으로 직접 수행 할 수 있습니다.
double QgsGeometry :: closestSegmentWithContext (const QgsPoint & point, QgsPoint & minDistPoint, int & afterVertex, double * leftOf = 0, double epsilon = DEFAULT_SEGMENT_EPSILON)
주어진 점에 가장 가까운 지오메트리 세그먼트를 검색합니다.
매개 변수 point 검색 할 지점을 지정합니다
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 : 점이 세그먼트의 오른쪽 왼쪽에있는 경우 (<0은 왼쪽,> 0은 오른쪽) 엡실론 엡실론 세그먼트 스냅 (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)