Erstellen von äquidistanten Punkten in QGIS?

22

Ich versuche, in QGIS Punkte (neue Ebene) in einem bestimmten Abstand entlang der Straße (vorhandene Ebene) zu erstellen. Erstellen von regelmäßigen Punkten für jeden Zähler auf Kreisebene mit ArcGIS Desktop? gibt Lösung für ArcGIS. Wie erreicht man das in QGIS? Hinzufügen von Punkten zur Punktvektorebene mit QGIS? Erklärt das Erstellen von Punkten, ändert aber nichts an der Entfernung.


(Ich habe die vorgeschlagenen Lösungen mit unterschiedlichen Längenmaßen angewendet, da ich die Umrechnung nicht kannte.) @Nathanss Lösung funktionierte in gewissem Maße, ich bekam ...

Bildbeschreibung hier eingeben. Hier unterscheidet sich die Projektion dieser äquidistanten Punkte von der ursprünglichen Linie.

Mit @ underdarks Vorschlag bekam ich

dieses Bildwo die Punkte nicht äquidistant zu sein scheinen. Ich vermute, dass es bei beiden ein Projektionsproblem gibt, das ich nicht verstehe.

Stat-R
quelle
2
Ein paar Punkte. Erstens muss die Linie in einem projizierten CRS sein (nicht lat / lon). Zweitens ist Ihre Linie eine echte Polylinie? Ich glaube nicht, dass eine Methode in einer Zeile, die aus einer Reihe einzelner Zeilen besteht, richtig funktioniert. Nick.
nhopton
Auch mit meinem Code müssen Sie die import locateLeitung nicht mehr als einmal anrufen . Rufen Sie einfach einmal an, dann können Sie locate.pointsAlongLine(30)so oft anrufen , wie Sie möchten
Nathan W
Eine andere Methode (vorausgesetzt, dass Sextant, wie in einigen Antworten hier vorgeschlagen, nur QGIS <2.0 ist) ist die Verwendung des Plugins namens QChainage.
Andy

Antworten:

14

Hinweis: Es gibt jetzt ein QGIS-Plugin QChainage. Das alles und noch viel mehr. Der folgende Code ist mit QGIS 2.0 und höher nicht mehr aktuell.

Hier ist ein Python-Code, den Sie in eine Datei einfügen und in QGIS verwenden können:

QGIS verfügt über eine Methode in der API, mit der Verweise auf Linien erstellt werden können. Ich konnte sie jedoch nicht zum korrekten Funktionieren bringen. Ich werde mich jedoch an den Autor des Codes wenden und prüfen, ob ich etwas falsch gemacht habe.

Fürs Erste benötigen Sie die formschöne Python-Bibliothek, die Sie trotzdem installieren sollten, da es praktisch ist, sie in der Nähe zu haben. Es hat auch eine großartige Dokumentation unter http://toblerity.github.com/shapely/manual.html

Dies ist der Abschnitt, den ich im folgenden Beispiel verwende: http://toblerity.github.com/shapely/manual.html#interoperation .

Der größte Teil des folgenden Codes ist QGIS-Boilerplate-Code, der nur die Features und Layer erstellt und von wkb und wkt und zurück konvertiert. Das Kernbit ist das, point = line.interpolate(currentdistance)das einen Punkt in einem Abstand entlang einer Linie zurückgibt. Wir wickeln dies einfach in eine Schleife, bis wir keine Linie mehr haben.

import qgis
from qgis.core import *
from PyQt4.QtCore import QVariant
from shapely.wkb import loads
from shapely.wkt import dumps

vl = None
pr = None

def createPointsAt(distance, geom):
    if distance > geom.length():
        print "No Way Man!"
        return

    length = geom.length()
    currentdistance = distance
    feats = []  

    while currentdistance < length: 
        line = loads(geom.asWkb())
        point = line.interpolate(currentdistance)
        fet = QgsFeature()
        fet.setAttributeMap( { 0 : currentdistance } )
        qgsgeom = QgsGeometry.fromWkt(dumps(point))
        fet.setGeometry(qgsgeom)
        feats.append(fet)
        currentdistance = currentdistance + distance

    pr.addFeatures(feats)
    vl.updateExtents()

