def processAlgorithm(self, progress):
        progress.setPercentage(0)
        # Retrieve the values of the parameters entered by the user
        roadsLayer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.ROADS_LAYER))
        gridLayer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.GRID_LAYER))
        vertIdField = self.getParameterValue(self.VERT_ID_FIELD)
        stress = self.getParameterValue(self.STRESS)

        # build the output layer
        outFields = QgsFields()
        outFields.append(QgsField('grid_id', QVariant.Int))
        outFields.append(QgsField('status',QVariant.String))
        outFields.append(QgsField('free_cost', QVariant.Int))
        outFields.append(QgsField('cnst_cost', QVariant.Int))
        outFields.append(QgsField('cost_ratio', QVariant.Double))
        writer = self.getOutputFromName(self.OUTPUT_LAYER).getVectorWriter(
            outFields, QGis.WKBPolygon, roadsLayer.crs())
        progress.setPercentage(2)

        # establish db connection
        progress.setInfo('Getting DB connection')
        self.setDbFromRoadsLayer(roadsLayer)
        self.setLayersFromDb()

        # get network
        progress.setInfo('Building network')
        nu = NXUtils(self.vertsLayer,self.linksLayer)
        nu.buildNetwork()
        DG = nu.getNetwork()
        SG = nu.getStressNetwork(stress)
        progress.setPercentage(10)
        graphCosts = nx.get_edge_attributes(DG,'weight')

        #get grid feature and vert id
        progress.setText('Reading selected feature(s)')
        selectedGridFeatures = processing.features(gridLayer)
        if not len(selectedGridFeatures) == 1:
            raise GeoAlgorithmExecutionException('You must select one and only one feature in the grid layer')
        gridFeature = QgsFeature()
        for i, f in enumerate(selectedGridFeatures):
            gridFeature = f
        sourceVertId = gridFeature.attribute(vertIdField)

        #test for source feature not having any low stress connections
        if not SG.has_node(sourceVertId):
            raise GeoAlgorithmExecutionException('The selected grid cell has no low stress connections')

        #iterate grid features and compile scores
        progress.setText('Generating grid scores')
        #helper function to sum costs from graph
        def sumCosts(nodes,graphWeights):
            cost = 0
            del nodes[1]    #remove the source and target nodes from consideration
            del nodes[-1]
            for j, node in enumerate(nodes):
                    try:
                        cost = cost + graphCosts[(node,nodes[j+1])]
                    except:
                        pass
            return cost
        #gridProvider = grid.dataProvider()
        gridFeatures = gridLayer.getFeatures()
        for i, gf in enumerate(gridFeatures):
            targetVertId = gf.attribute(vertIdField)
            progress.setInfo('from: ' + str(sourceVertId) + ' to: ' + str(targetVertId))

            #write new feature
            progress.setText('Writing grid feature')
            newFeat = QgsFeature()
            newGeom = QgsGeometry(gf.geometry())
            newFeat.setGeometry(newGeom)
            newFeat.initAttributes(5)
            newFeat.setAttribute(0,gf.attribute(vertIdField))
            if targetVertId == sourceVertId:
                newFeat.setAttribute(1,'Source cell')
            elif not SG.has_node(targetVertId):
                newFeat.setAttribute(1,'Unreachable')
            elif not nx.has_path(SG,source=sourceVertId,target=targetVertId):
                newFeat.setAttribute(1,'Unreachable')
            else:
                #get shortest path without stress
                pathNoStress = nx.shortest_path(DG,source=sourceVertId,target=targetVertId,weight='weight')
                #get shortest path with stress
                pathStress = nx.shortest_path(SG,source=sourceVertId,target=targetVertId,weight='weight')
                #get cost values
                costNoStress = sumCosts(pathNoStress,graphCosts)
                costStress = sumCosts(pathStress,graphCosts)

                #add attributes
                newFeat.setAttribute(1,'Target cell')
                newFeat.setAttribute(2,costNoStress)
                newFeat.setAttribute(3,costStress)
                if costNoStress == 0:
                    pass
                else:
                    newFeat.setAttribute(4,float(costStress)/float(costNoStress))

            writer.addFeature(newFeat)

        del writer
