Переміщення точок на лінії (~ околиці)


14

У мене є два векторних шару, з яких один - точковий шар, заснований на "подіях" за допомогою дистанційного зондування, а другий - це лінійний шар з місцевих досліджень.

У моєму випадку це землетруси та тектонічні розломи, але, мабуть, можна просто вибрати "автомобільні аварії та дороги" як загальний приклад.

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

Будь-які ідеї?

Linux, QGIS 1.8



Ви шукаєте цілком автоматизовану функцію для цього, чи був би якийсь інструмент для оснащення, щоб зробити це вручну?
Simbamangu

Я задав подібне запитання, я намагався підключити лінію до балів, але не знайшов простого рішення. gis.stackexchange.com/questions/52232/…
GreyHippo

А як щодо триангуляції та узгодження відстаней?
huckfinn

Я знайшов це питання щодо методу, який працює в ArcGIS, використовуючи Near. Пішов шукати еквівалент QGIS і знайшов цей форум, де хтось запропонував GRASS v.distance. Це приведе мене до цього підручника, який може визначити метод. Можливо, десь там хтось уже написав плагін?
Chris 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 за допомогою najbližeSegmentWithContext дає ті самі результати за меншими рядками коду. Цікаво, чому вони придумали цю дивну назву методу? повинно було бути на кшталт найближчогоPointOnGeometry.

Тож ми можемо уникати струнких і подібних дій,

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
зіткнувшись з кошмаром, намагаючись відформатувати цей код пітона.
vinayan

5

ось псевдокод для початку. Я сподіваюся, що це допоможе, і що хтось встигне надати повний код (у мене зараз немає)

Перше, що потрібно зробити, це зробити цикл на точці та вибрати лінії, які знаходяться в межах порогової відстані до кожної точки. Це можна зробити за допомогою 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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.