def pointsAlongLine(distance):
    global vl
    vl = QgsVectorLayer("Point", "distance nodes", "memory")
    global pr
    pr = vl.dataProvider()  
    pr.addAttributes( [ QgsField("distance", QVariant.Int) ] )
    layer = qgis.utils.iface.mapCanvas().currentLayer()
    for feature in layer.selectedFeatures():
        geom = feature.geometry()
        createPointsAt(distance, geom)

    QgsMapLayerRegistry.instance().addMapLayer(vl)

Kopieren Sie den obigen Code und fügen Sie ihn in die Datei "my locate.py" im ~./qgis/pythonVerzeichnis ein (weil es sich im Python-Pfad befindet). Führen Sie dies einfach in der Python-Konsole in QGIS aus.

 import locate
 locate.pointsAlongLine(30)

Auf diese Weise wird entlang der ausgewählten Linien alle 30 Meter eine neue Punktebene mit Punkten erstellt.

Bildbeschreibung hier eingeben

Hinweis: Code ist ziemlich rau und muss möglicherweise bereinigt werden.

BEARBEITEN: Der neueste QGIS-Entwickler kann dies jetzt nativ tun.

Ändern Sie die while-Schleife in createPointsAt:

 while currentdistance < length: 
    point = geom.interpolate(distance)
    fet = QgsFeature()
    fet.setAttributeMap( { 0 : currentdistance } )
    fet.setGeometry(point)
    feats.append(fet)
    currentdistance = currentdistance + distance

und Sie können die entfernen

from shapely.wkb import loads
from shapely.wkt import dumps
Nathan W
quelle
Vielen Dank an Nathan. Ich konnte das Shapely-Paket für meine Python nicht bekommen. Ich habe Python 2.7 installiert, aber das Shapely-Installationsprogramm gibt an, dass Python 2.7 nicht in meiner Registrierung enthalten ist. Gibt es eine andere Möglichkeit, Shapely zu installieren?
Stat-R
Ich folgte stackoverflow.com/questions/3652625/… und tippte die beiden obigen Zeilen ein, um sie aufzurufen locateund zu verwenden, bekam aber immer noch nicht die äquidistanten Punkte. Außerdem bin ich ein Neuling in Python, daher habe ich nicht verstanden, wo ich den Code (1) python im qgis-Verzeichnis oder (2) das unter C: \ Python27 \ ausführen soll.
Stat-R
Auf welchem ​​Betriebssystem bist du?
Nathan W
Windows 7 Professional
Stat-R
erstelle die Python-Datei in C:\Users\{you user name}\.qgis\pythonQGIS und starte es neu, wenn es geöffnet ist, und gehe zu "Plugins-> Python Console . Load a line layer, select a line a call import locate" undlocate.pointsAlongLine(30)
Nathan W
5

Sie können das QGIS GRASS-Plugin v.to.points verwenden, um in regelmäßigen Abständen Punkte entlang von Linien zu erstellen

# convert line to points; dmax = distance between points
v.to.points -i -v -t in=road out=road_pts type=line dmax=90
Underdunkel
quelle
Ich habe dmax als 100 verwendet und die daraus resultierenden Projektionen sind wie folgt. (Ich weiß nicht, wie das CRS von selbst zugewiesen wird.)CRS of Original Shape file, the line = EPSG:26915 - NAD83 / UTM zone 15N, CRS of Grass line vector obtained using v.in.ogr = EPSG:4269 - NAD83, CRS of Grass points vector obtained using v.to.points = EPSG:4326 - WGS 84
Stat-R
Nun auch so: QGIS -> Sextante -> GRASS -> v.to.points
markusN
5

Wenn Sie die Verkettung in festgelegten Intervallen entlang einer Straßenlinie zeichnen möchten, können Sie das Plug-In "Profil ab Linie" verwenden. Sie benötigen ein DEM unter dem Straßenrand, aber der Vorgang ist schnell und sehr einfach. Nick.

Bildbeschreibung hier eingeben

nhopton
quelle
Dies ist auch eine ziemlich gute und einfache Methode, danke!
Shepherdjo
2

Beachten Sie, dass das Shapely (Python) / GEOS (C ++) - Datenmodell in einer Ebene definiert ist. Wenn Ihre Punkte also aus GPS-Positionen (Breitengrad, Längengrad) bestehen, wird mit dieser shapely.geometry.LineString.interpolate(distance)Methode eine GPS-Position in der euklidischen Entfernung entlang der angegebenen Position ausgegeben LineString.

