Créer des points équidistants dans QGIS?

22

J'essaie de créer des points (nouvelle couche) à une distance spécifique le long de la route (couche existante) dans QGIS. Créer des points réguliers chaque mètre au niveau du comté à l'aide d'ArcGIS Desktop? fournit une solution pour ArcGIS. Comment y parvenir dans QGIS? Ajouter des points à la couche vectorielle de points à l'aide de QGIS? explique comment créer des points mais ne fait rien sur la distance.


(J'ai appliqué les solutions proposées avec différentes mesures de longueurs car je ne connaissais pas la conversion) @ La solution de Nathans a fonctionné dans une certaine mesure, j'ai eu ...

entrez la description de l'image ici. Ici, la projection de ces points équidistants est différente de la ligne d'origine.

Avec la suggestion de @ underdark, j'ai eu

cette imageoù les points ne semblent pas équidistants. Je suppose qu'il y a un problème de projection avec ces deux éléments que je ne comprends pas.

Stat-R
la source
2
Quelques points. Premièrement, la ligne doit être dans un CRS projeté (pas lat / lon). Deuxièmement, votre ligne est-elle une véritable polyligne? Je ne pense pas qu'une méthode fonctionnera correctement sur une ligne comprenant une chaîne de lignes individuelles. Entaille.
nhopton
De plus, avec mon code, vous n'avez pas besoin d'appeler la import locateligne plus d'une fois. Appelez-le une seule fois et vous pourrez appeler locate.pointsAlongLine(30)autant que vous le souhaitez
Nathan W
Une autre méthode (étant donné que Sextant comme suggéré par certaines réponses ici est QGIS <2.0 uniquement), consiste également à utiliser le plugin appelé QChainage.
andy

Réponses:

14

Remarque: Il existe maintenant un plugin QGIS QChainage. Il fait tout cela et plus encore. Le code ci-dessous est obsolète avec QGIS 2.0 et supérieur.

Voici du code Python que vous pouvez coller dans un fichier et utiliser dans QGIS:

QGIS possède une méthode dans l'API pour faire le référencement de ligne, mais je n'ai pas pu le faire fonctionner correctement, mais je vais contacter l'auteur du code et voir si je faisais quelque chose de mal.

Pour l'instant, vous aurez besoin de la bibliothèque Python galbée , que vous devez installer de toute façon car elle est pratique à avoir autour. Il a également une excellente documentation sur http://toblerity.github.com/shapely/manual.html

Il s'agit de la section que j'utilise dans l'exemple suivant http://toblerity.github.com/shapely/manual.html#interoperation .

La plupart du code suivant est du code passe-partout QGIS créant simplement les fonctionnalités, les couches, la conversion de wkb et wkt et vice-versa. Le trépan est le point = line.interpolate(currentdistance)qui renvoie un point à distance le long d'une ligne. Nous emballons simplement cela dans une boucle jusqu'à ce que nous manquions de ligne.

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)

Copiez et collez le code ci-dessus dans un fichier, j'ai appelé mon Locate.py, dans le ~./qgis/pythonrépertoire (car il se trouve dans le chemin Python) et faites-le dans la console Python à l'intérieur de QGIS.

 import locate
 locate.pointsAlongLine(30)

Cela créera une nouvelle couche de points avec des points tous les 30 mètres le long des lignes sélectionnées, comme ceci:

entrez la description de l'image ici

Remarque: Le code est assez approximatif et peut nécessiter un nettoyage.

EDIT: La dernière version de développement de QGIS peut maintenant le faire en mode natif.

Remplacez la boucle while par createPointsAt:

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

et vous pouvez supprimer le

from shapely.wkb import loads
from shapely.wkt import dumps
Nathan W
la source
Merci @Nathan. Je n'ai pas pu obtenir le package Shapely pour mon python. J'ai installé python 2.7 mais le programme d'installation de Shapely indique que python 2.7 n'est pas dans mon registre. Existe-t-il une autre façon d'installer Shapely?
Stat-R
J'ai suivi stackoverflow.com/questions/3652625/… et tapé les deux lignes ci-dessus pour appeler locateet l'utiliser mais je n'ai toujours pas obtenu les points équidistants. De plus, je suis néophyte en Python, donc je ne comprenais pas où exécuter le code (1) python dans le répertoire qgis ou (2) que sur C: \ Python27 \?
Stat-R
Sur quel OS êtes-vous?
Nathan W
Windows 7 Professionnel
Stat-R
créez le fichier python C:\Users\{you user name}\.qgis\pythonpuis redémarrez QGIS s'il est ouvert, et allez dans `Plugins-> Python Console . Load a line layer, select a line a call import localiser` etlocate.pointsAlongLine(30)
Nathan W
5

