선으로 점 이동 (~ 이웃)


14

두 개의 벡터 레이어가 있는데 그 중 하나는 원격 감지에 의한 "이벤트"를 기반으로하는 포인트 레이어이고 두 번째는 로컬 리서치의 라인 레이어입니다.

내 경우에는 지진과 지각 결함이지만 일반적인 예로 "자동차 사고와 도로"를 선택할 수 있다고 생각합니다.

그래서 내가하고 싶은 것은 새로운 포인트 레이어 (+ attr 이동)를 사용하여 공차 거리 (1 ~ 2km 또는 0.0xx °) 내에서 라인의 가장 가까운 지점으로 포인트를 이동 / 복사하는 것입니다 y / n).

어떤 아이디어?

리눅스, QGIS 1.8



이 작업을 수행하기 위해 완전히 자동화 된 기능을 찾고 있습니까, 아니면 수동으로 수행 할 수있는 일종의 스냅 도구가 좋습니까?
Simbamangu

비슷한 질문을했는데, 선을 점으로 맞추려고했지만 결코 쉬운 해결책을 찾지 못했습니다. gis.stackexchange.com/questions/52232/…
GreyHippo

삼각 분할과 거리 매칭은 어떻습니까?
huckfinn

Near를 사용하여 ArcGIS에서 작동하는 방법에 대한 이 질문을 찾았습니다 . QGIS Near equivalent을 검색하여 누군가 GRASS v.distance를 제안한 이 포럼 게시물을 찾았 습니다. 그것은 저를 이끌어 이 튜토리얼 방법을 식별 할 수 있습니다. 어쩌면 누군가 어딘가에 플러그인을 작성했을까요?
Chris W

답변:


13

아래를하지 않는 코드 스 니펫 (파이썬 콘솔에서 테스트 됨)을 게시했습니다.

  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)

편집 : 이제 closestSegmentWithContext를 사용하는 @radouxju 메소드가 적은 코드 줄로 동일한 결과를 제공한다는 것을 알았습니다. 왜 그들이 이상한 방법 이름을 생각해 냈을 까? 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
이 파이썬 코드를 포맷하려고하는 악몽에 빠져 ..argh !!
vinayan

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은 오른쪽) 엡실론 엡실론 세그먼트 스냅 (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)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.