Анализ сетей

Вопросы по свободной ГИС QGIS. Сообщения об ошибках, предложения по улучшению, локализация.
Ответить
Аватара пользователя
Евгений Брусникин
Новоприбывший
Сообщения: 14
Зарегистрирован: 31 май 2014, 14:21
Репутация: 0

Анализ сетей

Сообщение Евгений Брусникин » 04 ноя 2015, 18:48

Добрый день, уважаемое сообщество. Столкнулся с проблемой реализации (в виде расширения) алгоритма сетевого анализа из библиотеки QGIS network-analysis.
В статье http://gis-lab.info/qa/qgis-network-analysis-lib.html, дан алгоритм такого анализа. Ввиду моего плохого знания питона, прошу помощи с решением проблемы, как это реализовать в виде работающего скрипта. Думаю, многим будет полезно.

Алгоритм должен находить оптимальный маршрут от одной из вершин графа до всех остальных. Выбор начальной вершины, задается щелчком мыши. Выдаваемый результат должен отображаться в виде отдельного слоя.

Код: Выделить всё

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)
Последний раз редактировалось Евгений Брусникин 04 ноя 2015, 20:37, всего редактировалось 1 раз.

Аватара пользователя
Евгений Брусникин
Новоприбывший
Сообщения: 14
Зарегистрирован: 31 май 2014, 14:21
Репутация: 0

Re: Анализ сетей

Сообщение Евгений Брусникин » 04 ноя 2015, 19:04

есть еще некий код, ShortestPath, но он, к сожалению не работает на qgis>1.8

Код: Выделить всё

from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
from qgis.gui import *
import qgis.utils
from qgis.networkanalysis import *
from packageUI import PackageUI


#initialize Qt resources from file resouces.py
import resources

class networking:
    def __init__(self, iface):
        
        self.iface=iface
        self.canvas=self.iface.mapCanvas()
        self.pin=QgsMapToolEmitPoint(self.canvas)
        self.haveDotLayer=False
        self.userPoints=[]
        self.havePLayer=False
    def initGui(self):
        #create action that will start plugin configuration
        self.action=QAction(QIcon(":/plugins/ShortestPath/pin.png"), "Find Shortest Path", self.iface.mainWindow())
        self.action.setWhatsThis("Configuration for test plugin")
        self.action.setStatusTip("Find the Shortest Path")
        QObject.connect(self.action, SIGNAL("triggered()"),self.run)

        #add toolbar button and menu item
        self.iface.addToolBarIcon(self.action)
        self.iface.addPluginToMenu("&Find Shortest Path", self.action)

        #connect to signal renderComplete which is emitted when canvas rendering is done
        QObject.connect(self.pin, SIGNAL("canvasClicked(const QgsPoint &, Qt::MouseButton)"), self.placePin)
            
    def unload(self):
         #remove the plugin menu item and icon
         self.iface.removePluginMenu("&Add Two Points", self.action)
         self.iface.removeToolBarIcon(self.action)

         #disconnect from signal of the canvas
         QObject.disconnect(self.pin,SIGNAL("canvasClicked(const QgsPoint &, Qt::MouseButton)"),self.placePin)

    def run(self):        
        #create and show a configuration dialog or something similar
        print "NAPlug: run called"
        self.myVLayer=self.iface.activeLayer()
        if self.myVLayer is None:
            reply=QMessageBox.warning(self.iface.mainWindow(),
                                      "Error",
                                      "Please load a vector line Layer")
        else:
             #Call the UI Dialog
            self.myCrs=self.myVLayer.crs()
            self.dialog=PackageUI()
            
        #Show the dialog for the information
            self.dialog.show()
            QObject.connect(self.dialog.ui.btnRouting,
                            SIGNAL("clicked()"), 
                            self.act)
          
        #Change the mouse cursor to pinTool so that user can place points on map
            self.canvas.setMapTool(self.pin)

    def createPLayer(self):
        self.pLayer=QgsVectorLayer("Point","Pins","memory")
        
        self.provider=self.pLayer.dataProvider()
        self.provider.addAttributes([
                QgsField("id",QVariant.Int),
                QgsField("x",QVariant.Double),
                QgsField("y",QVariant.Double)
                ])
        self.pLayer.updateFieldMap()
        QgsMapLayerRegistry.instance().addMapLayer(self.pLayer)
        result=QObject.connect(self.pLayer, SIGNAL("layerDeleted()"),self.DeletePLayer)
        self.havePLayer=True
    def DeletePLayer(self):
        self.havePLayer=False
    
#Place Pins on the map
    def placePin(self, point):
        x=point.x()
        y=point.y()
        self.userPoints.append([x,y])
        if self.havePLayer==False:
            self.createPLayer()
        fc=int(self.provider.featureCount())
        feature=QgsFeature()
        feature.setGeometry(QgsGeometry.fromPoint(point))
        feature.setAttributeMap( {
                0 : QVariant(fc),
                1 : QVariant(x),
                2 : QVariant(y)})
        self.provider.addFeatures([feature])
        self.pLayer.updateExtents()
        self.pLayer.setCacheImage(None)
        self.canvas.refresh()
                                  
        
    def act(self):
        print "act is running"
        print self.userPoints
        self.pointsCount=len(self.userPoints)
        print str(self.pointsCount)
        for i in range (self.pointsCount-1):
            self.pathGraphBuild(self.userPoints[i],self.userPoints[i+1],(i+1))
       
    def pathGraphBuild(self,startPoint,endPoint,pid):
        
        self.director=QgsLineVectorLayerDirector(self.myVLayer,-1,'','','',3)
        self.properter=QgsDistanceArcProperter()
        self.director.addProperter(self.properter)
        
        self.builder=QgsGraphBuilder(self.myCrs)
        
        #Get the Start and End Points for each two pair of points
        sx=startPoint[0]
        sy=startPoint[1]
        ex=endPoint[0]
        ey=endPoint[1]
        sp=QgsPoint(sx,sy)
        ep=QgsPoint(ex,ey)


        tiedPoints=self.director.makeGraph(self.builder,[sp,ep])
        self.graph=self.builder.graph()
        
        tStart=tiedPoints[0]
        tEnd=tiedPoints[1]
        
        idStart=self.graph.findVertex(tStart)
        idEnd=self.graph.findVertex(tEnd)
        
        (tree, cost)=QgsGraphAnalyzer.dijkstra(self.graph, idStart, 0)
        
        if tree[idEnd]==-1:
            print "Path not found"
        else:
            p=[]
            curPos=idEnd
            while curPos != idStart:
                p.append(self.graph.vertex(self.graph.arc(tree[curPos]).inVertex()).point())
                curPos=self.graph.arc(tree[curPos]).outVertex();
            p.append(tStart)
            rb=QgsRubberBand(self.iface.mapCanvas())
            rb.setColor(Qt.red)
            for pnt in p:
                rb.addPoint(pnt)