Shapelys interpolate()basiert auf der geos::linearref::LengthIndexedLineKlasse von GEOS, die diese extractPointMethode verwendet.

Angeblich ist die gleichmäßig verteilte Interpolation in der Breiten- und Längengradebene ausreichend für Anwendungen, die relativ kleine Entfernungen berücksichtigen. Im Allgemeinen sollte man jedoch die Entfernung auf einer Kugel für GIS-Anwendungen berücksichtigen (wie in WGS84 definiert ).

Ich kann mir zwei Problemumgehungen mit dem Shapely-Modul vorstellen:

  • LineStringEigenschaften sind alle gegebenen Punkte und linear interpolierte Kurven entlang dieser. Vielleicht können Sie ein Element schreiben, das auf die interpolierten Kurven zugreift, und das folgende Linienintegral implementieren, wobei der euklidische Abstand ersetzt wird. Ich mag diesen Ansatz, weil mit der stückweise durchgehenden Kurve die gewünschten Punkte erhalten werden können, indem die Schnittpunkte benachbarter Kreise entlang der Kurve mit dem Radius berechnet werden r = radian_measure(arc_length) = arc_length / R, wobei R dem Radius der Erde an der angegebenen Position entspricht.
  • Codieren Sie Ihre eigene Interpolationsmethode (ohne Shapely-Code zu berühren) mit einer geeigneten Distanzfunktion (z. B. Haversine-Formel).

Um dies zu erreichen, möchte ich mich auf die folgende StackOverflow-Frage und insbesondere auf diese Antwort beziehen :

Entlang der Kurve können äquidistante Punkte erzeugt werden. Aber es muss mehr Definition geben, was Sie für eine echte Antwort wollen. Entschuldigung, aber der Code, den ich für diese Aufgabe geschrieben habe, ist in MATLAB, aber ich kann die allgemeinen Ideen beschreiben. Es gibt drei Möglichkeiten.

Erstens, sind die Punkte in Bezug auf eine einfache euklidische Distanz wirklich gleich weit von den Nachbarn entfernt? Dazu müsste der Schnittpunkt an einem beliebigen Punkt der Kurve mit einem Kreis mit festem Radius gefunden werden. Dann gehen Sie einfach die Kurve entlang.

Wenn Sie als Nächstes beabsichtigen, dass der Abstand den Abstand entlang der Kurve selbst bedeutet, und wenn die Kurve stückweise linear ist, ist das Problem wieder leicht zu lösen. Gehen Sie einfach die Kurve entlang, da der Abstand auf einem Liniensegment einfach zu messen ist.

Wenn Sie schließlich vorhaben, dass die Kurve ein kubischer Spline ist, ist dies wiederum nicht unglaublich schwierig, aber es ist ein bisschen mehr Arbeit. Hier ist der Trick:

  • Berechnen Sie die stückweise lineare Bogenlänge von Punkt zu Punkt entlang der Kurve. Nennen Sie es t. Erzeugen Sie ein Paar kubischer Splines, x (t), y (t).

  • Differenziere x und y als Funktionen von t. Da es sich um kubische Segmente handelt, ist dies einfach. Die Ableitungsfunktionen sind stückweise
    quadratisch.

  • Verwenden Sie einen Odenlöser, um sich entlang der Kurve zu bewegen, und integrieren Sie die Funktion für die differentielle Bogenlänge. In MATLAB hat ODE45 gut funktioniert.

Man integriert also

sqrt((x')^2 + (y')^2)

Auch in MATLAB kann ODE45 so eingestellt werden, dass die Stellen identifiziert werden, an denen die Funktion bestimmte festgelegte Punkte kreuzt.

Wenn Ihre MATLAB-Kenntnisse der Aufgabe gewachsen sind, können Sie sich den Code im Interparc genauer ansehen . Es ist einigermaßen gut kommentierter Code.

3 : http://www.mathworks.com/matlabcentral/fileexchange/34874-interparc

Patryk
quelle
1

Sextante hat ein Tool, das für Sie arbeiten könnte. Sextante kann aus dem Qgis-Plugin-Repository heruntergeladen werden.

Suchen Sie nach:
"Werkzeuge für
Linienebenen " "Linien zu gleichmässigen Punkten"

klewis
quelle
Dieses Plugin ist offenbar nicht für QGIS 2 oder 3 verfügbar.
Martin Burch