Перемещение точек на линии (окрестности)

14

У меня есть два векторных слоя, один из которых представляет собой точечный слой, основанный на «событиях» с помощью дистанционного зондирования, а второй - линейный слой из локальных исследований.

В моем случае это землетрясения и тектонические разломы, но я думаю, что можно просто выбрать «автомобильные аварии и дороги» в качестве общего примера.

Поэтому я хотел бы переместить / скопировать точки в ближайшую точку линий, если они находятся в пределах допустимого расстояния (скажем, 1-2 км или 0,0xx °), с новым слоем точек (+ attr перемещено г / л).

Есть идеи ?

Linux, QGIS 1.8

Крис Паллаш
источник
3
Было бы решение PostGIS: PostGIS: ближайшая точка на линейной линии к данной точке
подземное движение
Вы ищете полностью автоматизированную функцию, чтобы сделать это, или какой-нибудь инструмент привязки, чтобы сделать это вручную, будет в порядке?
Симбамангу
Я задал похожий вопрос, пытался привязать линию к точкам, но так и не нашел простого решения. gis.stackexchange.com/questions/52232/…
GreyHippo
Как насчет триангуляции и сопоставления расстояний?
huckfinn
Я нашел этот вопрос о методе, который работает в ArcGIS с использованием Near. Поискал QGIS Почти эквивалентный и нашел этот пост на форуме, где кто-то предложил GRASS v.distance. Это привело меня к этому уроку, который может определить метод. Возможно, где-то там кто-то уже написал плагин?
Крис W

Ответы:

13

Выложил фрагмент кода (протестированный в консоли Python), который делает ниже

  1. Используйте QgsSpatialIndex, чтобы найти ближайший линейный объект к точке
  2. Найти ближайшую точку на этой линии к точке. Я использовал красивую упаковку в качестве ярлыка для этого. Я нашел методы QGis для этого недостаточными (или, скорее всего, я не понимаю их правильно)
  3. Добавлены резиновые ленты в местах привязки
from shapely.wkt import *
from shapely.geometry import *
from qgis.gui import *
from PyQt4.QtCore import Qt
lineLayer = iface.mapCanvas().layer(0)
pointLayer =  iface.mapCanvas().layer(1)
canvas =  iface.mapCanvas()
spIndex = QgsSpatialIndex() #create spatial index object
lineIter =  lineLayer.getFeatures()
for lineFeature in lineIter:
    spIndex.insertFeature(lineFeature)        
pointIter =  pointLayer.getFeatures()
for feature in pointIter:
    ptGeom = feature.geometry()
    pt = feature.geometry().asPoint()
    nearestIds = spIndex.nearestNeighbor(pt,1) # we need only one neighbour
    featureId = nearestIds[0]
    nearestIterator = lineLayer.getFeatures(QgsFeatureRequest().setFilterFid(featureId))
    nearFeature = QgsFeature()
    nearestIterator.nextFeature(nearFeature)
    shplyLineString = shapely.wkt.loads(nearFeature.geometry().exportToWkt())
    shplyPoint = shapely.wkt.loads(ptGeom.exportToWkt())
    #nearest distance from point to line
    dist = shplyLineString.distance(shplyPoint)
    print dist
    #the point on the road where the point should snap
    shplySnapPoint = shplyLineString.interpolate(shplyLineString.project(shplyPoint))
    #add rubber bands to the new points
    snapGeometry = QgsGeometry.fromWkt(shapely.wkt.dumps(shplySnapPoint))
    r = QgsRubberBand(canvas,QGis.Point)
    r.setColor(Qt.red)
    r.setToGeometry(snapGeometry,pointLayer)

Изменить: только что обнаружил, что метод @radouxju с использованием closestSegmentWithContext дает те же результаты в меньшем количестве строк кода. Интересно, почему они придумали это странное имя метода? должно было быть что-то вроде closestPointOnGeometry.

Таким образом, мы можем избежать стройной и делать, как,

nearFeature = QgsFeature()
nearestIterator.nextFeature(nearFeature)   

closeSegResult = nearFeature.geometry().closestSegmentWithContext(ptGeom.asPoint())
closePoint = closeSegResult[1]
snapGeometry = QgsGeometry.fromPoint(QgsPoint(closePoint[0],closePoint[1])) 

p1 = ptGeom.asPoint()
p2 = snapGeometry.asPoint()

dist = math.hypot(p2.x() - p1.x(), p2.y() - p1.y())
print dist
Винаян
источник
1
натыкаясь на кошмар, пытаясь отформатировать этот код Python
Винаян
5

вот псевдокод для начала. Я надеюсь, что это поможет и что у кого-то будет время предоставить полный код (у меня нет в настоящее время)

Первое, что нужно сделать, это зациклить точку и выбрать линии, которые находятся в пределах порогового расстояния до каждой точки. Это можно сделать с помощью 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 означает справа) 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)
radouxju
источник