Аватара пользователя
Евгений Брусникин
Новоприбывший
Сообщения: 14
Зарегистрирован: 31 май 2014, 14:21
Репутация: 0

Re: Анализ сетей

Сообщение Евгений Брусникин » 04 ноя 2015, 20:36

Вроде все получилось. Вечером залью архив. У кого будет время - потестируйте, пожалуйста.
Может кому пригодится 8)

Аватара пользователя
Евгений Брусникин
Новоприбывший
Сообщения: 14
Зарегистрирован: 31 май 2014, 14:21
Репутация: 0

Re: Анализ сетей

Сообщение Евгений Брусникин » 09 ноя 2015, 20:03

Есть кто может помочь, с созданием векторного слоя из построенного графа? как реализовать?

Аватара пользователя
Дмитрий Барышников
Гуру
Сообщения: 2572
Зарегистрирован: 17 ноя 2009, 19:17
Репутация: 261
Откуда: Москва

Re: Анализ сетей

Сообщение Дмитрий Барышников » 09 ноя 2015, 21:43

А у вас есть собственно геометрии (вектора)?
Ведь граф - это узлы и ребра - некие идентификаторы и не более. А вот к чему они относятся - зависит от вас.

Аватара пользователя
Евгений Брусникин
Новоприбывший
Сообщения: 14
Зарегистрирован: 31 май 2014, 14:21
Репутация: 0

Re: Анализ сетей

Сообщение Евгений Брусникин » 09 ноя 2015, 21:51

Дмитрий Барышников писал(а):А у вас есть собственно геометрии (вектора)?

Код: Выделить всё

def pathGraphBuild(self,startPoint,endPoint):
		self.director=QgsLineVectorLayerDirector(self.myVLayer,5,"2","0","1",1)
		self.properter=QgsDistanceArcProperter()
		self.director.addProperter(self.properter)
		
		self.builder=QgsGraphBuilder(self.myCrs)
		
		sx=startPoint[0]
		sy=startPoint[1]
		sp=QgsPoint(sx,sy)
		pStart = self.userPoints[0]
		tiedPoint = self.director.makeGraph(self.builder,[sp])
		pStart = tiedPoint[0]

		self.graph = self.builder.graph()

		idStart = self.graph.findVertex( pStart )

		( tree, costs ) = QgsGraphAnalyzer.dijkstra( self.graph, idStart, 0 )

		for edgeId in tree:
			if edgeId == -1:
				continue
			rb = QgsRubberBand( qgis.utils.iface.mapCanvas() )
			rb.setColor ( Qt.red )
			rb.setWidth (4)
			rb.addPoint ( self.graph.vertex( self.graph.arc( edgeId ).inVertex() ).point() )
			rb.addPoint ( self.graph.vertex( self.graph.arc( edgeId ).outVertex() ).point() )
Это код класса, отвечающий за построение графа.
У него есть идентификаторы начального узла и идентификаторы сегментов: idStart и edgeID. Также имеются point и line слои. По линейному слою строится граф, а точечный слой, это его узлы

Аватара пользователя
Дмитрий Барышников
Гуру
Сообщения: 2572
Зарегистрирован: 17 ноя 2009, 19:17
Репутация: 261
Откуда: Москва

Re: Анализ сетей

Сообщение Дмитрий Барышников » 10 ноя 2015, 21:33

На сколько я понимаю в QGIS один тип геометрии - один слой. Так что вы можете выбранные линии и точки в 2 слоя записать. Можно попробовать записать в Geometry Collection - типа sqlite - но потом в чем с этим работать?

5Nap
Участник
Сообщения: 85
Зарегистрирован: 21 ноя 2010, 17:36
Репутация: 31

Re: Анализ сетей

Сообщение 5Nap » 13 ноя 2015, 17:43

посмотрите pgRouting. Он ровно для анализа сетей и сделан. вот здесь: http://anitagraser.com/2013/07/07/publi ... pgrouting/ есть начальное описание работы. Как-то тестил - маршрут строит, выборку точек по расстоянию делает.

Аватара пользователя
Дмитрий Барышников
Гуру
Сообщения: 2572
Зарегистрирован: 17 ноя 2009, 19:17
Репутация: 261
Откуда: Москва

Re: Анализ сетей

Сообщение Дмитрий Барышников » 13 ноя 2015, 19:28

QGIS никак не связан с pgRouting. Это можно и OSRM, grapghhopper, gdal GNM смотреть. Да и ArcGIS geography model до кучи.

Ответить

Вернуться в «QGIS»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 14 гостей