di sini adalah pseudo-code untuk memulai. Saya harap ini membantu dan seseorang akan punya waktu untuk memberikan kode lengkap (saya tidak punya saat ini)
Hal pertama yang harus dilakukan adalah mengulang pada titik dan memilih garis yang berada dalam jarak ambang batas untuk setiap titik. Ini dapat dilakukan dengan QgsSpatialIndex
Dalam loop pertama, hal kedua yang harus dilakukan adalah loop pada garis yang dipilih dan menemukan titik terdekat pada garis. Ini dapat dilakukan langsung berdasarkan QgsGeometry :: terdekatSegmentWithContext
double QgsGeometry :: terdekatSegmentWithContext (const QgsPoint & point, QgsPoint & minDistPoint, int & afterVertex, double * leftOf = 0, double epsilon = DEFAULT_SEGMENT_EPSILON)
Mencari segmen geometri terdekat ke titik tertentu.
Titik parameter Menentukan titik untuk pencarian
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 kiriOf Keluar: Mengembalikan jika titik terletak di sebelah kiri sisi kanan segmen (<0 berarti kiri,> 0 berarti kanan) epsilon epsilon untuk gertakan segmen (ditambahkan 1,8)
langkah ketiga (dalam loop pertama) akan terdiri dalam memperbarui geometri titik dengan geometri minDistPoint dengan jarak terkecil
perbarui dengan beberapa kode (pada 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)