Spostamento di punti su linee (~ vicinato)


14

Ho due livelli vettoriali, di cui uno è un livello punti basato su "eventi" mediante telerilevamento e il secondo è un livello linea proveniente dalla ricerca locale.

Nel mio caso si tratta di terremoti e difetti tettonici, ma immagino che si possa semplicemente scegliere "incidenti stradali e strade" come esempio generale.

Quindi quello che mi piacerebbe fare è spostare / copiare i punti sul punto più vicino delle linee, purché si trovi entro una distanza di tolleranza (diciamo 1-2km o 0.0xx °), con il nuovo livello punti (+ attr spostato y / n).

Qualche idea ?

Linux, QGIS 1.8



Stai cercando una funzione totalmente automatizzata per fare questo, o sarebbe una sorta di strumento di scatto per farlo manualmente?
Simbamangu,

Ho fatto una domanda simile, stavo cercando di agganciare la linea ai punti ma non ho mai trovato una soluzione facile. gis.stackexchange.com/questions/52232/…
GreyHippo

Che dire della triangolazione e della corrispondenza della distanza?
huckfinn,

Ho trovato questa domanda su un metodo che funziona in ArcGIS usando Near. Sono andato alla ricerca di QGIS quasi equivalente e ho trovato questo post nel forum in cui qualcuno ha suggerito GRASS v. Distanza. Questo mi ha portato a questo tutorial che può identificare un metodo. Forse da qualche parte lì dentro qualcuno ha scritto un plugin ormai?
Chris W,

Risposte:


13

Ha pubblicato uno snippet di codice (testato nella console di Python) che esegue le operazioni seguenti

  1. Utilizzare QgsSpatialIndex per trovare la funzione di linea più vicina a un punto
  2. Trova il punto più vicino su questa linea al punto. Ho usato un pacchetto ben fatto come scorciatoia per questo. Ho trovato i metodi QGis per questo insufficienti (o molto probabilmente non li capisco correttamente)
  3. Aggiunti elastici nei punti di aggancio
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)

Modifica: Proprio ora ho scoperto che il metodo @radouxju usando il metodo più ravvicinatoWithContext fornisce gli stessi risultati in meno righe di codice. Mi chiedo perché abbiano inventato questo strano nome di metodo? avrebbe dovuto essere qualcosa di simile aPointPointOnGeometry.

Quindi possiamo evitare formosamente e fare come,

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
incappando in un incubo cercando di formattare questo codice Python..argh !!
Vinayan,

5

ecco uno pseudo-codice per cominciare. Spero che questo aiuti e che qualcuno abbia il tempo di fornire il codice completo (non ho al momento)

la prima cosa da fare è fare un ciclo sul punto e selezionare le linee che si trovano all'interno della distanza di soglia per ciascun punto. Questo può essere fatto con QgsSpatialIndex

All'interno del primo ciclo, la seconda cosa da fare è fare un ciclo sulle linee selezionate e trovare il punto più vicino sulla linea. Questo può essere fatto direttamente sulla base di QgsGeometry :: latestSegmentWithContext

double QgsGeometry :: latestSegmentWithContext (const QgsPoint & point, QgsPoint & minDistPoint, int & afterVertex, double * leftOf = 0, double epsilon = DEFAULT_SEGMENT_EPSILON)

Cerca il segmento di geometria più vicino a un determinato punto.

Parametri point Specifica il punto per la ricerca

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: restituisce se il punto si trova sulla sinistra del lato destro del segmento (<0 significa sinistra,> 0 significa destra) epsilon epsilon per lo snap a segmenti (aggiunto in 1.8)

il terzo passo (all'interno del primo ciclo) consisterebbe nell'aggiornamento della geometria del punto con la geometria del minDistPoint con la distanza minima

aggiornamento con un po 'di codice (su 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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.