Vous pouvez utiliser l'outil plugin QGIS GRASS v.to.points pour créer des points le long des lignes à intervalles réguliers

# convert line to points; dmax = distance between points
v.to.points -i -v -t in=road out=road_pts type=line dmax=90
obscur
la source
J'ai utilisé dmax comme 100 et les projections résultantes pour chacune sont les suivantes. (Je ne sais pas comment le CRS est attribué par lui-même.)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
Maintenant aussi comme ceci: QGIS -> Sextante -> GRASS -> v.to.points
markusN
5

Si vous voulez tracer le chaînage à intervalles fixes le long d'une ligne de route, vous pouvez utiliser le plug-in "Profil de ligne" pour ce faire. Vous avez besoin d'un DEM sous la couche de la route, mais la procédure est rapide et très simple. Entaille.

entrez la description de l'image ici

nhopton
la source
c'est aussi une méthode assez bonne et facile, merci!
Shepherdjo
2

Attention, le modèle de données Shapely (Python) / GEOS (C ++) est défini dans un plan. Donc, si vos points sont constitués de positions GPS (latitude, longitude), la shapely.geometry.LineString.interpolate(distance)méthode affichera une position GPS à la distance euclidienne le long de la donnée LineString.

Shapely interpolate()est basé sur la geos::linearref::LengthIndexedLineclasse GEOS utilisant la extractPointméthode.

On suppose que l'interpolation également espacée dans le plan latitude-longitude est suffisante pour les applications qui considèrent des distances relativement petites. En général, cependant, il faut considérer la distance sur une sphère pour les applications SIG (telles que définies dans WGS84 ).

Je peux penser à deux solutions de contournement en utilisant le module Shapely:

  • LineStringles propriétés se voient toutes attribuer des points et des courbes interpolées linéairement le long de celles-ci. Vous pouvez peut-être écrire un membre qui accède aux courbes interpolées et implémenter l'intégrale de ligne suivante en remplaçant la distance euclidienne. J'adore cette approche car en utilisant la courbe continue par morceaux, les points souhaités peuvent être obtenus en calculant les intersections de cercles adjacents le long de la courbe avec le rayon r = radian_measure(arc_length) = arc_length / R, où R est égal au rayon de la Terre à la position donnée.
  • codez votre propre méthode d'interpolation (sans toucher au code Shapely) en utilisant une fonction de distance appropriée (par exemple une formule haversine).

Pour ce faire, je voudrais me référer à la question StackOverflow suivante et à cette réponse en particulier:

Il est possible de générer des points équidistants le long de la courbe. Mais il doit y avoir plus de définition de ce que vous voulez pour une vraie réponse. Désolé, mais le code que j'ai écrit pour cette tâche est dans MATLAB, mais je peux décrire les idées générales. Il y a trois possibilités.

Premièrement, les points doivent-ils être vraiment équidistants des voisins en termes de distance euclidienne simple? Pour ce faire, il faudrait trouver l'intersection en tout point de la courbe avec un cercle de rayon fixe. Il suffit ensuite de marcher le long de la courbe.

Ensuite, si vous prévoyez que la distance signifie la distance le long de la courbe elle-même, si la courbe est linéaire par morceaux, le problème est à nouveau facile à faire. Il suffit de marcher le long de la courbe, car la distance sur un segment de ligne est facile à mesurer.

Enfin, si vous avez l'intention que la courbe soit une spline cubique, ce n'est pas incroyablement difficile, mais c'est un peu plus de travail. Ici, l'astuce consiste à:

  • Calculez la longueur d'arc linéaire par morceaux d'un point à un autre le long de la courbe. Appelez ça t. Générez une paire de splines cubiques, x (t), y (t).

  • Différencier x et y en fonction de t. Comme ce sont des segments cubiques, c'est facile. Les fonctions dérivées seront
    quadratiques par morceaux .

  • Utilisez un solveur d'ode pour vous déplacer le long de la courbe, en intégrant la fonction de longueur d'arc différentielle. Dans MATLAB, ODE45 a bien fonctionné.

Ainsi, on intègre

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

Encore une fois, dans MATLAB, ODE45 peut être défini pour identifier les emplacements où la fonction traverse certains points spécifiés.

Si vos compétences MATLAB sont à la hauteur, vous pouvez consulter le code dans interparc pour plus d'explications. Il s'agit d'un code raisonnablement bien commenté.

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

Patryk
la source
1

Sextante a un outil qui pourrait fonctionner pour vous. Sextante peut être téléchargé à partir du référentiel de plugins Qgis.

Recherchez:
"Outils pour les couches de
lignes " "Lignes vers des points espacés"

klewis
la source
Ce plugin ne semble pas être disponible pour QGIS 2 ou 3.
Martin Burch