จุดย้ายเข้าสู่เส้น (~ ละแวกใกล้เคียง)


14

ฉันมีเลเยอร์เวกเตอร์สองอันโดยที่หนึ่งเป็นเลเยอร์จุดที่อิงจาก "เหตุการณ์" โดยการสำรวจระยะไกลและอันที่สองคือเลเยอร์บรรทัดจากการวิจัยในท้องถิ่น

ในกรณีของฉันเหล่านี้คือแผ่นดินไหวและความผิดปกติของเปลือกโลก แต่ฉันคิดว่าใคร ๆ ก็สามารถเลือก "อุบัติเหตุทางรถยนต์และถนน" เป็นตัวอย่างทั่วไปได้

สิ่งที่ฉันอยากทำก็คือเลื่อน / คัดลอกคะแนนไปยังจุดที่ใกล้ที่สุดของเส้นตราบใดที่มันอยู่ในระยะที่ยอมรับได้ (พูด 1-2km หรือ 0.0xx °) โดยที่จุดเลเยอร์ใหม่ (+ attr ถูกย้าย Y / n)

ความคิดใด ๆ

Linux, QGIS 1.8



คุณกำลังมองหาฟังก์ชั่นอัตโนมัติทั้งหมดในการทำเช่นนี้หรือจะใช้เครื่องมือจัดเรียงเพื่อทำมันด้วยมือได้ไหม?
Simbamangu

ฉันถามคำถามที่คล้ายกันฉันพยายาม snap จุดไปยังจุด แต่ไม่เคยพบทางออกที่ง่าย gis.stackexchange.com/questions/52232/…
GreyHippo

สิ่งที่เกี่ยวกับการจับคู่สมการและระยะทาง?
huckfinn

ฉันพบคำถามนี้เกี่ยวกับวิธีการที่ทำงานใน ArcGIS โดยใช้ Near ไปค้นหา QGIS ใกล้เทียบเท่าและพบโพสต์ฟอรัมนี้ที่มีคนแนะนำ GRASS v.distance นั่นทำให้ฉันไปที่บทช่วยสอนนี้ซึ่งอาจระบุวิธีการ อาจจะมีบางคนในนั้นเขียนปลั๊กอินโดยตอนนี้?
Chris W

คำตอบ:


13

โพสต์โค้ดขนาดเล็ก (ทดสอบในคอนโซลหลาม) ที่ทำตามด้านล่าง

  1. ใช้ QgsSpatialIndex เพื่อค้นหาคุณลักษณะบรรทัดที่ใกล้ที่สุดไปยังจุด
  2. ค้นหาจุดที่ใกล้ที่สุดในบรรทัดนี้ไปยังจุด ฉันใช้แพคเกจหุ่นดีเป็นทางลัดสำหรับสิ่งนี้ ฉันพบว่าวิธีการของ QGis ไม่เพียงพอ (หรือส่วนใหญ่ฉันอาจไม่เข้าใจอย่างถูกต้อง)
  3. เพิ่มสายรัดยางในตำแหน่ง snap
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 จะให้ผลลัพธ์เดียวกันในบรรทัดของรหัสที่น้อยลง ฉันสงสัยว่าทำไมพวกเขาถึงมีชื่อวิธีแปลก ๆ นี้? น่าจะเป็นสิ่งที่ใกล้เคียง 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

นี่คือรหัสหลอกที่จะเริ่มต้นด้วย ฉันหวังว่านี่จะช่วยได้และใครบางคนจะมีเวลาให้รหัสเต็ม (ฉันยังไม่มีในขณะนี้)

สิ่งแรกที่ต้องทำคือการวนรอบจุดและเลือกบรรทัดที่อยู่ภายในระยะทางขีด จำกัด ของแต่ละจุด Thi สามารถทำได้ด้วย QgsSpatialIndex

ภายในลูปแรกสิ่งที่สองที่ต้องทำคือการวนลูปในบรรทัดที่เลือกและค้นหาจุดที่ใกล้ที่สุดในบรรทัด ซึ่งสามารถทำได้โดยตรงตาม QgsGeometry :: closestSegmentWithContext

double QgsGeometry :: closestSegmentWithContext (const QgsPoint & point, QgsPoint & minDistPoint, int & afterVertex, double * 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 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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.