ここから開始する擬似コードです。これが助けになり、誰かが完全なコードを提供する時間があることを願っています(現時点ではありません)
最初に行うことは、ポイントでループし、各ポイントまでのしきい値距離内にあるラインを選択することです。これはQgsSpatialIndexで実行できます
最初のループ内で、2番目に行うことは、選択した行でループし、その行で最も近い点を見つけることです。これは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で追加)
3番目のステップ(最初のループ内)は、ポイントのジオメトリを最小距離の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)