#1 Wed 28 June 2017 12:38
- hotegbe
- Participant occasionnel
- Date d'inscription: 28 Jun 2017
- Messages: 32
QGIS / Pyqgis: Algorithme De Dijkstra
Bonjour, je sollicite votre aide par rapport à l'API pyqgis.
étant nouveau utilisateur des SIG je souhaiterais réaliser une opération.
Il s'agit pour moi de recherher le plus court chemin dans un graphe en utilisant l'agorithme de DIJKSTRA.
Le code de la doc de qgis après quelques petites adaptations marche bien sauf que je ne récupère rien à la fin si ce n'est un tracé graphique. Je souhaiterais après léxécution récupérer le chemin le plus court retrouvé (le résultat) sous forme d'entité que j'insère dans une table et ainsi de suite pour éventuellement d'autres chemins plus courts que je calculerai.
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
from qgis.gui import *
from qgis.networkanalysis import *
vl = qgis.utils.iface.mapCanvas().currentLayer()
director = QgsLineVectorLayerDirector(vl, -1, '', '', '', 3)
properter = QgsDistanceArcProperter()
director.addProperter(properter)
crs = qgis.utils.iface.mapCanvas().mapRenderer().destinationCrs()
builder = QgsGraphBuilder(crs)
pStart = QgsPoint(-0.835953, 0.15679)
pStop = QgsPoint(-1.1027, 0.699986)
tiedPoints = director.makeGraph(builder, [pStart, pStop])
graph = builder.graph()
tStart = tiedPoints[0]
tStop = tiedPoints[1]
idStart = graph.findVertex(tStart)
idStop = graph.findVertex(tStop)
(tree, cost) = QgsGraphAnalyzer.dijkstra(graph, idStart, 0)
if tree[idStop] == -1:
print "Path not found"
else:
p = []
curPos = idStop
while curPos != idStart:
p.append(graph.vertex(graph.arc(tree[curPos]).inVertex()).point())
curPos = graph.arc(tree[curPos]).outVertex();
p.append(tStart)
rb = QgsRubberBand(qgis.utils.iface.mapCanvas())
rb.setColor(Qt.red)
for pnt in p:
rb.addPoint(pnt).[/b]
Pourriez vous m'aider svp à améliorer ce code ?
Merci
Hors ligne
#2 Wed 28 June 2017 15:21
- Sylvain PIERRE
- Participant assidu
- Lieu: Strasbourg
- Date d'inscription: 6 Sep 2005
- Messages: 170
Re: QGIS / Pyqgis: Algorithme De Dijkstra
Bonjour,
Il vous manque quelque chose à la fin du traitement.
Le résultat est en l'état uniquement stockée dans la QgsRubberBand qui n'est qu'une couche graphique recevant les objets créés lorsqu'on dessine des lignes ou des polygones.
Il faut donc transformer ces objets graphiques en objets géographiques
Code:
geom = rb .asGeometry() polyline = geom.asGeometryCollection()[0].asPolyline()
Il vous faudra également "pousser" ces objets géographiques dans une layer, voir ici: http://docs.qgis.org/testing/en/docs/py … ector.html
Voilà qq pistes pour avancer
Sylvain
Hors ligne
#3 Wed 28 June 2017 15:52
- hotegbe
- Participant occasionnel
- Date d'inscription: 28 Jun 2017
- Messages: 32
Re: QGIS / Pyqgis: Algorithme De Dijkstra
Bonjour,
Merci pour votre aide.
Cependant en rajoutant les deux lignes de code à mon script, je n'ai pas d'objet géographique créé. je n'ai pas non plus d'erreur.
J'ai juste rajouté les deux lignes que vous m'avez communiquées à la fin du script.
A votre avis pourquoi ça coince encore?
Hors ligne
#4 Wed 28 June 2017 16:20
- Sylvain PIERRE
- Participant assidu
- Lieu: Strasbourg
- Date d'inscription: 6 Sep 2005
- Messages: 170
Re: QGIS / Pyqgis: Algorithme De Dijkstra
La réponse est à rechercher ans la seconde partie de mon message, il vous faut manipuler de nouvelles classes de l'API PyQgis:
QgsVectorLayer entre autre ainsi que certaines de ses sous-classes, ainsi que QgsMapLayerRegistry
Code:
vl = QgsVectorLayer("MultiLineString?crs=epsg:3948", "temporary_line", "memory") pr = vl.dataProvider() pr.addFeatures([polyline]) if vl.isValid(): QgsMapLayerRegistry.instance().addMapLayer(vl)
Attention de spécifier le code epsg correspondant à votre projection courante
Le code est fourni sans garantie , mais dans l'esprit c'est ce qu'il faut faire
Hors ligne
#5 Thu 29 June 2017 10:23
- hotegbe
- Participant occasionnel
- Date d'inscription: 28 Jun 2017
- Messages: 32
Re: QGIS / Pyqgis: Algorithme De Dijkstra
Je vous remercie pour votre réponse. après quelques modifications j'obtiens un résultat qui m'a permis de bien avancer dans mon travail. Cependant,
J'ai une erreur python qui persiste "qgis dumpé" après exécution de mon code plusieurs fois.
J'ai désinstallé et changé la version de mon QGIS mais rien n'y fait; j'ai même changé d'ordinateur.
Comment régler ce souci svp?
Merci
Hors ligne
#6 Thu 29 June 2017 10:52
- Sylvain PIERRE
- Participant assidu
- Lieu: Strasbourg
- Date d'inscription: 6 Sep 2005
- Messages: 170
Re: QGIS / Pyqgis: Algorithme De Dijkstra
A mon avis c'est le recours à une layer de type memory
a chaque fois que vous lancer le script, la memory layer est créée
Il faudrait travailler sur une couche physique ans laquelle vous enregistrerez vos objets
1 créer un shape avec geometrie ligne
2 modifier le code
Code:
inLayer = 'le_nom_de_mon_shape' for layer in QgsMapLayerRegistry.instance().mapLayers().values(): if inLayer in layer.name(): vl = layer pr = vl.dataProvider() pr.addFeatures([polyline])
Hors ligne
#7 Thu 29 June 2017 13:57
- hotegbe
- Participant occasionnel
- Date d'inscription: 28 Jun 2017
- Messages: 32
Re: QGIS / Pyqgis: Algorithme De Dijkstra
J'ai pu avancer j'obtiens bien une couche dans laquelle une entité est créée.
Cependant le chemin le plus court recherché ne passe plus par tous les points intermédiaires entre le point de départ et d'arrivée.
Mon code est le suivant
geom = rb .asGeometry()
polyline = geom.asGeometryCollection()[0].asPolyline()
v_layer = QgsVectorLayer("LineString", "cable", "memory")
pr = v_layer.dataProvider()
seg = QgsFeature()
seg.setGeometry(QgsGeometry.fromPolyline([polyline]))
pr.addFeatures( [seg] )
v_layer.updateExtents()
QgsMapLayerRegistry.instance().addMapLayers([v_layer]).
Comment puis je imposer la géométrie de polyline à l'entité que je créee dans ma table??
Merci
Hors ligne
#8 Thu 29 June 2017 14:25
- Sylvain PIERRE
- Participant assidu
- Lieu: Strasbourg
- Date d'inscription: 6 Sep 2005
- Messages: 170
Re: QGIS / Pyqgis: Algorithme De Dijkstra
Peut-être remplacer
Code:
geom = rb .asGeometry() polyline = geom.asGeometryCollection()[0].asPolyline()
par
Code:
polyline = QgsGeometry( rb.asGeometry() )
En tous cas creuser autour de la construction de cet objet polyline
Hors ligne
#9 Thu 29 June 2017 14:47
- hotegbe
- Participant occasionnel
- Date d'inscription: 28 Jun 2017
- Messages: 32
Re: QGIS / Pyqgis: Algorithme De Dijkstra
Pour ça il n'y a aucun souci. c'est plutôt au niveau de la création du feature (entité) dans ma couche.
Mon souci est au niveau de la géométrie du feature que je vais insérer dans la couche que je crée. En renseignant directement tStart et tStop dans seg.setGeometry j'obtiens un tracé de ligne droite entre ces deux points et une insertion de ce tracé comme entité dans ma couche.
Du coup je n'arrive pas à imposer la géométrie de mon polyline à cette nouvelle que je crée comme ci bas.
seg = QgsFeature()
seg.setGeometry(QgsGeometry.fromPolyline([tStart ,tStop]))
Mon but est de garder la géométrie de polyline dans le seg.setGeometry.
Je ne sais pas si je suis plus clair.
Merci
voici le code plus détaillé
for pnt in p:
rb.addPoint(pnt)
polyline = QgsGeometry( rb.asGeometry() )
v_layer = QgsVectorLayer("LineString", "cable", "memory")
pr = v_layer.dataProvider()
seg = QgsFeature()
seg.setGeometry(QgsGeometry.fromPolyline([tStart ,tStop]))
pr.addFeatures( [seg] )
v_layer.updateExtents()
QgsMapLayerRegistry.instance().addMapLayers([v_layer])
Hors ligne
#10 Thu 29 June 2017 15:05
- Sylvain PIERRE
- Participant assidu
- Lieu: Strasbourg
- Date d'inscription: 6 Sep 2005
- Messages: 170
Re: QGIS / Pyqgis: Algorithme De Dijkstra
Vous ne mettez que le point de départ et celui d'arrivée
Il faudrait remplacer dans
Code:
seg.setGeometry(QgsGeometry.fromPolyline([tStart ,tStop]))
par
Code:
seg.setGeometry(QgsGeometry.fromPolyline([polyline ]))
Hors ligne
#11 Thu 29 June 2017 15:15
- hotegbe
- Participant occasionnel
- Date d'inscription: 28 Jun 2017
- Messages: 32
Re: QGIS / Pyqgis: Algorithme De Dijkstra
Voici l'erreur que je récupère en faisant seg.setGeometry(QgsGeometry.fromPolyline([polyline ]))
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "c:/users/shount~1/appdata/local/temp/tmplczshv.py", line 53, in <module>
seg.setGeometry(QgsGeometry.fromPolyline([polyline ]))
TypeError: QgsGeometry.fromPolyline(list-of-QgsPoint): argument 1 has unexpected type 'list'
Hors ligne
#12 Thu 29 June 2017 16:13
- Sylvain PIERRE
- Participant assidu
- Lieu: Strasbourg
- Date d'inscription: 6 Sep 2005
- Messages: 170
Re: QGIS / Pyqgis: Algorithme De Dijkstra
pourquoi ne pas avoir conservé le code suivant:
Code:
pr.addFeatures([polyline])
?
Hors ligne
#13 Thu 29 June 2017 16:18
- hotegbe
- Participant occasionnel
- Date d'inscription: 28 Jun 2017
- Messages: 32
Re: QGIS / Pyqgis: Algorithme De Dijkstra
je récupère toujours la meme erreur en essayant de passer polyline en paramètre comme ceci :
pr.addFeatures([polyline])
seg.setGeometry(QgsGeometry.fromPolyline([polyline]))
Hors ligne
#14 Thu 29 June 2017 16:30
- Sylvain PIERRE
- Participant assidu
- Lieu: Strasbourg
- Date d'inscription: 6 Sep 2005
- Messages: 170
Re: QGIS / Pyqgis: Algorithme De Dijkstra
Normalement pas besoin de la seconde ligne
Hors ligne
#15 Thu 29 June 2017 16:32
- hotegbe
- Participant occasionnel
- Date d'inscription: 28 Jun 2017
- Messages: 32
Re: QGIS / Pyqgis: Algorithme De Dijkstra
C'est pareil polyline n'est pas accepté en tant qu'argument ni par addfeatures() ni par setGeometry comme écrit plus haut.
même erreur
Hors ligne
#16 Thu 29 June 2017 16:45
- dominique.lys
- Participant assidu
- Date d'inscription: 5 Oct 2006
- Messages: 473
- Site web
Re: QGIS / Pyqgis: Algorithme De Dijkstra
Peut-être
Code:
poly = QgsPolyline(p) #avec p la liste de QgsPoint geom = QgsGeometry.fromPolyline(poly) feat = QgsFeature() feat.setGeometry(geom) pr.addFeature(seg)
Hors ligne
#17 Thu 29 June 2017 16:52
- Sylvain PIERRE
- Participant assidu
- Lieu: Strasbourg
- Date d'inscription: 6 Sep 2005
- Messages: 170
Re: QGIS / Pyqgis: Algorithme De Dijkstra
Il faut alors gérer en même temps un objet rubberband et un objet liste de points qgis
Code:
else: p = [] coordinatePairs = [] curPos = idStop while curPos != idStart: pnt = graph.vertex(graph.arc(tree[curPos]).inVertex()).point() print pnt p.append(pnt) coordinatePairs.append(QgsPoint(pnt)) curPos = graph.arc(tree[curPos]).outVertex() .... seg.setGeometry(QgsGeometry.fromPolyline([coordinatePairs]))
par contre il faudrait voir ce que donne le print pnt pour être certain qu'il renvoie bien un couple X,Y
Dernière modification par Sylvain PIERRE (Thu 29 June 2017 16:56)
Hors ligne
#18 Thu 29 June 2017 17:05
- hotegbe
- Participant occasionnel
- Date d'inscription: 28 Jun 2017
- Messages: 32
Re: QGIS / Pyqgis: Algorithme De Dijkstra
la liste de QgsPoint est constituée des coordonnées des points de départ et d'arrivé du tracé.
avec cela je récupère l'erreur suivante :
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "c:/users/shount~1/appdata/local/temp/tmp9zubp9.py", line 59, in <module>
poly = QgsPolyline(p)
NameError: name 'QgsPolyline' is not defined
Hors ligne
#19 Thu 29 June 2017 17:20
- Sylvain PIERRE
- Participant assidu
- Lieu: Strasbourg
- Date d'inscription: 6 Sep 2005
- Messages: 170
Re: QGIS / Pyqgis: Algorithme De Dijkstra
Heu là il faudrait calmement repartir de l'ensemble du code...
Hors ligne
#20 Thu 29 June 2017 17:21
- hotegbe
- Participant occasionnel
- Date d'inscription: 28 Jun 2017
- Messages: 32
Re: QGIS / Pyqgis: Algorithme De Dijkstra
seg.setGeometry(QgsGeometry.fromPolyline([coordinatePairs]))
TypeError: QgsGeometry.fromPolyline(list-of-QgsPoint): argument 1 has unexpected type 'list'
l'array coordinatepairs n'est pas accepté comme argument non plus.
le print pnt renvoie bien un couple de (X,Y ) en boucle
Hors ligne
#21 Thu 29 June 2017 21:27
- JD
- Moderateur
- Date d'inscription: 8 Aug 2013
- Messages: 726
Re: QGIS / Pyqgis: Algorithme De Dijkstra
Bonsoir,
vous pouvez passer par la construction de la polyligne
ou alors vous supprimez les ligne entre --- et vous décommentez les lignes en commentaires.
Code:
# rb = QgsRubberBand(qgis.utils.iface.mapCanvas()) # rb.setColor(Qt.red) #----- geom = QgsGeometry.fromPolyline(p) #----- # for pnt in p: # rb.addPoint(pnt) v_layer = QgsVectorLayer("LineString", "cable", "memory") QgsMapLayerRegistry.instance().addMapLayers([v_layer]) pr = v_layer.dataProvider() v_layer.startEditing() seg = QgsFeature() #geom = rb.asGeometry() seg.setGeometry(geom) pr.addFeatures( [seg] ) v_layer.commitChanges()
Cordialement,
Dernière modification par lejedi76 (Thu 29 June 2017 21:34)
Hors ligne
#22 Fri 30 June 2017 08:29
- hotegbe
- Participant occasionnel
- Date d'inscription: 28 Jun 2017
- Messages: 32
Re: QGIS / Pyqgis: Algorithme De Dijkstra
Bonjour lejedi76, votre solution marche bien et je vous en remercie.
Maintenant je voudrais savoir comment automatiser les points de départ et d'arrivée de mon tracé afin d'éviter de fixer
pStart = QgsPoint(4.818554,45.832345)
pStop = QgsPoint(4.828114,45.8332884)
Mais juste en prenant pour paramètre les coordonnées d'un x et d'un y par simple clic dans le canevas.
Merci
Hors ligne
#23 Fri 30 June 2017 09:25
- Sylvain PIERRE
- Participant assidu
- Lieu: Strasbourg
- Date d'inscription: 6 Sep 2005
- Messages: 170
Re: QGIS / Pyqgis: Algorithme De Dijkstra
Script + interaction avec l'interface = plugin
Je crois que vous allez devoir plonger un peu plus profondément dans le développement avec l'API PyQgis.
Cela ouvre des possibilités vraiment intéressantes
Sylvain
Hors ligne
#24 Fri 30 June 2017 09:42
- hotegbe
- Participant occasionnel
- Date d'inscription: 28 Jun 2017
- Messages: 32
Re: QGIS / Pyqgis: Algorithme De Dijkstra
Merci à vous. je commence à creuser
Hors ligne
#25 Fri 30 June 2017 10:28
- hotegbe
- Participant occasionnel
- Date d'inscription: 28 Jun 2017
- Messages: 32
Re: QGIS / Pyqgis: Algorithme De Dijkstra
par rapport au résultat, j'obtiens à chaque fois la création d'un nouveau layer avec une nouvelle entité que je crée ce qui n'est pas mon objectif.
Il s'agit plutôt de mettre toutes les entités créées dans le même layer avec les champs qui sont déjà prédéfinis plitôt que de recréer à chaque fois un nouveau layer.
Je mets ci joint le code
Code:
from PyQt4.QtCore import * from PyQt4.QtGui import * from qgis.core import * from qgis.gui import * from qgis.networkanalysis import * vl = qgis.utils.iface.mapCanvas().currentLayer() director = QgsLineVectorLayerDirector(vl, -1, '', '', '', 3) properter = QgsDistanceArcProperter() director.addProperter(properter) crs = qgis.utils.iface.mapCanvas().mapRenderer().destinationCrs() builder = QgsGraphBuilder(crs) pStart = QgsPoint(4.83382,45.83818) pStop = QgsPoint(4.841678,45.834846) tiedPoints = director.makeGraph(builder, [pStart, pStop]) graph = builder.graph() tStart = tiedPoints[0] tStop = tiedPoints[1] idStart = graph.findVertex(tStart) idStop = graph.findVertex(tStop) (tree, cost) = QgsGraphAnalyzer.dijkstra(graph, idStart, 0) if tree[idStop] == -1: print "Path not found" else: p = [] curPos = idStop while curPos != idStart: pnt = graph.vertex(graph.arc(tree[curPos]).inVertex()).point() p.append(pnt) curPos = graph.arc(tree[curPos]).outVertex() p.append(tStart) rb = QgsRubberBand(qgis.utils.iface.mapCanvas()) rb.setColor(Qt.red) geom = QgsGeometry.fromPolyline(p) for pnt in p: rb.addPoint(pnt) v_layer = QgsVectorLayer("LineString", "cable", "memory") QgsMapLayerRegistry.instance().addMapLayers([v_layer]) pr = v_layer.dataProvider() v_layer.startEditing() v_layer.addAttribute(QgsField("id", QVariant.String)) v_layer.addAttribute(QgsField("longueur", QVariant.String)) v_layer.addAttribute(QgsField("type", QVariant.String)) v_layer.addAttribute(QgsField("diametre", QVariant.String)) seg = QgsFeature() geom = rb.asGeometry() seg.setGeometry(geom) pr.addFeatures( [seg] ) v_layer.commitChanges()
Hors ligne