Aligner plusieurs points sur la ligne dans QGIS?

11

Je voudrais aligner plusieurs points sur une ligne, ou des lignes à l'intérieur d'un calque, en utilisant une tolérance ou un tampon spécifié autour des objets de ligne. Veuillez vous référer à l'exemple de croquis ci-joint.

Pour les besoins de cet exemple, les points les plus proches de la ligne dans l'image AVANT sont à moins de 5 unités de carte de la ligne, tandis que les points les plus à l'extérieur sont à plus de 10 unités de carte. Je voudrais accrocher les points les plus proches sur la ligne la plus proche, en utilisant une tolérance de 5 unités de carte pour obtenir le résultat dans l'image APRÈS.

entrez la description de l'image ici

Ed Camden
la source
Le point doit donc être à 0 unité de carte latéralement de la ligne, mais vous souciez-vous de l'endroit où le point se termine longitudinalement par rapport à l'emplacement d'origine du point?
Joe
Le scénario idéal serait de déplacer les points en utilisant un chemin perpendiculaire à la ligne. Cependant, l'intention est d'utiliser des tolérances assez faibles. Si les points sont déplacés longitudinalement ou latéralement, vers la ligne, cela ne compensera pas beaucoup les points par rapport à une position perpendiculaire préférable.
Ed Camden
Je ne sais pas si c'est la meilleure façon, mais je peux penser à une façon d'écrire du code python pour analyser les deux jeux de données et produire des coordonnées ponctuelles. Si c'est ce que vous pensez vouloir, faites-le moi savoir et je pourrai vous répondre. Par exemple, pour chaque point, si la valeur absolue de lat dist de la ligne <= 5 unités, alors la distance latérale = 0. Vous devrez importer une bibliothèque gdal pour convertir les valeurs x, y en coordonnées. Voir les commentaires dans: gis.stackexchange.com/questions/185445/…
Joe
Avec PyQGIS, il peut être produit une couche de mémoire où les points sont capturés selon la tolérance précédemment considérée de 5 unités de carte et un chemin perpendiculaire à la ligne. Voir ma réponse.
xunilk

Réponses:

15

Il existe un outil intégré pour le faire dans la version (non publiée) de QGIS 3.0. Vous pouvez obtenir un instantané nocturne sur le site Web de QGIS pour le tester à l'avance.

Pour faire ça:

  1. Exécutez l'algorithme de traitement "Snap geometries to layer"
  2. Sélectionnez votre couche de points comme "couche d'entrée"
  3. Sélectionnez le calque de ligne comme "calque de référence"
  4. Entrez une tolérance appropriée (distance maximale pour déplacer les points lors de l'accrochage)
  5. Changez le comportement en "Préférer le point le plus proche"

entrez la description de l'image ici

Voici le résultat, montrant les points d'origine sous forme de «x» et les points cassés sous forme de points verts. J'ai utilisé une tolérance ici afin que seuls certains points d'entrée soient capturés.

entrez la description de l'image ici

ndawson
la source
C'est exactement ce dont j'ai besoin. Malheureusement, mon employeur installe uniquement les versions LTR de QGIS et nous ne pouvons tous télécharger et installer des versions de test. (soupir) Je suppose que c'est une question d'attente. S'agit-il d'une fonction standard / intégrée ou d'un plug-in?
Ed Camden
Fonctionnalité standard reposant sur les changements dans les classes c ++ - il n'y a aucun moyen de copier manuellement cela dans une version plus ancienne. Vous pouvez éventuellement essayer d'installer OSGEO4W sur une autre machine, puis copier le dossier osgeo4w sur une clé USB pour l'exécuter sur votre poste de travail. J'ai eu de la chance avec cette approche dans le passé.
ndawson
1
Pour l'ancienne version jetez un oeil sur ce plugin. docs.qgis.org/2.14/en/docs/user_manual/plugins/…
iRfAn
il semble que le plugin ne supporte pas les couches de points.
Mykola Kozyr
7

Cela peut être possible avec PyQGIS . Pour la prochaine situation:

entrez la description de l'image ici

le code suivant, considérant une tolérance de 5 unités de carte, a été exécuté sur la console Python de QGIS:

from math import sqrt

registry = QgsMapLayerRegistry.instance()

points = registry.mapLayersByName('points')
line = registry.mapLayersByName('line')

feat_points = [ feat for feat in points[0].getFeatures() ]
feat_line = line[0].getFeatures().next()

new_points = []

for feat in feat_points:
    pt = feat.geometry().asPoint()
    sqrdist, point, vertex = feat_line.geometry().closestSegmentWithContext(pt)
    if sqrt(sqrdist) <= 5:
        new_points.append(point)
    else:
        new_points.append(pt)

epsg = points[0].crs().postgisSrid()

uri = "Point?crs=epsg:" + str(epsg) + "&field=id:integer""&index=yes"

mem_layer = QgsVectorLayer(uri,
                           'new_points',
                           'memory')

prov = mem_layer.dataProvider()

feats = [ QgsFeature() for i in range(len(new_points)) ]

for i, feat in enumerate(feats):
    feat.setAttributes([i])
    feat.setGeometry(QgsGeometry.fromPoint(new_points[i]))

prov.addFeatures(feats)

QgsMapLayerRegistry.instance().addMapLayer(mem_layer)

Il a été produit une couche de mémoire où les points ont été capturés selon la tolérance précédemment considérée de 5 unités de carte et un chemin perpendiculaire à la ligne.

entrez la description de l'image ici

xunilk
la source
2

Vous pouvez également le faire dans le Field Calculator avec le plugin refFunctions. Vous pouvez utiliser la calculatrice de champs pour mettre à jour une géométrie de couche ainsi que des champs. refFunctions vous donne une fonction "geomdistance" pour trouver la ligne la plus proche dans une distance donnée (ou "geomnearest" si vous ne voulez pas de seuil) et retournera un attribut ou la géométrie, et la fonction "most_point" trouvera la plus proche point sur une géométrie donnée. Enchaînez-les comme pour calculer de nouvelles géométries pour votre couche de points:

closest_point(geom_from_wkt(geomdistance('snap_lines','$geometry',10)) , $geometry)

Au lieu de mettre à jour directement la géométrie, vous pouvez plutôt calculer un champ avec la géométrie accrochée. Je stocke plusieurs géométries pour aligner les points de ponceau sur différentes couches de cours d'eau et je peux facilement mettre à jour la géométrie des points dans la calculatrice de terrain en fonction des lignes de cours d'eau que je dois utiliser.

Il y a quelques limites à cela, les deux couches doivent être le même CRS et la fonction géomdistance vous donnera une erreur si vous avez plus de 100000 points mais vous pouvez changer cette limite si vous éditez le fichier du plugin refFunctions.

amcaninch
la source