Esempio n. 2
0
    def processAlgorithm(self, progress):
        progress.setPercentage(0)
        # Retrieve the values of the parameters entered by the user
        inLayer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.ROADS_LAYER))
        originsLayer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.ORIGINS_LAYER))
        oVertIdField = self.getParameterValue(self.ORIGIN_VERT_ID_FIELD)
        gridLayer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.GRID_LAYER))
        gVertIdField = self.getParameterValue(self.GRID_VERT_ID_FIELD)
        stress = self.getParameterValue(self.STRESS)
        budget = self.getParameterValue(self.BUDGET)

        # build the output layer
        gridFields = QgsFields()
        gridFields.append(QgsField('id', QVariant.Int))
        gridFields.append(QgsField('origin_id', QVariant.Int))
        gridFields.append(QgsField('grid_id', QVariant.Int))
        gridFields.append(QgsField('car_cost', QVariant.Int))
        gridFields.append(QgsField('bike_cost', QVariant.Int))
        gridFields.append(QgsField('conn_idx', QVariant.Double))
        gridWriter = self.getOutputFromName(self.OUT_LAYER).getVectorWriter(
            gridFields, QGis.WKBPolygon, inLayer.crs())

        progress.setPercentage(2)

        # establish db connection
        progress.setInfo('Getting DB connection')
        self.setDbFromRoadsLayer(inLayer)
        self.setLayersFromDb()
        if self.vertsLayer is None or self.linksLayer is None:
            raise GeoAlgorithmExecutionException('Could not find related \
                network tables. Have you built the network tables on \
                layer %s?' % inLayer.name())
        progress.setPercentage(3)

        # get network
        progress.setInfo('Building network')
        nu = NXUtils(self.vertsLayer,self.linksLayer)
        nu.buildNetwork()
        DG = nu.getNetwork()
        # if not stress:
        #     stress = 99
        SG = nu.getStressNetwork(stress)
        progress.setPercentage(10)

        # loop through the grid features and get distances to origins for each
        count = 0
        totalCount = len(vector.features(originsLayer))
        idStep = 0
        for originFeat in vector.features(originsLayer):
            originVertId = originFeat.attribute(oVertIdField)

            # skip if node is not accessible by low stress
            if not originVertId in SG:
                continue

            # get shortest path
            pathsBase = nx.single_source_dijkstra_path_length(
                DG,
                source=originVertId,
                cutoff=budget,
                weight='weight'
            )

            # get shortest low stress path
            pathsLowStress = nx.single_source_dijkstra_path_length(
                SG,
                source=originVertId,
                cutoff=budget,
                weight='weight'
            )

            # loop through grid and establish features
            for gridFeat in vector.features(gridLayer):
                gridVertId = gridFeat.attribute(gVertIdField)
                if gridVertId in pathsLowStress:
                    if gridVertId in pathsBase:
                        carCost = pathsBase[gridVertId]
                    else:
                        carCost = None
                    bikeCost = pathsLowStress[gridVertId]
                    connIdx = float()
                    if carCost is None:
                        connIdx = 1
                    elif carCost == 0:
                        connIdx = 1
                    else:
                        connIdx = float(bikeCost)/float(carCost)
                    outFeat = QgsFeature(gridFields)
                    outFeat.setAttribute(0,idStep) #feature id
                    outFeat.setAttribute(1,originFeat.id()) #origin_id
                    outFeat.setAttribute(2,gridFeat.id()) #grid_id
                    outFeat.setAttribute(3,carCost) #car_cost
                    outFeat.setAttribute(4,bikeCost) #bike_cost
                    outFeat.setAttribute(5,connIdx) #conn_idx
                    outGeom = QgsGeometry(gridFeat.geometry())
                    outFeat.setGeometry(outGeom)
                    idStep += 1
                    gridWriter.addFeature(outFeat)

            count += 1
            progress.setPercentage(10+int(90*float(count)/totalCount))

        del gridWriter
    def processAlgorithm(self, progress):
        progress.setPercentage(0)
        # Retrieve the values of the parameters entered by the user
        roadsLayer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.ROADS_LAYER))
        destsLayer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.DESTINATIONS_LAYER))
        stress = self.getParameterValue(self.STRESS)
        maxCost = self.getParameterValue(self.MAX_COST)
        keepRaw = self.getParameterValue(self.KEEP_RAW)
        keepRoutes = self.getParameterValue(self.KEEP_ROUTES)
        keepSums = self.getParameterValue(self.KEEP_SUMS)

        # build the raw output layer
        if keepRaw:
            rawFields = QgsFields()
            rawFields.append(QgsField('path_id', QVariant.Int))
            rawFields.append(QgsField('sequence', QVariant.Int))
            rawFields.append(QgsField('from_road_id', QVariant.Int))
            rawFields.append(QgsField('to_road_id', QVariant.Int))
            rawFields.append(QgsField('int_id', QVariant.Int))
            rawFields.append(QgsField('int_cost', QVariant.Int))
            rawFields.append(QgsField('road_id', QVariant.Int))
            rawFields.append(QgsField('road_cost', QVariant.Int))
            rawFields.append(QgsField('cmtve_cost', QVariant.Int))
            rawWriter = self.getOutputFromName(self.RAW_LAYER).getVectorWriter(
                rawFields, QGis.WKBLineString, roadsLayer.crs())
        if keepRoutes:
            routeFields = QgsFields()
            routeFields.append(QgsField('path_id', QVariant.Int))
            routeFields.append(QgsField('from_road_id', QVariant.Int))
            routeFields.append(QgsField('to_road_id', QVariant.Int))
            routeFields.append(QgsField('cmtve_cost', QVariant.Int))
            routeWriter = self.getOutputFromName(self.ROUTES_LAYER).getVectorWriter(
                routeFields, QGis.WKBLineString, roadsLayer.crs())

        sumFields = QgsFields()
        sumFields.append(QgsField('road_id', QVariant.Int))
        sumFields.append(QgsField('use_count', QVariant.Int))
        if keepSums:
            sumWriter = self.getOutputFromName(self.SUMS_LAYER).getVectorWriter(
                sumFields, QGis.WKBLineString, roadsLayer.crs())
        progress.setPercentage(2)

        # establish db connection
        progress.setInfo('Getting DB connection')
        self.setDbFromRoadsLayer(roadsLayer)
        self.setLayersFromDb()

        # get network
        progress.setInfo('Building network')
        nu = NXUtils(self.vertsLayer,self.linksLayer)
        nu.buildNetwork()
        if not stress:
            DG = nu.getNetwork()
        else:
            DG = nu.getStressNetwork(stress)
        progress.setPercentage(10)

        '''# Build spatial index of road features
        progress.setInfo('Indexing road features')
        index = vector.spatialindex(roadsLayer)

        # Get nearest Road ID for input layer
        progress.setInfo('Getting road IDs')
        destinations = {}
        for feat in vector.features(destsLayer):
            roadMatch = QgsFeatureId()
            destGeom = QgsGeometry(feat.geometry())
            roadMatch = index.nearestNeighbor(destGeom.asPoint(),1)[0]
            roadFeat = roadsLayer.getFeatures(QgsFeatureRequest().setFilterFid(roadMatch))[0]
            roadGeom = QgsGeometry(roadFeat.geometry())
            destinations[feat.id()] = {
                'roadId': roadMatch,
                'distance': 0
            }'''
        # Assume nearest Road ID and distance fields exist as road_id and road_dist

        roadIds = list()
        for val in vector.values(destsLayer,'road_id')['road_id']:
            if val.is_integer():
                roadIds.append(int(val))
            else:
                raise GeoAlgorithmExecutionException(
                    self.tr('Bad road_id values. Input field was %s. Check that \
                        these are integer values.' % 'road_id'))

        # count pairs
        roadPairCount = len(roadIds) ** 2 - len(roadIds)
        progress.setInfo('%i total destination pairs identified' % roadPairCount)

        # loop through each destination and get shortest routes to all others
        try:
            rowCount = 0
            pairCount = 0
            for fromRoad in roadIds:
                for toRoad in roadIds:
                    if not fromRoad == toRoad:
                        # set counts
                        pairCount += 1
                        seq = 0
                        cost = 0
                        if pairCount % 1000 == 0:
                            progress.setInfo('Shortest path for pair %i of %i'
                                    % (pairCount, RoadPairCount))

                        # set feature for route output
                        routeFeat = None
                        if keepRoutes:
                            routeFeat = QgsFeature(routeFields)
                            routeFeat.setAttribute(0,pairCount) #path_id
                            routeFeat.setAttribute(1,fromRoad) #from_road_id
                            routeFeat.setAttribute(2,toRoad) #to_road_id












                        # check the path and iterate through it
                        if nx.has_path(DG,source=fromRoad,target=toRoad):
                            shortestPath = nx.shortest_path(
                                DG,
                                source=fromRoad,
                                target=toRoad,
                                weight='weight'
                            )
                            for i, v1 in enumerate(shortestPath, start=1):
                                if i == len(shortestPath):
                                    continue    #Leave out because this is the last Roadex

                                rowCount += 1
                                v2 = shortestPath[i]
                                seq += 1
                                roads[roadId]['count'] += 1

                                # set costs
                                linkCost = DG.edge[v1][v2]['weight']
                                intCost = 0
                                cost += linkCost
                                cost += intCost

                                # create the new features
                                if roadId in roads and roads.get(roadId).get('geom'):
                                    geom = roads.get(roadId).get('geom')
                                    if keepRaw:
                                        rawFeat = QgsFeature(rawFields)
                                        rawFeat.setAttribute(0,pairCount) #path_id
                                        rawFeat.setAttribute(1,seq) #sequence
                                        rawFeat.setAttribute(2,fromRoad) #from_road_id
                                        rawFeat.setAttribute(3,toRoad) #to_road_id
                                        rawFeat.setAttribute(4,DG.node[v2]['int_id']) #int_id
                                        rawFeat.setAttribute(5,intCost) #int_cost
                                        rawFeat.setAttribute(6,roadId) #road_id
                                        rawFeat.setAttribute(7,linkCost) #road_cost
                                        rawFeat.setAttribute(8,cost) #cmtve_cost
                                        rawFeat.setGeometry(geom)
                                        rawWriter.addFeature(rawFeat)
                                        del rawFeat
                                    if keepRoutes:
                                        routeFeat.setAttribute(3,cost) #cmtve_cost
                                        if not routeFeat.constGeometry():
                                            routeFeat.setGeometry(geom)
                                        else:
                                            routeFeat.setGeometry(
                                                geom.combine(routeFeat.constGeometry())
                                            )
                                        routeWriter.addFeature(routeFeat)
                                    if keepSums:
                                        sumFeat = roads.get(roadId).get('feat')
                                        useCount = roads.get(roadId).get('count')
                                        sumFeat.setAttribute(1,useCount) #use_count

                        del routeFeat
                        progress.setPercentage(10 + 90*pairCount/RoadPairCount)

            for roadId, r in roads.iteritems():
                if r.get('count') > 0:
                    if keepSums:
                        sumWriter.addFeature(r.get('feat'))

        except Exception, e:
            raise GeoAlgorithmExecutionException('Uncaught error: %s' % e)