Example #1
0
    def graph_builder(self, network, cost_field, origins, tolerance, crs,
                      epsg):

        # Settings
        otf = False

        # Get index of cost field
        network_fields = network.fields()
        network_cost_index = network_fields.indexFromName(cost_field)

        # Setting up graph build director
        director = QgsVectorLayerDirector(network, -1, '', '', '',
                                          QgsVectorLayerDirector.DirectionBoth)

        # Determining cost calculation
        if cost_field != 'length':
            strategy = ct.CustomCost(network_cost_index, 0.01)
        else:
            strategy = QgsNetworkDistanceStrategy()

        # Creating graph builder
        director.addStrategy(strategy)
        builder = QgsGraphBuilder(crs, otf, tolerance, epsg)

        # Reading origins and making list of coordinates
        graph_origin_points = []

        # Loop through the origin points and add graph vertex indices
        for index, origin in enumerate(origins):
            graph_origin_points.append(origins[index]['geom'].asPoint())

        # Get origin graph vertex index
        tied_origin_vertices = director.makeGraph(builder, graph_origin_points)

        # Build the graph
        graph = builder.graph()

        # Create dictionary of origin names and tied origins
        tied_origins = {}

        # Combine origin names and tied point vertices
        for index, tied_origin in enumerate(tied_origin_vertices):
            tied_origins[index] = {
                'name': origins[index]['name'],
                'vertex': tied_origin
            }

        self.spIndex = QgsSpatialIndex()
        self.indices = {}
        self.attributes_dict = {}
        self.centroids = {}
        i = 0
        for f in network.getFeatures():
            if f.geometry().type() == QgsWkbTypes.LineGeometry:
                if not f.geometry().isMultipart():
                    self.attributes_dict[f.id()] = f.attributes()
                    polyline = f.geometry().asPolyline()
                    for idx, p in enumerate(polyline[1:]):
                        ml = QgsGeometry.fromPolylineXY([polyline[idx], p])
                        new_f = QgsFeature()
                        new_f.setGeometry(ml.centroid())
                        new_f.setAttributes([f.id()])
                        new_f.setId(i)
                        self.spIndex.addFeature(new_f)
                        self.centroids[i] = f.id()
                        i += 1
                else:
                    self.attributes_dict[f.id()] = f.attributes()
                    for pl in f.geometry().asMultiPolyline():
                        for idx, p in enumerate(pl[1:]):
                            ml = QgsGeometry.fromPolylineXY([pl[idx], p])
                            new_f = QgsFeature()
                            new_f.setGeometry(ml.centroid())
                            new_f.setAttributes([f.id()])
                            new_f.setId(i)
                            self.spIndex.addFeature(new_f)
                            self.centroids[i] = f.id()
                            i += 1

        self.network_fields = network_fields
        return graph, tied_origins
    def processAlgorithm(self, parameters, context, feedback):
        layer = QgsProcessingUtils.mapLayerFromString(
            self.getParameterValue(self.INPUT_VECTOR), context)
        startPoint = self.getParameterValue(self.START_POINT)
        endPoint = self.getParameterValue(self.END_POINT)
        strategy = self.getParameterValue(self.STRATEGY)

        directionFieldName = self.getParameterValue(self.DIRECTION_FIELD)
        forwardValue = self.getParameterValue(self.VALUE_FORWARD)
        backwardValue = self.getParameterValue(self.VALUE_BACKWARD)
        bothValue = self.getParameterValue(self.VALUE_BOTH)
        defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION)
        bothValue = self.getParameterValue(self.VALUE_BOTH)
        defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION)
        speedFieldName = self.getParameterValue(self.SPEED_FIELD)
        defaultSpeed = self.getParameterValue(self.DEFAULT_SPEED)
        tolerance = self.getParameterValue(self.TOLERANCE)

        fields = QgsFields()
        fields.append(QgsField('start', QVariant.String, '', 254, 0))
        fields.append(QgsField('end', QVariant.String, '', 254, 0))
        fields.append(QgsField('cost', QVariant.Double, '', 20, 7))

        writer = self.getOutputFromName(self.OUTPUT_LAYER).getVectorWriter(
            fields, QgsWkbTypes.LineString, layer.crs(), context)

        tmp = startPoint.split(',')
        startPoint = QgsPointXY(float(tmp[0]), float(tmp[1]))
        tmp = endPoint.split(',')
        endPoint = QgsPointXY(float(tmp[0]), float(tmp[1]))

        directionField = -1
        if directionFieldName is not None:
            directionField = layer.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName is not None:
            speedField = layer.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(layer, directionField, forwardValue,
                                          backwardValue, bothValue,
                                          defaultDirection)

        distUnit = iface.mapCanvas().mapSettings().destinationCrs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(
            distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)
            multiplier = 3600

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(
            iface.mapCanvas().mapSettings().destinationCrs(), True, tolerance)
        feedback.pushInfo(self.tr('Building graph...'))
        snappedPoints = director.makeGraph(builder, [startPoint, endPoint])

        feedback.pushInfo(self.tr('Calculating shortest path...'))
        graph = builder.graph()
        idxStart = graph.findVertex(snappedPoints[0])
        idxEnd = graph.findVertex(snappedPoints[1])

        tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
        if tree[idxEnd] == -1:
            raise GeoAlgorithmExecutionException(
                self.tr('There is no route from start point to end point.'))

        route = []
        cost = 0.0
        current = idxEnd
        while current != idxStart:
            cost += graph.edge(tree[current]).cost(0)
            route.append(
                graph.vertex(graph.edge(tree[current]).inVertex()).point())
            current = graph.edge(tree[current]).outVertex()

        route.append(snappedPoints[0])
        route.reverse()

        self.setOutputValue(self.TRAVEL_COST, cost / multiplier)

        feedback.pushInfo(self.tr('Writing results...'))
        geom = QgsGeometry.fromPolyline(route)
        feat = QgsFeature()
        feat.setFields(fields)
        feat['start'] = startPoint.toString()
        feat['end'] = endPoint.toString()
        feat['cost'] = cost / multiplier
        feat.setGeometry(geom)
        writer.addFeature(feat)
        del writer
    def processAlgorithm(self, parameters, context, feedback):
        network = self.parameterAsSource(parameters, self.INPUT, context)
        startPoints = self.parameterAsSource(parameters, self.START_POINTS, context)
        endPoint = self.parameterAsPoint(parameters, self.END_POINT, context)
        strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)

        directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context)
        forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context)
        backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context)
        bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context)
        defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context)
        speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context)
        defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context)
        tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)

        fields = QgsFields()
        fields.append(QgsField('start', QVariant.String, '', 254, 0))
        fields.append(QgsField('end', QVariant.String, '', 254, 0))
        fields.append(QgsField('cost', QVariant.Double, '', 20, 7))

        feat = QgsFeature()
        feat.setFields(fields)

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               fields, QgsWkbTypes.LineString, network.sourceCrs())

        directionField = -1
        if directionFieldName:
            directionField = network.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName:
            speedField = network.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(network,
                                          directionField,
                                          forwardValue,
                                          backwardValue,
                                          bothValue,
                                          defaultDirection)

        distUnit = context.project().crs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField,
                                               defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)
            multiplier = 3600

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(context.project().crs(),
                                  True,
                                  tolerance)

        feedback.pushInfo(self.tr('Loading start points...'))
        request = QgsFeatureRequest()
        request.setFlags(request.flags() ^ QgsFeatureRequest.SubsetOfAttributes)
        request.setDestinationCrs(network.sourceCrs())
        features = startPoints.getFeatures(request)
        total = 100.0 / startPoints.featureCount() if startPoints.featureCount() else 0

        points = [endPoint]
        for current, f in enumerate(features):
            if feedback.isCanceled():
                break

            points.append(f.geometry().asPoint())
            feedback.setProgress(int(current * total))

        feedback.pushInfo(self.tr('Building graph...'))
        snappedPoints = director.makeGraph(builder, points, feedback)

        feedback.pushInfo(self.tr('Calculating shortest paths...'))
        graph = builder.graph()

        idxEnd = graph.findVertex(snappedPoints[0])
        route = []

        nPoints = len(snappedPoints)
        total = 100.0 / nPoints if nPoints else 1
        for i in range(1, count + 1):
            if feedback.isCanceled():
                break

            idxStart = graph.findVertex(snappedPoints[i])
            tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)

            if tree[idxEnd] == -1:
                msg = self.tr('There is no route from start point ({}) to end point ({}).'.format(points[i].toString(), endPoint.toString()))
                feedback.setProgressText(msg)
                QgsMessageLog.logMessage(msg, self.tr('Processing'), QgsMessageLog.WARNING)
                continue

            cost = 0.0
            current = idxEnd
            while current != idxStart:
                cost += graph.edge(tree[current]).cost(0)
                route.append(graph.vertex(graph.edge(tree[current]).inVertex()).point())
                current = graph.edge(tree[current]).outVertex()

            route.append(snappedPoints[i])
            route.reverse()

            geom = QgsGeometry.fromPolyline(route)
            feat.setGeometry(geom)
            feat['start'] = points[i].toString()
            feat['end'] = endPoint.toString()
            feat['cost'] = cost / multiplier
            sink.addFeature(feat, QgsFeatureSink.FastInsert)

            route[:] = []

            feedback.setProgress(int(i * total))

        return {self.OUTPUT: dest_id}
Example #4
0
    def processAlgorithm(self, feedback):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_VECTOR))
        startPoint = self.getParameterValue(self.START_POINT)
        endPoint = self.getParameterValue(self.END_POINT)
        strategy = self.getParameterValue(self.STRATEGY)

        directionFieldName = self.getParameterValue(self.DIRECTION_FIELD)
        forwardValue = self.getParameterValue(self.VALUE_FORWARD)
        backwardValue = self.getParameterValue(self.VALUE_BACKWARD)
        bothValue = self.getParameterValue(self.VALUE_BOTH)
        defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION)
        bothValue = self.getParameterValue(self.VALUE_BOTH)
        defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION)
        speedFieldName = self.getParameterValue(self.SPEED_FIELD)
        defaultSpeed = self.getParameterValue(self.DEFAULT_SPEED)
        tolerance = self.getParameterValue(self.TOLERANCE)

        fields = QgsFields()
        fields.append(QgsField('start', QVariant.String, '', 254, 0))
        fields.append(QgsField('end', QVariant.String, '', 254, 0))
        fields.append(QgsField('cost', QVariant.Double, '', 20, 7))

        writer = self.getOutputFromName(
            self.OUTPUT_LAYER).getVectorWriter(
                fields.toList(),
                QgsWkbTypes.LineString,
                layer.crs())

        tmp = startPoint.split(',')
        startPoint = QgsPoint(float(tmp[0]), float(tmp[1]))
        tmp = endPoint.split(',')
        endPoint = QgsPoint(float(tmp[0]), float(tmp[1]))

        directionField = -1
        if directionFieldName is not None:
            directionField = layer.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName is not None:
            speedField = layer.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(layer,
                                          directionField,
                                          forwardValue,
                                          backwardValue,
                                          bothValue,
                                          defaultDirection)

        distUnit = iface.mapCanvas().mapSettings().destinationCrs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField,
                                               defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)
            multiplier = 3600

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(iface.mapCanvas().mapSettings().destinationCrs(),
                                  iface.mapCanvas().hasCrsTransformEnabled(),
                                  tolerance)
        feedback.pushInfo(self.tr('Building graph...'))
        snappedPoints = director.makeGraph(builder, [startPoint, endPoint])

        feedback.pushInfo(self.tr('Calculating shortest path...'))
        graph = builder.graph()
        idxStart = graph.findVertex(snappedPoints[0])
        idxEnd = graph.findVertex(snappedPoints[1])

        tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
        if tree[idxEnd] == -1:
            raise GeoAlgorithmExecutionException(
                self.tr('There is no route from start point to end point.'))

        route = []
        cost = 0.0
        current = idxEnd
        while current != idxStart:
            cost += graph.edge(tree[current]).cost(0)
            route.append(graph.vertex(graph.edge(tree[current]).inVertex()).point())
            current = graph.edge(tree[current]).outVertex()

        route.append(snappedPoints[0])
        route.reverse()

        self.setOutputValue(self.TRAVEL_COST, cost / multiplier)

        feedback.pushInfo(self.tr('Writing results...'))
        geom = QgsGeometry.fromPolyline(route)
        feat = QgsFeature()
        feat.setFields(fields)
        feat['start'] = startPoint.toString()
        feat['end'] = endPoint.toString()
        feat['cost'] = cost / multiplier
        feat.setGeometry(geom)
        writer.addFeature(feat)
        del writer
Example #5
0
    def processAlgorithm(self, parameters, context, feedback):
        network = self.parameterAsSource(parameters, self.INPUT, context)
        startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs())
        strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)
        travelCost = self.parameterAsDouble(parameters, self.TRAVEL_COST, context)

        directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context)
        forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context)
        backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context)
        bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context)
        defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context)
        speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context)
        defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context)
        tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)

        directionField = -1
        if directionFieldName:
            directionField = network.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName:
            speedField = network.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(network,
                                          directionField,
                                          forwardValue,
                                          backwardValue,
                                          bothValue,
                                          defaultDirection)

        distUnit = context.project().crs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField,
                                               defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(network.sourceCrs(),
                                  True,
                                  tolerance)
        feedback.pushInfo(self.tr('Building graph...'))
        snappedPoints = director.makeGraph(builder, [startPoint], feedback)

        feedback.pushInfo(self.tr('Calculating service area...'))
        graph = builder.graph()
        idxStart = graph.findVertex(snappedPoints[0])

        tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
        vertices = []
        for i, v in enumerate(cost):
            if v > travelCost and tree[i] != -1:
                vertexId = graph.edge(tree[i]).fromVertex()
                if cost[vertexId] <= travelCost:
                    vertices.append(i)

        upperBoundary = []
        lowerBoundary = []
        for i in vertices:
            upperBoundary.append(graph.vertex(graph.edge(tree[i]).toVertex()).point())
            lowerBoundary.append(graph.vertex(graph.edge(tree[i]).fromVertex()).point())

        feedback.pushInfo(self.tr('Writing results...'))

        fields = QgsFields()
        fields.append(QgsField('type', QVariant.String, '', 254, 0))
        fields.append(QgsField('start', QVariant.String, '', 254, 0))

        feat = QgsFeature()
        feat.setFields(fields)

        geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary)
        geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary)

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               fields, QgsWkbTypes.MultiPoint, network.sourceCrs())

        feat.setGeometry(geomUpper)
        feat['type'] = 'upper'
        feat['start'] = startPoint.toString()
        sink.addFeature(feat, QgsFeatureSink.FastInsert)

        feat.setGeometry(geomLower)
        feat['type'] = 'lower'
        feat['start'] = startPoint.toString()
        sink.addFeature(feat, QgsFeatureSink.FastInsert)

        upperBoundary.append(startPoint)
        lowerBoundary.append(startPoint)
        geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary)
        geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary)

        return {self.OUTPUT: dest_id}
Example #6
0
    def processAlgorithm(self, parameters, context, feedback):
        network = self.parameterAsSource(parameters, self.INPUT, context)
        if network is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

        startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs())
        endPoint = self.parameterAsPoint(parameters, self.END_POINT, context, network.sourceCrs())
        strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)

        directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context)
        forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context)
        backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context)
        bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context)
        defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context)
        speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context)
        defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context)
        tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)

        fields = QgsFields()
        fields.append(QgsField('start', QVariant.String, '', 254, 0))
        fields.append(QgsField('end', QVariant.String, '', 254, 0))
        fields.append(QgsField('cost', QVariant.Double, '', 20, 7))

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               fields, QgsWkbTypes.LineString, network.sourceCrs())
        if sink is None:
            raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))

        directionField = -1
        if directionField:
            directionField = network.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName:
            speedField = network.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(network,
                                          directionField,
                                          forwardValue,
                                          backwardValue,
                                          bothValue,
                                          defaultDirection)

        distUnit = context.project().crs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField,
                                               defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)
            multiplier = 3600

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(network.sourceCrs(),
                                  True,
                                  tolerance)
        feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToPoint', 'Building graph…'))
        snappedPoints = director.makeGraph(builder, [startPoint, endPoint], feedback)

        feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToPoint', 'Calculating shortest path…'))
        graph = builder.graph()
        idxStart = graph.findVertex(snappedPoints[0])
        idxEnd = graph.findVertex(snappedPoints[1])

        tree, costs = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
        if tree[idxEnd] == -1:
            raise QgsProcessingException(
                self.tr('There is no route from start point to end point.'))

        route = [graph.vertex(idxEnd).point()]
        cost = costs[idxEnd]
        current = idxEnd
        while current != idxStart:
            current = graph.edge(tree[current]).fromVertex()
            route.append(graph.vertex(current).point())

        route.reverse()

        feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToPoint', 'Writing results…'))
        geom = QgsGeometry.fromPolylineXY(route)
        feat = QgsFeature()
        feat.setFields(fields)
        feat['start'] = startPoint.toString()
        feat['end'] = endPoint.toString()
        feat['cost'] = cost / multiplier
        feat.setGeometry(geom)
        sink.addFeature(feat, QgsFeatureSink.FastInsert)

        results = {}
        results[self.TRAVEL_COST] = cost / multiplier
        results[self.OUTPUT] = dest_id
        return results
Example #7
0
    def processAlgorithm(self, feedback):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_VECTOR))
        startPoints = dataobjects.getObjectFromUri(
            self.getParameterValue(self.START_POINTS))
        strategy = self.getParameterValue(self.STRATEGY)
        travelCost = self.getParameterValue(self.TRAVEL_COST)

        directionFieldName = self.getParameterValue(self.DIRECTION_FIELD)
        forwardValue = self.getParameterValue(self.VALUE_FORWARD)
        backwardValue = self.getParameterValue(self.VALUE_BACKWARD)
        bothValue = self.getParameterValue(self.VALUE_BOTH)
        defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION)
        bothValue = self.getParameterValue(self.VALUE_BOTH)
        defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION)
        speedFieldName = self.getParameterValue(self.SPEED_FIELD)
        defaultSpeed = self.getParameterValue(self.DEFAULT_SPEED)
        tolerance = self.getParameterValue(self.TOLERANCE)

        fields = QgsFields()
        fields.append(QgsField('type', QVariant.String, '', 254, 0))
        fields.append(QgsField('start', QVariant.String, '', 254, 0))

        feat = QgsFeature()
        feat.setFields(fields)

        writerPoints = self.getOutputFromName(
            self.OUTPUT_POINTS).getVectorWriter(
                fields,
                QgsWkbTypes.MultiPoint,
                layer.crs())

        writerPolygons = self.getOutputFromName(
            self.OUTPUT_POLYGON).getVectorWriter(
                fields,
                QgsWkbTypes.Polygon,
                layer.crs())

        directionField = -1
        if directionFieldName is not None:
            directionField = layer.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName is not None:
            speedField = layer.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(layer,
                                          directionField,
                                          forwardValue,
                                          backwardValue,
                                          bothValue,
                                          defaultDirection)

        distUnit = iface.mapCanvas().mapSettings().destinationCrs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField,
                                               defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(iface.mapCanvas().mapSettings().destinationCrs(),
                                  iface.mapCanvas().hasCrsTransformEnabled(),
                                  tolerance)

        feedback.pushInfo(self.tr('Loading start points...'))
        request = QgsFeatureRequest()
        request.setFlags(request.flags() ^ QgsFeatureRequest.SubsetOfAttributes)
        features = vector.features(startPoints, request)
        points = []
        for f in features:
            points.append(f.geometry().asPoint())

        feedback.pushInfo(self.tr('Building graph...'))
        snappedPoints = director.makeGraph(builder, points)

        feedback.pushInfo(self.tr('Calculating service areas...'))
        graph = builder.graph()

        vertices = []
        upperBoundary = []
        lowerBoundary = []
        total = 100.0 / len(snappedPoints)
        for i, p in enumerate(snappedPoints):
            idxStart = graph.findVertex(snappedPoints[i])
            origPoint = points[i].toString()

            tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
            for j, v in enumerate(cost):
                if v > travelCost and tree[j] != -1:
                    vertexId = graph.edge(tree[j]).outVertex()
                    if cost[vertexId] <= travelCost:
                        vertices.append(j)

            for j in vertices:
                upperBoundary.append(graph.vertex(graph.edge(tree[j]).inVertex()).point())
                lowerBoundary.append(graph.vertex(graph.edge(tree[j]).outVertex()).point())

            geomUpper = QgsGeometry.fromMultiPoint(upperBoundary)
            geomLower = QgsGeometry.fromMultiPoint(lowerBoundary)

            feat.setGeometry(geomUpper)
            feat['type'] = 'upper'
            feat['start'] = origPoint
            writerPoints.addFeature(feat)

            feat.setGeometry(geomLower)
            feat['type'] = 'lower'
            feat['start'] = origPoint
            writerPoints.addFeature(feat)

            upperBoundary.append(startPoint)
            lowerBoundary.append(startPoint)
            geomUpper = QgsGeometry.fromMultiPoint(upperBoundary)
            geomLower = QgsGeometry.fromMultiPoint(lowerBoundary)

            geom = geomUpper.convexHull()
            feat.setGeometry(geom)
            feat['type'] = 'upper'
            feat['start'] = origPoint
            writerPolygons.addFeature(feat)

            geom = geomLower.convexHull()
            feat.setGeometry(geom)
            feat['type'] = 'lower'
            feat['start'] = origPoint
            writerPolygons.addFeature(feat)

            vertices[:] = []
            upperBoundary[:] = []
            lowerBoundary[:] = []

            feedback.setProgress(int(i * total))

        del writerPoints
        del writerPolygons
Example #8
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
                self.getParameterValue(self.INPUT_VECTOR))
        startPoint = self.getParameterValue(self.START_POINT)
        strategy = self.getParameterValue(self.STRATEGY)
        travelCost = self.getParameterValue(self.TRAVEL_COST)

        directionFieldName = self.getParameterValue(self.DIRECTION_FIELD)
        forwardValue = self.getParameterValue(self.VALUE_FORWARD)
        backwardValue = self.getParameterValue(self.VALUE_BACKWARD)
        bothValue = self.getParameterValue(self.VALUE_BOTH)
        defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION)
        bothValue = self.getParameterValue(self.VALUE_BOTH)
        defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION)
        speedFieldName = self.getParameterValue(self.SPEED_FIELD)
        defaultSpeed = self.getParameterValue(self.DEFAULT_SPEED)
        tolerance = self.getParameterValue(self.TOLERANCE)

        tmp = startPoint.split(',')
        startPoint = QgsPoint(float(tmp[0]), float(tmp[1]))

        directionField = -1
        if directionFieldName is not None:
            directionField = layer.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName is not None:
            speedField = layer.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(layer,
                                          directionField,
                                          forwardValue,
                                          backwardValue,
                                          bothValue,
                                          defaultDirection)

        distUnit = iface.mapCanvas().mapSettings().destinationCrs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField,
                                               defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(iface.mapCanvas().mapSettings().destinationCrs(),
                                  iface.mapCanvas().hasCrsTransformEnabled(),
                                  tolerance)
        progress.setInfo(self.tr('Building graph...'))
        snappedPoints = director.makeGraph(builder, [startPoint])

        progress.setInfo(self.tr('Calculating service area...'))
        graph = builder.graph()
        idxStart = graph.findVertex(snappedPoints[0])

        tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
        vertices = []
        for i, v in enumerate(cost):
            if v > travelCost and tree[i] != -1:
                vertexId = graph.edge(tree [i]).outVertex()
                if cost[vertexId] <= travelCost:
                    vertices.append(i)

        upperBoundary = []
        lowerBoundary = []
        for i in vertices:
            upperBoundary.append(graph.vertex(graph.edge(tree[i]).inVertex()).point())
            lowerBoundary.append(graph.vertex(graph.edge(tree[i]).outVertex()).point())

        progress.setInfo(self.tr('Writting results...'))

        fields = QgsFields()
        fields.append(QgsField('type', QVariant.String, '', 254, 0))
        fields.append(QgsField('start', QVariant.String, '', 254, 0))

        feat = QgsFeature()
        feat.setFields(fields)

        geomUpper = QgsGeometry.fromMultiPoint(upperBoundary)
        geomLower = QgsGeometry.fromMultiPoint(lowerBoundary)

        writer = self.getOutputFromName(
            self.OUTPUT_POINTS).getVectorWriter(
                fields,
                QgsWkbTypes.MultiPoint,
                layer.crs())

        feat.setGeometry(geomUpper)
        feat['type'] = 'upper'
        feat['start'] = startPoint.toString()
        writer.addFeature(feat)

        feat.setGeometry(geomLower)
        feat['type'] = 'lower'
        feat['start'] = startPoint.toString()
        writer.addFeature(feat)

        del writer

        writer = self.getOutputFromName(
            self.OUTPUT_POLYGON).getVectorWriter(
                fields,
                QgsWkbTypes.Polygon,
                layer.crs())

        geom = geomUpper.convexHull()
        feat.setGeometry(geom)
        feat['type'] = 'upper'
        feat['start'] = startPoint.toString()
        writer.addFeature(feat)

        geom = geomLower.convexHull()
        feat.setGeometry(geom)
        feat['type'] = 'lower'
        feat['start'] = startPoint.toString()
        writer.addFeature(feat)
        del writer
Example #9
0
class Qneat3Network():
    """
    Qneat3Network:
    Provides basic logic for more advanced network analysis algorithms
    """
    def __init__(
            self,
            input_network,  #QgsProcessingParameterFeatureSource
            input_points,  #[QgsPointXY] or QgsProcessingParameterFeatureSource or QgsVectorLayer --> Implement List of QgsFeatures [QgsFeatures]
            input_strategy,  #int
            input_directionFieldName,  #str, empty if field not given
            input_forwardValue,  #str
            input_backwardValue,  #str
            input_bothValue,  #str
            input_defaultDirection,  #int
            input_analysisCrs,  #QgsCoordinateReferenceSystem
            input_speedField,  #str
            input_defaultSpeed,  #float
            input_tolerance,  #float
            feedback  #feedback object from processing (log window)
    ):
        """
        Constructur for a Qneat3Network object.
        @type input_network: QgsProcessingParameterFeatureSource
        @param input_network: input network dataset from processing algorithm 
        @type input_points: QgsProcessingParameterFeatureSource/QgsVectorLayer/[QgsPointXY]
        @param input_points: input point dataset from processing algorithm
        @type input_strategy: int
        @param input_strategy: Strategy parameter (0 for distance evaluation, 1 time evaluation)
        @type directionFieldName: string
        @param directionFieldName: Field name of field containing direction information
        @type input_forwardValue: string
        @param input_forwardValue: Value assigned to forward-directed edges
        @type input_backwardValue: string
        @param input_backwardValue: Value assigned to backward-directed edges
        @type input_bothValue: string
        @param input_bothValues: Value assigned to undirected edges (accessible from both directions)
        @type input_defaultDirection: QgsVectorLayerDirector.DirectionForward/DirectionBackward/DirectionBoth
        @param input_defaultDirection: QgsVectorLayerDirector Direction enum to determine default direction
        @type input_analysisCrs: QgsCoordinateReferenceSystem
        @param input_analysisCrs: Analysis coordinate system
        @type input_speedField: string
        @param input_speedField: Field name of field containing speed information
        @type input_tolerance: float
        @param input_tolerance: tolerance value when connecting graph edges
        @type feedback: QgsProcessingFeedback
        @param feedback: feedback object from processing algorithm
        
        """

        #initialize feedback
        self.feedback = feedback

        self.feedback.pushInfo("[QNEAT3Network]: setting up parameters")
        self.AnalysisCrs = input_analysisCrs

        #init direction fields
        self.feedback.pushInfo(
            "[QNEAT3Network]: setting up network direction parameters")
        self.directedAnalysis = self.setNetworkDirection(
            (input_directionFieldName, input_forwardValue, input_backwardValue,
             input_bothValue, input_defaultDirection))
        self.director = QgsVectorLayerDirector(
            input_network,
            getFieldIndexFromQgsProcessingFeatureSource(
                input_network, input_directionFieldName), input_forwardValue,
            input_backwardValue, input_bothValue, input_defaultDirection)

        #init analysis points
        self.feedback.pushInfo("[QNEAT3Network]: setting up analysis points")
        if isinstance(input_points, (list, )):
            self.list_input_points = input_points  #[QgsPointXY]
        else:
            self.list_input_points = getListOfPoints(
                input_points)  #[QgsPointXY]
            self.input_points = input_points

        #Setup cost-strategy pattern.
        self.feedback.pushInfo(
            "[QNEAT3Network]: Setting analysis strategy: {}".format(
                input_strategy))
        self.setNetworkStrategy(input_strategy, input_network,
                                input_speedField, input_defaultSpeed)
        self.director.addStrategy(self.strategy)
        #add the strategy to the QgsGraphDirector
        self.director.addStrategy(self.strategy)
        self.builder = QgsGraphBuilder(self.AnalysisCrs)
        #tell the graph-director to make the graph using the builder object and tie the start point geometry to the graph

        self.feedback.pushInfo(
            "[QNEAT3Network]: Start tying analysis points to the graph and building it."
        )
        self.feedback.pushInfo(
            "...This is a compute intensive task and may take some time depending on network size"
        )
        start_local_time = time.localtime()
        start_time = time.time()
        self.feedback.pushInfo("...Start Time: {}".format(
            time.strftime(":%Y-%m-%d %H:%M:%S", start_local_time)))
        self.list_tiedPoints = self.director.makeGraph(self.builder,
                                                       self.list_input_points)
        self.network = self.builder.graph()
        end_local_time = time.localtime()
        end_time = time.time()
        self.feedback.pushInfo("...End Time: {}".format(
            time.strftime(":%Y-%m-%d %H:%M:%S", end_local_time)))
        self.feedback.pushInfo("...Total Build Time: {}".format(end_time -
                                                                start_time))
        self.feedback.pushInfo("[QNEAT3Network]: Analysis setup complete")

    def setNetworkDirection(self, directionArgs):
        if directionArgs.count("") == 0:
            self.directedAnalysis = True
            self.directionFieldId, self.input_forwardValue, self.input_backwardValue, self.input_bothValue, self.input_defaultDirection = directionArgs
        else:
            self.directedAnalysis = False

    def setNetworkStrategy(self, input_strategy, input_network,
                           input_speedField, input_defaultSpeed):
        distUnit = self.AnalysisCrs.mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(
            distUnit, QgsUnitTypes.DistanceMeters)

        speedFieldId = getFieldIndexFromQgsProcessingFeatureSource(
            input_network, input_speedField)
        if input_strategy == 0:
            self.strategy = QgsNetworkDistanceStrategy()
        else:
            self.strategy = QgsNetworkSpeedStrategy(
                speedFieldId, float(input_defaultSpeed),
                multiplier * 1000.0 / 3600.0)
        self.multiplier = 3600

    def calcDijkstra(self, startpoint_id, criterion):
        """Calculates Dijkstra on whole network beginning from one startPoint. Returns a list containing a TreeId-Array and Cost-Array that match up with their indices [[tree],[cost]] """
        tree, cost = QgsGraphAnalyzer.dijkstra(self.network, startpoint_id,
                                               criterion)
        dijkstra_query = list()
        dijkstra_query.insert(0, tree)
        dijkstra_query.insert(1, cost)
        return dijkstra_query

    def calcShortestTree(self, startpoint_id, criterion):
        tree = QgsGraphAnalyzer.shortestTree(self.network, startpoint_id,
                                             criterion)
        return tree

    def calcIsoPoints(self, analysis_point_list, max_dist):
        iso_pointcloud = dict()

        for point in analysis_point_list:
            dijkstra_query = self.calcDijkstra(point.network_vertex_id, 0)
            tree = dijkstra_query[0]
            cost = dijkstra_query[1]

            current_start_point_id = point.point_id
            field_type = getFieldDatatypeFromPythontype(current_start_point_id)
            i = 0
            while i < len(cost):
                #as long as costs at vertex i is greater than iso_distance and there exists an incoming edge (tree[i]!=-1)
                #consider it as a possible catchment polygon element
                if tree[i] != -1:
                    toVertexId = self.network.edge(tree[i]).toVertex()
                    #if the costs of the current vertex are lower than the radius, append the vertex id to results.
                    if cost[toVertexId] <= max_dist:
                        current_cost = cost[toVertexId]
                        #build feature

                        feat = QgsFeature()
                        fields = QgsFields()
                        fields.append(
                            QgsField('vertex_id', QVariant.Int, '', 254, 0))
                        fields.append(
                            QgsField('cost', QVariant.Double, '', 254, 7))
                        fields.append(
                            QgsField('origin_point_id', field_type, '', 254,
                                     7))
                        feat.setFields(fields)
                        feat['vertex_id'] = toVertexId
                        feat['cost'] = current_cost
                        feat['origin_point_id'] = current_start_point_id
                        geom = QgsGeometry().fromPointXY(
                            self.network.vertex(toVertexId).point())
                        feat.setGeometry(geom)

                        if toVertexId not in iso_pointcloud:
                            self.feedback.pushInfo(
                                "insert idx {} with {} cost".format(
                                    toVertexId, current_cost))
                            iso_pointcloud.update({toVertexId: feat})
                        if toVertexId in iso_pointcloud.keys(
                        ) and iso_pointcloud.get(
                                toVertexId)['cost'] > current_cost:
                            #if the vertex already exists in the iso_pointcloud and the c
                            self.feedback.pushInfo(
                                "replace idx {} with {} cost".format(
                                    toVertexId, current_cost))
                            iso_pointcloud.pop(toVertexId)
                            iso_pointcloud.update({toVertexId: feat})
                        #count up to next vertex
                i = i + 1

        return iso_pointcloud.values()  #list of QgsFeature (=QgsFeatureList)

    def calcIsoInterpolation(self, iso_point_layer, resolution,
                             interpolation_raster_path):
        layer_data = QgsInterpolator.LayerData()
        QgsInterpolator.LayerData

        layer_data.source = iso_point_layer  #in QGIS2: vectorLayer
        layer_data.valueSource = QgsInterpolator.ValueAttribute
        layer_data.interpolationAttribute = 1  #take second field to get costs
        layer_data.sourceType = QgsInterpolator.SourcePoints

        tin_interpolator = QgsTinInterpolator([layer_data],
                                              QgsTinInterpolator.Linear)

        rect = iso_point_layer.extent()
        ncol = int((rect.xMaximum() - rect.xMinimum()) / resolution)
        nrows = int((rect.yMaximum() - rect.yMinimum()) / resolution)

        writer = QgsGridFileWriter(tin_interpolator,
                                   self.interpolation_raster_path, rect, ncol,
                                   nrows, resolution, resolution)
        writer.writeFile(self.feedback)  # Creating .asc raste
        return QgsRasterLayer(self.interpolation_raster_path,
                              "temp_qneat3_interpolation_raster", True)

    def calcIsoContours(self, interval, sink):
        ds_in = gdal.Open(self.interpolation_raster_path)
        band_in = ds_in.GetRasterBand(1)
        xsize_in = band_in.XSize
        ysize_in = band_in.YSize

        geotransform_in = ds_in.GetGeoTransform()

        srs = osr.SpatialReference()
        srs.ImportFromWkt(ds_in.GetProjectionRef())

        x_pos = arange(geotransform_in[0],
                       geotransform_in[0] + xsize_in * geotransform_in[1],
                       geotransform_in[1])
        y_pos = arange(geotransform_in[3],
                       geotransform_in[3] + ysize_in * geotransform_in[5],
                       geotransform_in[5])
        x_grid, y_grid = meshgrid(x_pos, y_pos)

        raster_values = band_in.ReadAsArray(0, 0, xsize_in, ysize_in)

        stats = band_in.GetStatistics(False, True)

        min_value = stats[0]
        min_level = interval * floor(min_value / interval)

        max_value = stats[1]
        #Due to range issues, a level is added
        max_level = interval * (1 + ceil(max_value / interval))

        levels = arange(min_level, max_level, interval)

        contours = plt.contourf(x_grid, y_grid, raster_values, levels)

        fields = QgsFields()
        fields.append(QgsField('id', QVariant.Int, '', 254, 0))
        fields.append(QgsField('cost_level', QVariant.Double, '', 254, 7))
        """Maybe move to algorithm"""
        for i, level in enumerate(range(len(contours.collections))):
            paths = contours.collections[level].get_paths()
            for path in paths:

                feat = QgsFeature()
                feat.setFields(fields)
                geom = QgsGeometry().fromPolygonXY(path)
                feat.setGeometry(geom)
                feat['id'] = i
                feat['cost_level'] = level

                sink.addFeature(feat, QgsFeatureSink.FastInsert)
        """Maybe move to algorithm"""
        return sink

    def calcIsoPolygon(self):
        """
        feat_out = ogr.Feature( dst_layer.GetLayerDefn())
        feat_out.SetField( attr_name, contours.levels[level] )
        pol = ogr.Geometry(ogr.wkbPolygon)
        
                        ring = None            
                
                for i in range(len(path.vertices)):
                    point = path.vertices[i]
                    if path.codes[i] == 1:
                        if ring != None:
                            pol.AddGeometry(ring)
                        ring = ogr.Geometry(ogr.wkbLinearRing)
                        
                    ring.AddPoint_2D(point[0], point[1])
                
    
                pol.AddGeometry(ring)
                
                feat_out.SetGeometry(pol)
                if dst_layer.CreateFeature(feat_out) != 0:
                    print "Failed to create feature in shapefile.\n"
                    exit( 1 )
    
                
                feat_out.Destroy()  
        """
        self.iso_polygon
        pass
Example #10
0
    def __init__(
            self,
            input_network,  #QgsProcessingParameterFeatureSource
            input_points,  #[QgsPointXY] or QgsProcessingParameterFeatureSource or QgsVectorLayer --> Implement List of QgsFeatures [QgsFeatures]
            input_strategy,  #int
            input_directionFieldName,  #str, empty if field not given
            input_forwardValue,  #str
            input_backwardValue,  #str
            input_bothValue,  #str
            input_defaultDirection,  #int
            input_analysisCrs,  #QgsCoordinateReferenceSystem
            input_speedField,  #str
            input_defaultSpeed,  #float
            input_tolerance,  #float
            feedback  #feedback object from processing (log window)
    ):
        """
        Constructur for a Qneat3Network object.
        @type input_network: QgsProcessingParameterFeatureSource
        @param input_network: input network dataset from processing algorithm 
        @type input_points: QgsProcessingParameterFeatureSource/QgsVectorLayer/[QgsPointXY]
        @param input_points: input point dataset from processing algorithm
        @type input_strategy: int
        @param input_strategy: Strategy parameter (0 for distance evaluation, 1 time evaluation)
        @type directionFieldName: string
        @param directionFieldName: Field name of field containing direction information
        @type input_forwardValue: string
        @param input_forwardValue: Value assigned to forward-directed edges
        @type input_backwardValue: string
        @param input_backwardValue: Value assigned to backward-directed edges
        @type input_bothValue: string
        @param input_bothValues: Value assigned to undirected edges (accessible from both directions)
        @type input_defaultDirection: QgsVectorLayerDirector.DirectionForward/DirectionBackward/DirectionBoth
        @param input_defaultDirection: QgsVectorLayerDirector Direction enum to determine default direction
        @type input_analysisCrs: QgsCoordinateReferenceSystem
        @param input_analysisCrs: Analysis coordinate system
        @type input_speedField: string
        @param input_speedField: Field name of field containing speed information
        @type input_tolerance: float
        @param input_tolerance: tolerance value when connecting graph edges
        @type feedback: QgsProcessingFeedback
        @param feedback: feedback object from processing algorithm
        
        """

        #initialize feedback
        self.feedback = feedback

        self.feedback.pushInfo("[QNEAT3Network]: setting up parameters")
        self.AnalysisCrs = input_analysisCrs

        #init direction fields
        self.feedback.pushInfo(
            "[QNEAT3Network]: setting up network direction parameters")
        self.directedAnalysis = self.setNetworkDirection(
            (input_directionFieldName, input_forwardValue, input_backwardValue,
             input_bothValue, input_defaultDirection))
        self.director = QgsVectorLayerDirector(
            input_network,
            getFieldIndexFromQgsProcessingFeatureSource(
                input_network, input_directionFieldName), input_forwardValue,
            input_backwardValue, input_bothValue, input_defaultDirection)

        #init analysis points
        self.feedback.pushInfo("[QNEAT3Network]: setting up analysis points")
        if isinstance(input_points, (list, )):
            self.list_input_points = input_points  #[QgsPointXY]
        else:
            self.list_input_points = getListOfPoints(
                input_points)  #[QgsPointXY]
            self.input_points = input_points

        #Setup cost-strategy pattern.
        self.feedback.pushInfo(
            "[QNEAT3Network]: Setting analysis strategy: {}".format(
                input_strategy))
        self.setNetworkStrategy(input_strategy, input_network,
                                input_speedField, input_defaultSpeed)
        self.director.addStrategy(self.strategy)
        #add the strategy to the QgsGraphDirector
        self.director.addStrategy(self.strategy)
        self.builder = QgsGraphBuilder(self.AnalysisCrs)
        #tell the graph-director to make the graph using the builder object and tie the start point geometry to the graph

        self.feedback.pushInfo(
            "[QNEAT3Network]: Start tying analysis points to the graph and building it."
        )
        self.feedback.pushInfo(
            "...This is a compute intensive task and may take some time depending on network size"
        )
        start_local_time = time.localtime()
        start_time = time.time()
        self.feedback.pushInfo("...Start Time: {}".format(
            time.strftime(":%Y-%m-%d %H:%M:%S", start_local_time)))
        self.list_tiedPoints = self.director.makeGraph(self.builder,
                                                       self.list_input_points)
        self.network = self.builder.graph()
        end_local_time = time.localtime()
        end_time = time.time()
        self.feedback.pushInfo("...End Time: {}".format(
            time.strftime(":%Y-%m-%d %H:%M:%S", end_local_time)))
        self.feedback.pushInfo("...Total Build Time: {}".format(end_time -
                                                                start_time))
        self.feedback.pushInfo("[QNEAT3Network]: Analysis setup complete")
Example #11
0
def generate_od_routes(
    network_layer: QgsVectorLayer,
    origin_layer: QgsVectorLayer,
    poi_layer: QgsVectorLayer,
    size_field: str,
    class_field: str,
    work_layer: QgsVectorLayer = None,
    work_size_field: str = None,
    school_layer: QgsVectorLayer = None,
    school_size_field: str = None,
    origin_weight_field: str = None,
    socio_data=None,
    health_data=None,
    diversity_data=None,
    join_on: str = None,
    max_distance: int = 25000,
    return_layer: bool = True,
    return_raw: bool = False,
    feedback: QgsProcessingFeedback = None,
) -> QgsVectorLayer:
    """
    Shortest path algorithm based on Dijkstra's algorithm

    :param network_layer: road network
    :param points_layer: combined from to points
    :param relations_data: tabular from to id data
    :param origin_field: name of from field
    :param destination_field: name of to field
    :param max_distance: maximum distance/cost
    :param crs: output layer crs
    """

    if not network_layer.wkbType() & QgsWkbTypes.LineString:
        raise Exception('Network layer must be of type LineString')
    crs = network_layer.crs()

    ## prepare graph
    director = QgsVectorLayerDirector(
        source=network_layer,
        directionFieldId=-1,
        directDirectionValue='',
        reverseDirectionValue='',
        bothDirectionValue='',
        defaultDirection=QgsVectorLayerDirector.DirectionBoth,
    )
    # First strategy is for actual shortest distance calculation
    director.addStrategy(QgsNetworkDistanceStrategy())  # 0
    # Second strategy is a hack to be able to recover the edge id
    director.addStrategy(SaveFidStrategy())  # 1
    builder = QgsGraphBuilder(crs)

    ## spatial index

    poi_sidx = QgsSpatialIndex(poi_layer)
    work_sidx = QgsSpatialIndex(work_layer)
    school_sidx = QgsSpatialIndex(school_layer)

    ## prepare points
    orig_n = len(origin_layer)
    poi_n = len(poi_layer)
    work_n = len(work_layer) if work_layer else 0
    school_n = len(school_layer) if school_layer else 0
    dest_n = poi_n + work_n + school_n

    orig_points = [None] * orig_n
    orig_sizes = np.zeros(orig_n, dtype=float)
    if socio_data:
        orig_socio = np.zeros(orig_n, dtype=float)
    dest_points = [None] * dest_n
    dest_sizes = [None] * dest_n
    dest_fids = [None] * dest_n
    dest_cats = [None] * dest_n

    orig_id_field = 'deso'
    for i, feat in enumerate(origin_layer.getFeatures()):
        orig_points[i] = feat.geometry().asPoint()
        orig_sizes[i] = feat[size_field] * (
            feat[origin_weight_field] if origin_weight_field else 1
        )

        if socio_data:
            orig_socio[i] = socio_data[
                feat[orig_id_field]
            ]  # FIXME: check if all origins have data

    if socio_data:
        orig_socio = orig_socio / np.mean(orig_socio)
        orig_sizes *= orig_socio

    for i, feat in enumerate(poi_layer.getFeatures()):
        dest_points[i] = feat.geometry().asPoint()
        dest_fids[i] = feat.id()
        dest_sizes[i] = 1  # TODO: dest size
        dest_cats[i] = poi_class_map.get(feat[class_field])

    if work_layer:
        for i, feat in enumerate(work_layer.getFeatures(), start=poi_n):
            dest_points[i] = feat.geometry().asPoint()
            dest_fids[i] = feat.id()
            dest_sizes[i] = feat[work_size_field]  # TODO: dest size
            dest_cats[i] = 'work'

    if school_layer:
        for i, feat in enumerate(school_layer.getFeatures(), start=(poi_n + work_n)):
            dest_points[i] = feat.geometry().asPoint()
            dest_fids[i] = feat.id()
            dest_sizes[i] = feat[school_size_field]  # TODO: dest size
            dest_cats[i] = 'school'

    # points = [origin.point for origin in origins_data] + [
    #    dest.point for dest in dests_data
    # ]

    if feedback is None:
        feedback = QgsProcessingFeedback()

        def progress(p):
            if int(10 * p % 100) == 0:
                print(f'{int(p):#3d}%')

        feedback.progressChanged.connect(progress)

    with timing('build network graph'):
        tied_points = director.makeGraph(
            builder, orig_points + dest_points, feedback=feedback
        )
        graph = builder.graph()

    orig_tied_points = tied_points[:orig_n]
    dest_tied_points = tied_points[orig_n:]

    poi_tied_points = dest_tied_points[:poi_n]
    work_tied_points = dest_tied_points[poi_n : poi_n + work_n]
    school_tied_points = dest_tied_points[poi_n + work_n :]

    dest_fid_to_tied_points = dict(zip(dest_fids, enumerate(dest_tied_points)))

    poi_fid_to_tied_points = dict(zip(dest_fids[:poi_n], enumerate(poi_tied_points)))
    work_fid_to_tied_points = dict(
        zip(dest_fids[poi_n : poi_n + work_n], enumerate(work_tied_points, start=poi_n))
    )
    school_fid_to_tied_points = dict(
        zip(
            dest_fids[poi_n + work_n :],
            enumerate(school_tied_points, start=poi_n + work_n),
        )
    )

    orig_dests = [None] * orig_n
    for i, point in enumerate(orig_points):
        orig_dests[i] = (
            [
                poi_fid_to_tied_points[fid]
                for fid in poi_sidx.nearestNeighbor(
                    point, neighbors=MAX_NEIGHBORS, maxDistance=max_distance
                )
            ]
            + [
                work_fid_to_tied_points[fid]
                for fid in work_sidx.nearestNeighbor(
                    point, neighbors=MAX_NEIGHBORS, maxDistance=max_distance
                )
            ]
            + [
                school_fid_to_tied_points[fid]
                for fid in school_sidx.nearestNeighbor(
                    point, neighbors=MAX_NEIGHBORS, maxDistance=max_distance
                )
            ]
        )

    step = 100.0 / orig_n
    time_dijkstra = 0.0
    time_find = 0.0
    time_route = 0.0
    with timing('calculate connecting routes'):
        routes = []
        # for i, (origin_fid, dest_fids) in enumerate(od_data):
        for i, (orig_point, dests) in enumerate(zip(orig_tied_points, orig_dests)):
            origin_vertex_id = graph.findVertex(orig_point)

            # Calculate the tree and cost using the distance strategy (#0)
            ts = time()
            (tree, cost) = QgsGraphAnalyzer.dijkstra(graph, origin_vertex_id, 0)
            time_dijkstra += time() - ts

            for j, dest_point in dests:
                if feedback.isCanceled():
                    return
                if dest_sizes[j] <= 0:
                    continue
                category = dest_cats[j]
                if category is None:
                    continue
                ts = time()
                dest_vertex_id = graph.findVertex(dest_point)
                time_find += time() - ts
                if tree[dest_vertex_id] != -1 and (
                    cost[dest_vertex_id] <= MAX_DISTANCE_M
                    or MAX_DISTANCE_M <= 0  # TODO: enable skipping max distance
                ):
                    route_distance = cost[dest_vertex_id]
                    # route_points = [graph.vertex(dest_vertex_id).point()]
                    cur_vertex_id = dest_vertex_id
                    route_fids = []
                    # Iterate the graph from dest to origin saving the edges
                    ts = time()
                    while cur_vertex_id != origin_vertex_id:
                        cur_edge = graph.edge(tree[cur_vertex_id])
                        # Here we recover the edge id through strategy #1
                        route_fids.append(cur_edge.cost(1))
                        cur_vertex_id = cur_edge.fromVertex()
                        # route_points.append(graph.vertex(cur_vertex_id).point())
                    time_route += time() - ts

                    # route_points.reverse()
                    # route_geom = QgsGeometry.fromPolylineXY(route_points))

                    # Hack to remove duplicate fids
                    route_fids = list(
                        dict.fromkeys(route_fids)
                    )  # NOTE: requires python >= 3.7 for ordered dict FIXME: add python version check
                    route_fids.reverse()

                    # Calc
                    # TODO: Move to matrix and vectorize calculation using numpy
                    gravity_value = poi_gravity_values[category]
                    bike_params = mode_params_bike[category]
                    ebike_params = mode_params_ebike[category]

                    # NOTE: we include dest size in decay here
                    decay = dest_sizes[j] * math.exp(
                        gravity_value * route_distance / 1000.0
                    )
                    p_bike = sigmoid(*bike_params, route_distance)
                    p_ebike = sigmoid(*ebike_params, route_distance)

                    # TODO: use namedtuple or dataclass
                    routes.append(
                        Route(
                            i,
                            j,
                            category,
                            route_distance,
                            decay,
                            p_bike,
                            p_ebike,
                            route_fids,
                        )
                    )
            feedback.setProgress(i * step)

        print(f'dijkstra took: {time_dijkstra:#1.2f} sec')
        print(f'find vertex took: {time_find:#1.2f} sec')
        print(f'route took: {time_route:#1.2f} sec')

    with timing('post process routes'):
        alpha_bike = 0.8
        alpha_ebke = 0.2

        decay_sums = {cat: defaultdict(float) for cat in poi_categories}
        bike_values = {cat: defaultdict(float) for cat in poi_categories}
        ebike_values = {cat: defaultdict(float) for cat in poi_categories}

        for route in routes:
            # NOTE: dest size is included in decay
            decay_sums[route.cat][route.i] += route.decay
        for route in routes:
            decay_sum = decay_sums[route.cat][route.i]
            # TODO: add T_p and alpha_m
            T_p = trip_generation[route.cat]
            bike_value = (
                T_p
                * alpha_bike
                * orig_sizes[route.i]
                * route.p_bike
                * route.decay
                / decay_sum
            )
            ebike_value = (
                T_p
                * alpha_ebke
                * orig_sizes[route.i]
                * route.p_ebike
                * route.decay
                / decay_sum
            )
            for fid in route.net_fids:
                bike_values[route.cat][fid] += float(bike_value)
                ebike_values[route.cat][fid] += float(ebike_value)

    # FIXME: Un-kludge this
    with timing('create result features'):
        fields = get_fields()

        segments = []
        for feature in network_layer.getFeatures():
            fid = feature.id()
            segment = QgsFeature(fields)
            segment.setGeometry(QgsGeometry(feature.geometry()))

            segment['network_fid'] = fid
            flow = 0.0
            for cat in poi_categories:
                bike_field = f'{cat}_bike_value'
                ebike_field = f'{cat}_ebike_value'

                flow_bike = segment[bike_field] = bike_values[cat].get(fid)
                flow_ebke = segment[ebike_field] = ebike_values[cat].get(fid)

                if flow_bike is not None:
                    flow += flow_bike
                if flow_ebke is not None:
                    flow += flow_ebke

            segment['flow'] = flow
            segment['lts'] = feature['lts']
            segment['vgu'] = feature['vgu']
            segment['R'] = flow * feature['ratio']
            segments.append(segment)

    if not return_layer:
        if return_raw:
            return segments, bike_values, ebike_values
        return segments

    with timing('create result layer'):
        output_layer = QgsVectorLayer(
            f'LineString?crs={crs.toWkt()}', 'segments', 'memory'
        )
        with edit(output_layer):
            for field in fields:
                output_layer.addAttribute(field)
            output_layer.addFeatures(segments, flags=QgsFeatureSink.FastInsert)

    return output_layer
Example #12
0
class Qneat3Network():
    """
    Qneat3Network:
    Provides basic logic for more advanced network analysis algorithms
    """
    def __init__(
            self,
            input_network,  #QgsProcessingParameterFeatureSource
            input_points,  #[QgsPointXY] or QgsProcessingParameterFeatureSource or QgsVectorLayer --> Implement List of QgsFeatures [QgsFeatures]
            input_strategy,  #int
            input_directionFieldName,  #str, empty if field not given
            input_forwardValue,  #str
            input_backwardValue,  #str
            input_bothValue,  #str
            input_defaultDirection,  #int
            input_analysisCrs,  #QgsCoordinateReferenceSystem
            input_speedField,  #str
            input_defaultSpeed,  #float
            input_tolerance,  #float
            feedback  #feedback object from processing (log window)
    ):
        """
        Constructor for a Qneat3Network object.
        @type input_network: QgsProcessingParameterFeatureSource
        @param input_network: input network dataset from processing algorithm 
        @type input_points: QgsProcessingParameterFeatureSource/QgsVectorLayer/[QgsPointXY]
        @param input_points: input point dataset from processing algorithm
        @type input_strategy: int
        @param input_strategy: Strategy parameter (0 for distance evaluation, 1 time evaluation)
        @type directionFieldName: string
        @param directionFieldName: Field name of field containing direction information
        @type input_forwardValue: string
        @param input_forwardValue: Value assigned to forward-directed edges
        @type input_backwardValue: string
        @param input_backwardValue: Value assigned to backward-directed edges
        @type input_bothValue: string
        @param input_bothValues: Value assigned to undirected edges (accessible from both directions)
        @type input_defaultDirection: QgsVectorLayerDirector.DirectionForward/DirectionBackward/DirectionBoth
        @param input_defaultDirection: QgsVectorLayerDirector Direction enum to determine default direction
        @type input_analysisCrs: QgsCoordinateReferenceSystem
        @param input_analysisCrs: Analysis coordinate system
        @type input_speedField: string
        @param input_speedField: Field name of field containing speed information
        @type input_tolerance: float
        @param input_tolerance: tolerance value when connecting graph edges
        @type feedback: QgsProcessingFeedback
        @param feedback: feedback object from processing algorithm
        """

        #initialize feedback
        self.feedback = feedback

        self.feedback.pushInfo(
            "[QNEAT3Network][__init__] Setting up parameters")
        self.AnalysisCrs = input_analysisCrs

        #enable polygon calculation in geographic coordinate systems
        distUnit = self.AnalysisCrs.mapUnits()
        self.meter_to_unit_factor = QgsUnitTypes.fromUnitToUnitFactor(
            QgsUnitTypes.DistanceMeters, distUnit)

        #init direction fields
        self.feedback.pushInfo(
            "[QNEAT3Network][__init__] Setting up network direction parameters"
        )
        self.directedAnalysis = self.setNetworkDirection(
            (input_directionFieldName, input_forwardValue, input_backwardValue,
             input_bothValue, input_defaultDirection))
        self.director = QgsVectorLayerDirector(
            input_network,
            getFieldIndexFromQgsProcessingFeatureSource(
                input_network, input_directionFieldName), input_forwardValue,
            input_backwardValue, input_bothValue, input_defaultDirection)

        #init analysis points
        self.feedback.pushInfo(
            "[QNEAT3Network][__init__] Setting up analysis points")
        if isinstance(input_points, (list, )):
            self.list_input_points = input_points  #[QgsPointXY]
        else:
            self.list_input_points = getListOfPoints(
                input_points)  #[QgsPointXY]
            self.input_points = input_points

        #Setup cost-strategy pattern.
        self.feedback.pushInfo(
            "[QNEAT3Network][__init__] Setting analysis strategy: {}".format(
                input_strategy))
        self.default_speed = input_defaultSpeed

        self.setNetworkStrategy(input_strategy, input_network,
                                input_speedField, input_defaultSpeed)

        #add the strategy to the QgsGraphDirector
        self.director.addStrategy(self.strategy)
        self.builder = QgsGraphBuilder(self.AnalysisCrs)
        #tell the graph-director to make the graph using the builder object and tie the start point geometry to the graph

        self.feedback.pushInfo(
            "[QNEAT3Network][__init__] Start tying analysis points to the graph and building it."
        )
        self.feedback.pushInfo(
            "[QNEAT3Network][__init__] This is a compute intensive task and may take some time depending on network size"
        )
        start_local_time = time.localtime()
        start_time = time.time()
        self.feedback.pushInfo(
            "[QNEAT3Network][__init__] Start Time: {}".format(
                time.strftime(":%Y-%m-%d %H:%M:%S", start_local_time)))
        self.feedback.pushInfo("[QNEAT3Network][__init__] Building...")
        self.list_tiedPoints = self.director.makeGraph(self.builder,
                                                       self.list_input_points,
                                                       self.feedback)
        self.network = self.builder.graph()
        end_local_time = time.localtime()
        end_time = time.time()
        self.feedback.pushInfo("[QNEAT3Network][__init__] End Time: {}".format(
            time.strftime(":%Y-%m-%d %H:%M:%S", end_local_time)))
        self.feedback.pushInfo(
            "[QNEAT3Network][__init__] Total Build Time: {}".format(
                end_time - start_time))
        self.feedback.pushInfo(
            "[QNEAT3Network][__init__] Analysis setup complete")

    def setNetworkDirection(self, directionArgs):
        if directionArgs.count("") == 0:
            self.directedAnalysis = True
            self.directionFieldId, self.input_forwardValue, self.input_backwardValue, self.input_bothValue, self.input_defaultDirection = directionArgs
        else:
            self.directedAnalysis = False

    def setNetworkStrategy(self, input_strategy, input_network,
                           input_speedField, input_defaultSpeed):
        distUnit = self.AnalysisCrs.mapUnits()
        unit_to_meter_factor = QgsUnitTypes.fromUnitToUnitFactor(
            distUnit, QgsUnitTypes.DistanceMeters)

        speedFieldId = getFieldIndexFromQgsProcessingFeatureSource(
            input_network, input_speedField)
        if input_strategy == 0:
            self.strategy = QgsNetworkDistanceStrategy()
            self.strategy_int = 0
        else:
            self.strategy = QgsNetworkSpeedStrategy(
                speedFieldId, float(input_defaultSpeed),
                unit_to_meter_factor * 1000.0 / 3600.0)
            self.strategy_int = 1
        self.multiplier = 3600

    def calcDijkstra(self, startpoint_id, criterion):
        """Calculates Dijkstra on whole network beginning from one startPoint. Returns a list containing a TreeId-Array and Cost-Array that match up with their indices [[tree],[cost]] """
        tree, cost = QgsGraphAnalyzer.dijkstra(self.network, startpoint_id,
                                               criterion)
        dijkstra_query = list()
        dijkstra_query.insert(0, tree)
        dijkstra_query.insert(1, cost)
        return dijkstra_query

    def calcShortestTree(self, startpoint_id, criterion):
        tree = QgsGraphAnalyzer.shortestTree(self.network, startpoint_id,
                                             criterion)
        return tree

    def calcIsoPoints(self, analysis_point_list, max_dist):
        iso_pointcloud = dict()

        for counter, point in enumerate(analysis_point_list):
            self.feedback.pushInfo(
                "[QNEAT3Network][calcIsoPoints] Processing Point {}".format(
                    counter))
            dijkstra_query = self.calcDijkstra(point.network_vertex_id, 0)
            tree = dijkstra_query[0]
            cost = dijkstra_query[1]

            current_start_point_id = point.point_id  #id of the input point
            current_vertex_id = point.network_vertex_id
            entry_cost = point.entry_cost

            field_type = getFieldDatatypeFromPythontype(current_start_point_id)

            #startpoints are not part of the Query so they have to be added manually before
            #dikstra is called.
            start_vertex_feat = QgsFeature()
            start_vertex_fields = QgsFields()
            start_vertex_fields.append(
                QgsField('vertex_id', QVariant.Int, '', 254, 0))
            start_vertex_fields.append(
                QgsField('cost', QVariant.Double, '', 254, 7))
            start_vertex_fields.append(
                QgsField('origin_point_id', field_type, '', 254, 7))
            start_vertex_feat.setFields(start_vertex_fields)
            start_vertex_feat['vertex_id'] = current_vertex_id
            start_vertex_feat['cost'] = entry_cost
            start_vertex_feat['origin_point_id'] = current_start_point_id
            pt_m = QgsPoint(self.network.vertex(current_vertex_id).point())
            pt_m.addMValue(entry_cost)
            geom = QgsGeometry(pt_m)
            start_vertex_feat.setGeometry(geom)

            iso_pointcloud.update({current_vertex_id: start_vertex_feat})

            i = 0
            while i < len(cost):
                #as long as costs at vertex i is greater than iso_distance and there exists an incoming edge (tree[i]!=-1)
                #consider it as a possible catchment polygon element
                if tree[i] != -1:
                    fromVertexId = self.network.edge(tree[i]).toVertex()
                    real_cost = cost[fromVertexId] + entry_cost
                    #if the costs of the current vertex are lower than the radius, append the vertex id to results.
                    if real_cost <= max_dist:
                        #build feature

                        feat = QgsFeature()
                        fields = QgsFields()
                        fields.append(
                            QgsField('vertex_id', QVariant.Int, '', 254, 0))
                        fields.append(
                            QgsField('cost', QVariant.Double, '', 254, 7))
                        fields.append(
                            QgsField('origin_point_id', field_type, '', 254,
                                     7))
                        feat.setFields(fields)
                        feat['vertex_id'] = fromVertexId
                        feat['cost'] = real_cost
                        feat['origin_point_id'] = current_start_point_id
                        pt_m = QgsPoint(
                            self.network.vertex(fromVertexId).point())
                        pt_m.addMValue((500 - cost[fromVertexId]) * 2)
                        geom = QgsGeometry(pt_m)
                        feat.setGeometry(geom)

                        if fromVertexId not in iso_pointcloud:
                            #ERROR: FIRST POINT IN POINTCLOUD WILL NEVER BE ADDED
                            iso_pointcloud.update({fromVertexId: feat})
                        if fromVertexId in iso_pointcloud.keys(
                        ) and iso_pointcloud.get(
                                fromVertexId)['cost'] > real_cost:
                            #if the vertex already exists in the iso_pointcloud and the cost is greater than the existing cost
                            del iso_pointcloud[fromVertexId]
                            #iso_pointcloud.pop(toVertexId)
                            iso_pointcloud.update({fromVertexId: feat})
                        #count up to next vertex
                i = i + 1
                if (i % 10000) == 0:
                    self.feedback.pushInfo(
                        "[QNEAT3Network][calcIsoPoints] Added {} Nodes to iso pointcloud..."
                        .format(i))

        return iso_pointcloud.values()  #list of QgsFeature (=QgsFeatureList)

    def calcQneatInterpolation(self, iso_pointcloud_featurelist, resolution,
                               interpolation_raster_path):
        #prepare spatial index
        uri = 'PointM?crs={}&field=vertex_id:int(254)&field=cost:double(254,7)&key=vertex_id&index=yes'.format(
            self.AnalysisCrs.authid())

        mIsoPointcloud = QgsVectorLayer(uri, "mIsoPointcloud_layer", "memory")
        mIsoPointcloud_provider = mIsoPointcloud.dataProvider()
        mIsoPointcloud_provider.addFeatures(iso_pointcloud_featurelist,
                                            QgsFeatureSink.FastInsert)

        #implement spatial index for lines (closest line, etc...)
        spt_idx = QgsSpatialIndex(
            mIsoPointcloud.getFeatures(QgsFeatureRequest()), self.feedback)

        #prepare numpy coordinate grids
        NoData_value = -9999
        raster_rectangle = mIsoPointcloud.extent()

        #top left point
        xmin = raster_rectangle.xMinimum()
        ymin = raster_rectangle.yMinimum()
        xmax = raster_rectangle.xMaximum()
        ymax = raster_rectangle.yMaximum()

        cols = int((xmax - xmin) / resolution)
        rows = int((ymax - ymin) / resolution)

        output_interpolation_raster = gdal.GetDriverByName('GTiff').Create(
            interpolation_raster_path, cols, rows, 1, gdal.GDT_Float64)
        output_interpolation_raster.SetGeoTransform(
            (xmin, resolution, 0, ymax, 0, -resolution))

        band = output_interpolation_raster.GetRasterBand(1)
        band.SetNoDataValue(NoData_value)

        #initialize zero array with 2 dimensions (according to rows and cols)
        raster_data = zeros(shape=(rows, cols))

        #compute raster cell MIDpoints
        x_pos = linspace(xmin + (resolution / 2), xmax - (resolution / 2),
                         raster_data.shape[1])
        y_pos = linspace(ymax - (resolution / 2), ymin + (resolution / 2),
                         raster_data.shape[0])
        x_grid, y_grid = meshgrid(x_pos, y_pos)

        self.feedback.pushInfo(
            '[QNEAT3Network][calcQneatInterpolation] Beginning with interpolation'
        )
        total_work = rows * cols
        counter = 0

        self.feedback.pushInfo(
            '[QNEAT3Network][calcQneatInterpolation] Total workload: {} cells'.
            format(total_work))
        self.feedback.setProgress(0)
        for i in range(rows):
            for j in range(cols):
                current_pixel_midpoint = QgsPointXY(x_grid[i, j], y_grid[i, j])

                nearest_vertex_fid = spt_idx.nearestNeighbor(
                    current_pixel_midpoint, 1)[0]

                nearest_feature = mIsoPointcloud.getFeature(nearest_vertex_fid)

                nearest_vertex = self.network.vertex(
                    nearest_feature['vertex_id'])

                edges = nearest_vertex.incomingEdges(
                ) + nearest_vertex.outgoingEdges()

                vertex_found = False
                nearest_counter = 2
                while vertex_found == False:
                    n_nearest_feature_fid = spt_idx.nearestNeighbor(
                        current_pixel_midpoint,
                        nearest_counter)[nearest_counter - 1]
                    n_nearest_feature = mIsoPointcloud.getFeature(
                        n_nearest_feature_fid)
                    n_nearest_vertex_id = n_nearest_feature['vertex_id']

                    for edge_id in edges:
                        from_vertex_id = self.network.edge(
                            edge_id).fromVertex()
                        to_vertex_id = self.network.edge(edge_id).toVertex()

                        if n_nearest_vertex_id == from_vertex_id:
                            vertex_found = True
                            vertex_type = "from_vertex"
                            from_point = n_nearest_feature.geometry().asPoint()
                            from_vertex_cost = n_nearest_feature['cost']
                        if n_nearest_vertex_id == to_vertex_id:
                            vertex_found = True
                            vertex_type = "to_vertex"
                            to_point = n_nearest_feature.geometry().asPoint()
                            to_vertex_cost = n_nearest_feature['cost']

                    nearest_counter = nearest_counter + 1
                    """
                    if nearest_counter == 5:
                        vertex_found = True
                        vertex_type = "end_vertex"
                    """

                if vertex_type == "from_vertex":
                    nearest_edge_geometry = QgsGeometry().fromPolylineXY(
                        [from_point, nearest_vertex.point()])
                    res = nearest_edge_geometry.closestSegmentWithContext(
                        current_pixel_midpoint)
                    segment_point = res[
                        1]  #[0: distance, 1: point, 2: left_of, 3: epsilon for snapping]
                    dist_to_segment = segment_point.distance(
                        current_pixel_midpoint)
                    dist_edge = from_point.distance(segment_point)
                    #self.feedback.pushInfo("dist_to_segment = {}".format(dist_to_segment))
                    #self.feedback.pushInfo("dist_on_edge = {}".format(dist_edge))
                    #self.feedback.pushInfo("cost = {}".format(from_vertex_cost))
                    pixel_cost = from_vertex_cost + dist_edge + dist_to_segment
                    raster_data[i, j] = pixel_cost
                elif vertex_type == "to_vertex":
                    nearest_edge_geometry = QgsGeometry().fromPolylineXY(
                        [nearest_vertex.point(), to_point])
                    res = nearest_edge_geometry.closestSegmentWithContext(
                        current_pixel_midpoint)
                    segment_point = res[
                        1]  #[0: distance, 1: point, 2: left_of, 3: epsilon for snapping]
                    dist_to_segment = segment_point.distance(
                        current_pixel_midpoint)
                    dist_edge = to_point.distance(segment_point)
                    #self.feedback.pushInfo("dist_to_segment = {}".format(dist_to_segment))
                    #self.feedback.pushInfo("dist_on_edge = {}".format(dist_edge))
                    #self.feedback.pushInfo("cost = {}".format(from_vertex_cost))
                    pixel_cost = to_vertex_cost + dist_edge + dist_to_segment
                    raster_data[i, j] = pixel_cost
                else:
                    pixel_cost = -99999  #nearest_feature['cost'] + (nearest_vertex.point().distance(current_pixel_midpoint))
                """
                nearest_feature_pointxy = nearest_feature.geometry().asPoint()
                nearest_feature_cost = nearest_feature['cost']
                
                dist_to_vertex = current_pixel_midpoint.distance(nearest_feature_pointxy)
                #implement time cost
                pixel_cost = dist_to_vertex + nearest_feature_cost
                
                raster_data[i,j] = pixel_cost
                """
                counter = counter + 1
                if counter % 1000 == 0:
                    self.feedback.pushInfo(
                        "[QNEAT3Network][calcQneatInterpolation] Interpolated {} cells..."
                        .format(counter))
                self.feedback.setProgress((counter / total_work) * 100)

        band.WriteArray(raster_data)
        outRasterSRS = osr.SpatialReference()
        outRasterSRS.ImportFromWkt(self.AnalysisCrs.toWkt())
        output_interpolation_raster.SetProjection(outRasterSRS.ExportToWkt())
        band.FlushCache()

    def calcIsoTinInterpolation(self, iso_point_layer, resolution,
                                interpolation_raster_path):
        if self.AnalysisCrs.isGeographic():
            raise QgsProcessingException(
                'The TIN-Interpolation algorithm in QGIS is designed to work with projected coordinate systems.Please use a projected coordinate system (eg. UTM zones) instead of geographic coordinate systems (eg. WGS84)!'
            )

        layer_data = QgsInterpolator.LayerData()
        QgsInterpolator.LayerData

        layer_data.source = iso_point_layer  #in QGIS2: vectorLayer
        layer_data.valueSource = QgsInterpolator.ValueAttribute
        layer_data.interpolationAttribute = 1  #take second field to get costs
        layer_data.sourceType = QgsInterpolator.SourcePoints

        tin_interpolator = QgsTinInterpolator([layer_data],
                                              QgsTinInterpolator.Linear)

        rect = iso_point_layer.extent()
        ncol = int((rect.xMaximum() - rect.xMinimum()) / resolution)
        nrows = int((rect.yMaximum() - rect.yMinimum()) / resolution)

        writer = QgsGridFileWriter(tin_interpolator, interpolation_raster_path,
                                   rect, ncol, nrows)
        writer.writeFile(self.feedback)  # Creating .asc raste
        return QgsRasterLayer(interpolation_raster_path,
                              "temp_qneat3_interpolation_raster")

    def calcIsoContours(self, max_dist, interval, interpolation_raster_path):
        featurelist = []

        try:
            import matplotlib.pyplot as plt
        except:
            return featurelist

        ds_in = gdal.Open(interpolation_raster_path)
        band_in = ds_in.GetRasterBand(1)
        xsize_in = band_in.XSize
        ysize_in = band_in.YSize

        geotransform_in = ds_in.GetGeoTransform()

        srs = osr.SpatialReference()
        srs.ImportFromWkt(ds_in.GetProjectionRef())

        raster_values = band_in.ReadAsArray(0, 0, xsize_in, ysize_in)
        raster_values[
            raster_values <
            0] = max_dist + 1000  #necessary to produce rectangular array from raster
        #nodata values get replaced by the maximum value + 1

        x_pos = linspace(
            geotransform_in[0],
            geotransform_in[0] + geotransform_in[1] * raster_values.shape[1],
            raster_values.shape[1])
        y_pos = linspace(
            geotransform_in[3],
            geotransform_in[3] + geotransform_in[5] * raster_values.shape[0],
            raster_values.shape[0])
        x_grid, y_grid = meshgrid(x_pos, y_pos)

        start = interval
        end = interval * ceil(max_dist / interval) + interval

        levels = arange(start, end, interval)

        fid = 0
        for current_level in nditer(levels):
            self.feedback.pushInfo(
                "[QNEAT3Network][calcIsoContours] Calculating {}-level contours"
                .format(current_level))
            contours = plt.contourf(x_grid,
                                    y_grid,
                                    raster_values, [0, current_level],
                                    antialiased=True)

            for collection in contours.collections:
                for contour_paths in collection.get_paths():
                    for polygon in contour_paths.to_polygons():
                        x = polygon[:, 0]
                        y = polygon[:, 1]

                        polylinexy_list = [
                            QgsPointXY(i[0], i[1]) for i in zip(x, y)
                        ]

                        feat = QgsFeature()
                        fields = QgsFields()
                        fields.append(QgsField('id', QVariant.Int, '', 254, 0))
                        fields.append(
                            QgsField('cost_level', QVariant.Double, '', 20, 7))
                        feat.setFields(fields)
                        geom = QgsGeometry().fromPolylineXY(polylinexy_list)
                        feat.setGeometry(geom)
                        feat['id'] = fid
                        feat['cost_level'] = float(current_level)
                        featurelist.insert(0, feat)

            fid = fid + 1
        return featurelist

    def calcIsoPolygons(self, max_dist, interval, interpolation_raster_path):
        featurelist = []

        try:
            import matplotlib.pyplot as plt
        except:
            return featurelist

        ds_in = gdal.Open(interpolation_raster_path)
        band_in = ds_in.GetRasterBand(1)
        xsize_in = band_in.XSize
        ysize_in = band_in.YSize

        geotransform_in = ds_in.GetGeoTransform()

        srs = osr.SpatialReference()
        srs.ImportFromWkt(ds_in.GetProjectionRef())

        raster_values = band_in.ReadAsArray(0, 0, xsize_in, ysize_in)
        raster_values[
            raster_values <
            0] = max_dist + 1000  #necessary to produce rectangular array from raster
        #nodata values get replaced by the maximum value + 1

        x_pos = linspace(
            geotransform_in[0],
            geotransform_in[0] + geotransform_in[1] * raster_values.shape[1],
            raster_values.shape[1])
        y_pos = linspace(
            geotransform_in[3],
            geotransform_in[3] + geotransform_in[5] * raster_values.shape[0],
            raster_values.shape[0])
        x_grid, y_grid = meshgrid(x_pos, y_pos)

        start = interval
        end = interval * ceil(max_dist / interval) + interval

        levels = arange(start, end, interval)

        fid = 0
        for current_level in nditer(levels):
            self.feedback.pushInfo(
                "[QNEAT3Network][calcIsoPolygons] calculating {}-level contours"
                .format(current_level))
            contours = plt.contourf(x_grid,
                                    y_grid,
                                    raster_values, [0, current_level],
                                    antialiased=True)

            for collection in contours.collections:
                for contour_path in collection.get_paths():

                    polygon_list = []

                    for vertex in contour_path.to_polygons():
                        x = vertex[:, 0]
                        y = vertex[:, 1]

                        polylinexy_list = [
                            QgsPointXY(i[0], i[1]) for i in zip(x, y)
                        ]
                        polygon_list.append(polylinexy_list)

                    feat = QgsFeature()
                    fields = QgsFields()
                    fields.append(QgsField('id', QVariant.Int, '', 254, 0))
                    fields.append(
                        QgsField('cost_level', QVariant.Double, '', 20, 7))
                    feat.setFields(fields)
                    geom = QgsGeometry().fromPolygonXY(polygon_list)
                    feat.setGeometry(geom)
                    feat['id'] = fid
                    feat['cost_level'] = float(current_level)

                    featurelist.insert(0, feat)
            fid = fid + 1
        """Maybe move to algorithm"""
        #featurelist = featurelist[::-1] #reverse
        self.feedback.pushInfo(
            "[QNEAT3Network][calcIsoPolygons] number of elements in contour_featurelist: {}"
            .format(len(featurelist)))
        return featurelist
Example #13
0
class mtrForm(MTR_RestrictionDialog):
    def __init__(self, iface, parent=None):
        if not parent:
            parent = iface.mainWindow()
        super().__init__(parent)

        self.iface = iface

        QgsMessageLog.logMessage("In generateMTRForm::init", tag="TOMs panel")

        #self.currDialog = MTR_RestrictionDialog(self.iface.mainWindow())
        self.linkLayer = QgsProject.instance().mapLayersByName(
            "OS_RAMI_RoadLink")[0]
        self.dbConn = self.getDbConnection()
        if not self.dbConn:
            reply = QMessageBox.information(None, "Information",
                                            "Problem with db connection",
                                            QMessageBox.Ok)
            return

        self.currPointReferenceMapTool = None

        self.setupThisUi()
        # https://www.tutorialspoint.com/pyqt/pyqt_qstackedwidget.htm

        self.setupTrace()
        self.ptList = []

    def setupThisUi(self):

        # create stacked widgets that can be used based on the restriction type choosen
        self.accessRestrictionAttributeStack = QWidget()
        self.turnRestrictionAttributeStack = QWidget()
        self.highwayDedicationAttributeStack = QWidget()
        self.restrictionForVehiclesAttributeStack = QWidget()

        self.attributeLayout = self.findChild(QFormLayout,
                                              "attributesFormLayout")

        self.accessRestrictionGeometryStack = QWidget()
        self.turnRestrictionGeometryStack = QWidget()
        self.highwayDedicationGeometryStack = QWidget()
        self.restrictionForVehiclesGeometryStack = QWidget()

        self.geometryLayout = self.findChild(QFormLayout, "geometryFormLayout")

        self.generateAccessRestrictionForm()
        self.generateTurnRestrictionForm()
        self.generateHighwayDedicationForm()
        self.generateRestrictionForVehiclesForm()

        self.geometryStack = QStackedWidget(self)
        self.geometryStack.addWidget(self.accessRestrictionGeometryStack)
        self.geometryStack.addWidget(self.turnRestrictionGeometryStack)
        self.geometryStack.addWidget(self.highwayDedicationGeometryStack)
        self.geometryStack.addWidget(self.restrictionForVehiclesGeometryStack)
        self.geometryLayout.addWidget(self.geometryStack)

        self.attributeStack = QStackedWidget(self)
        self.attributeStack.addWidget(self.accessRestrictionAttributeStack)
        self.attributeStack.addWidget(self.turnRestrictionAttributeStack)
        self.attributeStack.addWidget(self.highwayDedicationAttributeStack)
        self.attributeStack.addWidget(
            self.restrictionForVehiclesAttributeStack)

        self.attributeLayout.addWidget(self.attributeStack)

        self.generateFirstStageForm()

        # Display for shortest path
        self.rbShortPath = QgsRubberBand(self.iface.mapCanvas())
        self.rbShortPath.setColor(Qt.green)
        self.rbShortPath.setWidth(5)

    def setupTrace(self):

        self.director = QgsVectorLayerDirector(
            self.linkLayer, -1, '', '', '',
            QgsVectorLayerDirector.DirectionBoth)
        strategy = QgsNetworkDistanceStrategy()
        self.director.addStrategy(strategy)
        self.builder = QgsGraphBuilder(self.linkLayer.crs())

    def generateFirstStageForm(self):

        QgsMessageLog.logMessage(
            "In generateFirstStageForm::generateForm ... ", tag="TOMs panel")

        mtrTypeLayout = self.findChild(QFormLayout, "MTR_Type_Layout")
        self.mtrTypeCB = self.findChild(QComboBox, "cmb_MTR_list")

        enumList = self.getEnumList('MT_RestrictionType')

        #QgsMessageLog.logMessage("In generateFirstStageForm::generateForm ... signal connected 1", tag="TOMs panel")
        self.mtrTypeCB.addItems(enumList)
        #QgsMessageLog.logMessage("In generateFirstStageForm::generateForm ... signal connected 2", tag="TOMs panel")
        self.mtrTypeCB.currentIndexChanged.connect(self.onChanged)
        self.mtrTypeCB.setCurrentIndex(1)
        QgsMessageLog.logMessage(
            "In generateFirstStageForm::generateForm ... signal connected 3",
            tag="TOMs panel")

    def onChanged(self, i):
        QgsMessageLog.logMessage(
            "In generateFirstStageForm::selectionchange...", tag="TOMs panel")
        #QgsMessageLog.logMessage("In generateFirstStageForm::selectionchange.  Current index selection changed " + text, tag="TOMs panel")
        self.attributeStack.setCurrentIndex(i -
                                            1)  # to take account of the "null"
        self.geometryStack.setCurrentIndex(i -
                                           1)  # to take account of the "null"

    def getPointReference(self):
        QgsMessageLog.logMessage("In getPointReference ..." +
                                 self.mtrTypeCB.currentText(),
                                 tag="TOMs panel")

        self.mapTool = self.currPointReferenceMapTool

        if not self.mapTool:
            self.mapTool = getLinkDetailsMapTool(self.iface)
            self.currPointReferenceMapTool = self.mapTool

        self.iface.mapCanvas().setMapTool(self.mapTool)

        self.mapTool.notifyLinkFound.connect(self.foundLinkForPoint)

    def getLinkReference(self):
        QgsMessageLog.logMessage("In getLinkReference ..." +
                                 self.mtrTypeCB.currentText(),
                                 tag="TOMs panel")

        self.mapTool = self.currPointReferenceMapTool

        if not self.mapTool:
            self.mapTool = getLinkDetailsMapTool(self.iface)
            self.currPointReferenceMapTool = self.mapTool

        self.iface.mapCanvas().setMapTool(self.mapTool)

        self.mapTool.notifyLinkFound.connect(self.foundLinkForLine)

    def getLinkReferenceFirst(self):
        QgsMessageLog.logMessage("In getLinkReferenceFirst ... ",
                                 tag="TOMs panel")
        self.ptList = []
        self.rbShortPath.reset()
        self.getLinkReference()

    def foundLinkForPoint(self, nearestPt, feature, length):
        QgsMessageLog.logMessage("In foundLink ... length: " + str(length),
                                 tag="TOMs panel")
        self.mapTool.notifyLinkFound.disconnect(self.foundLinkForPoint)

        # check restriction type
        # if only point
        # process point
        # add details to relevant layers
        # make the geometry layout "not available" and highlight the attribute details
        # otherwise check whether or not a point is already found

    def foundLinkForLine(self, nearestPt, feature, length):
        QgsMessageLog.logMessage("In foundLink ... length: " + str(length),
                                 tag="TOMs panel")
        self.mapTool.notifyLinkFound.disconnect(self.foundLinkForLine)

        # add details to list
        self.ptList.append((nearestPt, feature, length))
        if len(self.ptList) >= 2:
            # we can now display the line - taken from Qgis Py Cookbook
            startPt = self.ptList[0][0].asPoint()
            endPt = self.ptList[1][0].asPoint()

            QgsMessageLog.logMessage("In foundLinkForLine::startPt " +
                                     startPt.asWkt(),
                                     tag="TOMs panel")
            QgsMessageLog.logMessage("In foundLinkForLine::endPt " +
                                     endPt.asWkt(),
                                     tag="TOMs panel")

            route = self.showShortestPath(startPt, endPt)

            # prepare list of links

            startFeature = self.ptList[0][1]
            endFeature = self.ptList[1][1]

            if startFeature != endFeature:
                # need to step through route and identify each new link

                self.linkList = [startFeature]
                currLink = startFeature
                QgsMessageLog.logMessage("In foundLinkForLine::currLink " +
                                         currLink.geometry().asWkt(),
                                         tag="TOMs panel")
                for currPt in route:
                    # if p is on currLink, move on. Otherwise add link to list
                    QgsMessageLog.logMessage("In foundLinkForLine::currPt " +
                                             currPt.asWkt(),
                                             tag="TOMs panel")

                    if not self.pointOnLine(currPt, currLink.geometry()):
                        # get link that contains p and prevPt
                        nextLink = self.findLinkContainingLine(prevPt, currPt)
                        if nextLink == endFeature:
                            break
                        else:
                            self.linkList.append(nextLink)
                            currLink = nextLink
                            QgsMessageLog.logMessage(
                                "In foundLinkForLine::currLink " +
                                currLink.geometry().asWkt(),
                                tag="TOMs panel")

                    prevPt = currPt

                self.linkList.append(endFeature)

    def pointOnLine(self, pt, lineGeom):

        ptGeom = QgsGeometry.fromPointXY(pt)
        dist = ptGeom.distance(lineGeom.nearestPoint(ptGeom))
        QgsMessageLog.logMessage("In pointOnLine. Dist " + str(dist),
                                 tag="TOMs panel")
        if dist > 0.001:
            return False

        return True

    def findLinkContainingLine(self, pt1, pt2):

        QgsMessageLog.logMessage("In findLinkContainingLine::pt1 " +
                                 pt1.asWkt() + " pt2: " + pt2.asWkt(),
                                 tag="TOMs panel")

        lineGeom = QgsGeometry.fromPolylineXY([pt1, pt2])

        request = QgsFeatureRequest().setFilterRect(QgsRectangle(pt1, pt2))
        for feature in self.linkLayer.getFeatures(request):

            intersectGeom = lineGeom.intersection(feature.geometry())
            QgsMessageLog.logMessage(
                "In findLinkContainingLine:: intersectGeom " +
                intersectGeom.asWkt(),
                tag="TOMs panel")

            if intersectGeom.type() == QgsWkbTypes.LineGeometry:
                # this is our next feature
                return feature

        QgsMessageLog.logMessage(
            "In findLinkContainingLine: ERROR. No link found containing line.",
            tag="TOMs panel")
        return None

    def showShortestPath(self, startPoint, endPoint):
        # taken from Qgis Py Cookbook
        #startPoint = self.ptList[0][0].asPoint()
        #endPoint = self.ptList[1][0].asPoint()

        tiedPoints = self.director.makeGraph(self.builder,
                                             [startPoint, endPoint])
        tStart, tStop = tiedPoints

        graph = self.builder.graph()
        idxStart = graph.findVertex(tStart)

        tree = QgsGraphAnalyzer.shortestTree(graph, idxStart, 0)

        idxStart = tree.findVertex(tStart)
        idxEnd = tree.findVertex(tStop)

        if idxEnd == -1:
            raise Exception('No route!')

        # Add last point
        route = [tree.vertex(idxEnd).point()]

        # Iterate the graph
        while idxEnd != idxStart:
            edgeIds = tree.vertex(idxEnd).incomingEdges()
            if len(edgeIds) == 0:
                break
            edge = tree.edge(edgeIds[0])
            route.insert(0, tree.vertex(edge.fromVertex()).point())
            idxEnd = edge.fromVertex()

        # This may require coordinate transformation if project's CRS
        # is different than layer's CRS
        for p in route:
            self.rbShortPath.addPoint(p)

        return route

    def generateAccessRestrictionForm(self):

        QgsMessageLog.logMessage(
            "In generateAccessRestrictionForm::generateForm ... ",
            tag="TOMs panel")

        layout = QFormLayout()
        #groupBox = QGroupBox("Restriction Attributes", self.currDialog)
        #formLayout = QFormLayout()

        # Add access restriction type
        self.cb_accessRestrictionType = QComboBox(self)
        enumList = self.getEnumList('AccessRestrictionValue')
        self.cb_accessRestrictionType.addItems(enumList)
        layout.addRow(self.tr("&Access Restriction Type:"),
                      self.cb_accessRestrictionType)

        # Add vehicle exemption
        self.cb_accessRestrictionVehicleExemptions = QComboBox(self)
        enumList = self.getTableList('"moving_traffic"."vehicleQualifiers"')
        self.cb_accessRestrictionVehicleExemptions.addItems(enumList)
        layout.addRow(self.tr("&Vehicle exemptions:"),
                      self.cb_accessRestrictionVehicleExemptions)

        # Add vehicle inclusions
        self.cb_accessRestrictionVehicleInclusions = QComboBox(self)
        enumList = self.getTableList('"moving_traffic"."vehicleQualifiers"')
        self.cb_accessRestrictionVehicleInclusions.addItems(enumList)
        layout.addRow(self.tr("&Vehicle inclusions:"),
                      self.cb_accessRestrictionVehicleInclusions)

        # add time intervals
        self.cb_accessRestrictionTimePeriods = QComboBox(self)
        enumList = self.getTableList('"moving_traffic"."TimePeriods"')
        self.cb_accessRestrictionTimePeriods.addItems(enumList)
        layout.addRow(self.tr("&Time Period:"),
                      self.cb_accessRestrictionTimePeriods)

        # add traffic sign
        """self.cb_trafficSign = QComboBox(self)
        enumList = self.getTableList('Signs')
        self.cb_timePeriods.addItems(enumList)
        layout.addRow(self.tr("&Traffic Sign:"), self.cb_timePeriods)"""

        self.accessRestrictionAttributeStack.setLayout(layout)

        # set up network reference capture

        geomLayout = QFormLayout()
        self.btn_PointReference = QPushButton("Location")
        self.btn_PointReference.clicked.connect(self.getPointReference)
        geomLayout.addRow(self.tr("&Access Restriction Location:"),
                          self.btn_PointReference)

        # add link direction
        self.cb_accessRestrictionLinkDirectionValue = QComboBox(self)
        enumList = self.getEnumList('LinkDirectionValue')
        self.cb_accessRestrictionLinkDirectionValue.addItems(enumList)
        geomLayout.addRow(self.tr("&Applicable link direction:"),
                          self.cb_accessRestrictionLinkDirectionValue)

        self.accessRestrictionGeometryStack.setLayout(geomLayout)

        # create relevant features
        """
        self.accessRestrictionFeature = QgsFeature(self.accessRestrictionLayer)
        self.accessRestrictionNetworkReference = QgsFeature(self.pointReferenceLayer)
        # link them together with a uuid??

        # self.accessRestrictionFeature
        """

    def generateTurnRestrictionForm(self):

        QgsMessageLog.logMessage(
            "In generateTurnRestrictionForm::generateForm ... ",
            tag="TOMs panel")

        layout = QFormLayout()

        # Add turn restriction type
        self.cb_turnRestrictionType = QComboBox(self)
        enumList = self.getEnumList('TurnRestrictionValue')
        self.cb_turnRestrictionType.addItems(enumList)
        layout.addRow(self.tr("&Turn Restriction Type:"),
                      self.cb_turnRestrictionType)

        # Add vehicle exemption
        self.cb_turnRestrictionVehicleExemptions = QComboBox(self)
        enumList = self.getTableList('"moving_traffic"."vehicleQualifiers"')
        self.cb_turnRestrictionVehicleExemptions.addItems(enumList)
        layout.addRow(self.tr("&Vehicle exemptions:"),
                      self.cb_turnRestrictionVehicleExemptions)

        # Add vehicle inclusions
        self.cb_turnRestrictionVehicleInclusions = QComboBox(self)
        enumList = self.getTableList('"moving_traffic"."vehicleQualifiers"')
        self.cb_turnRestrictionVehicleInclusions.addItems(enumList)
        layout.addRow(self.tr("&Vehicle inclusions:"),
                      self.cb_turnRestrictionVehicleInclusions)

        # add time intervals
        self.cb_turnRestrictionTimePeriods = QComboBox(self)
        enumList = self.getTableList('"moving_traffic"."TimePeriods"')
        self.cb_turnRestrictionTimePeriods.addItems(enumList)
        layout.addRow(self.tr("&Time Period:"),
                      self.cb_turnRestrictionTimePeriods)

        self.turnRestrictionAttributeStack.setLayout(layout)

        # set up network reference capture

        geomLayout = QFormLayout()
        self.btn_StartReference = QPushButton("Start")
        self.btn_EndReference = QPushButton("End")
        self.btn_StartReference.clicked.connect(self.getLinkReferenceFirst)
        self.btn_EndReference.clicked.connect(self.getLinkReference)
        geomLayout.addRow(self.tr("&Turn Restriction Start:"),
                          self.btn_StartReference)
        geomLayout.addRow(self.tr("&Turn Restriction End:"),
                          self.btn_EndReference)

        self.turnRestrictionGeometryStack.setLayout(geomLayout)

        # create relevant features
        """
        self.turnRestrictionFeature = QgsFeature(self.turnRestrictionLayer)
        self.turnRestrictionNetworkReference = QgsFeature(self.linkReferenceLayer)
        # link them together with a uuid??

        # self.accessRestrictionFeature
        """

    def generateHighwayDedicationForm(self):

        QgsMessageLog.logMessage(
            "In generateHighwayDedicationForm::generateForm ... ",
            tag="TOMs panel")

        layout = QFormLayout()

        # Add turn restriction type
        self.cb_dedicationValue = QComboBox(self)
        enumList = self.getEnumList('DedicationValue')
        self.cb_dedicationValue.addItems(enumList)
        layout.addRow(self.tr("&Dedication:"), self.cb_dedicationValue)

        self.highwayDedicationAttributeStack.setLayout(layout)

        # set up network reference capture

        geomLayout = QFormLayout()
        self.btn_StartReference = QPushButton("Start")
        self.btn_EndReference = QPushButton("End")
        self.btn_StartReference.clicked.connect(self.getLinkReferenceFirst)
        self.btn_EndReference.clicked.connect(self.getLinkReference)
        geomLayout.addRow(self.tr("&Highway Dedication Start:"),
                          self.btn_StartReference)
        geomLayout.addRow(self.tr("&Highway Dedication End:"),
                          self.btn_EndReference)

        self.highwayDedicationGeometryStack.setLayout(geomLayout)

        # create relevant features
        """
        self.turnRestrictionFeature = QgsFeature(self.turnRestrictionLayer)
        self.turnRestrictionNetworkReference = QgsFeature(self.linkReferenceLayer)
        # link them together with a uuid??

        # self.accessRestrictionFeature
        """

    def generateRestrictionForVehiclesForm(self):

        QgsMessageLog.logMessage(
            "In generateRestrictionForVehiclesForm::generateForm ... ",
            tag="TOMs panel")

        layout = QFormLayout()
        # Add restriction for vehicles type
        self.cb_restrictionForVehiclesType = QComboBox(self)
        enumList = self.getEnumList('RestrictionTypeValue')
        self.cb_restrictionForVehiclesType.addItems(enumList)
        layout.addRow(self.tr("&Access Restriction Type:"),
                      self.cb_restrictionForVehiclesType)

        # add measure
        self.le_restrictionForVehiclesMeasure = QLineEdit()
        self.le_restrictionForVehiclesMeasure.setValidator(
            QDoubleValidator(0.99, 999.99, 2))
        layout.addRow(self.tr("&Measure (in metric units):"),
                      self.le_restrictionForVehiclesMeasure)

        # add measure
        self.le_restrictionForVehiclesMeasure2 = QLineEdit()
        self.le_restrictionForVehiclesMeasure2.setValidator(
            QDoubleValidator(0.99, 999.99, 2))
        layout.addRow(
            self.tr("&Measure (in imperial units) [only if present]:"),
            self.le_restrictionForVehiclesMeasure2)

        # Add vehicle exemption
        self.cb_restrictionForVehiclesVehicleExemptions = QComboBox(self)
        enumList = self.getTableList('"moving_traffic"."vehicleQualifiers"')
        self.cb_restrictionForVehiclesVehicleExemptions.addItems(enumList)
        layout.addRow(self.tr("&Vehicle exemptions:"),
                      self.cb_restrictionForVehiclesVehicleExemptions)

        # Add vehicle inclusions
        self.cb_restrictionForVehiclesVehicleInclusions = QComboBox(self)
        enumList = self.getTableList('"moving_traffic"."vehicleQualifiers"')
        self.cb_restrictionForVehiclesVehicleInclusions.addItems(enumList)
        layout.addRow(self.tr("&Vehicle inclusions:"),
                      self.cb_restrictionForVehiclesVehicleInclusions)

        # add structure type
        self.cb_restrictionForVehiclesStructureType = QComboBox(self)
        enumList = self.getEnumList('StructureTypeValue')
        self.cb_restrictionForVehiclesStructureType.addItems(enumList)
        layout.addRow(self.tr("&Structure Type:"),
                      self.cb_restrictionForVehiclesStructureType)

        # add traffic sign
        """self.cb_trafficSign = QComboBox(self)
        enumList = self.getTableList('Signs')
        self.cb_timePeriods.addItems(enumList)
        layout.addRow(self.tr("&Traffic Sign:"), self.cb_timePeriods)"""

        self.restrictionForVehiclesAttributeStack.setLayout(layout)

        geomLayout = QFormLayout()
        self.btn_PointReference = QPushButton("Location")
        self.btn_PointReference.clicked.connect(self.getPointReference)
        geomLayout.addRow(self.tr("&Restriction For Vehicle Location:"),
                          self.btn_PointReference)

        # add link direction
        self.cb_restrictionForVehiclesLinkDirectionValue = QComboBox(self)
        enumList = self.getEnumList('LinkDirectionValue')
        self.cb_restrictionForVehiclesLinkDirectionValue.addItems(enumList)
        geomLayout.addRow(self.tr("&Applicable link direction:"),
                          self.cb_restrictionForVehiclesLinkDirectionValue)

        self.restrictionForVehiclesGeometryStack.setLayout(geomLayout)

        # create relevant features
        """
        self.accessRestrictionFeature = QgsFeature(self.accessRestrictionLayer)
        self.accessRestrictionNetworkReference = QgsFeature(self.pointReferenceLayer)
        # link them together with a uuid??

        # self.accessRestrictionFeature
        """

    def getDbConnection(self):
        # http://pyqgis.org/blog/2013/04/11/creating-a-postgresql-connection-from-a-qgis-layer-datasource/
        # get the active layer
        dbConn = None
        #layer = self.iface.activeLayer()  # TODO: use a layer know to be using the database

        # get the underlying data provider
        provider = self.linkLayer.dataProvider()
        if provider.name() == 'postgres':
            # get the URI containing the connection parameters
            uri = QgsDataSourceUri(provider.dataSourceUri())
            QgsMessageLog.logMessage(
                "In captureGPSFeatures::getDbConnection. db URI :" + uri.uri(),
                tag="TOMs panel")
            dbConn = psycopg2.connect(uri.connectionInfo())

        return dbConn

    def getEnumList(self, enum):
        typeList = [
            '',
        ]

        query = 'SELECT unnest(enum_range(NULL::"{}"))::text'.format(enum)
        QgsMessageLog.logMessage("In generateMTRForm::getEnumList. query is " +
                                 query,
                                 tag="TOMs panel")

        cursor = self.dbConn.cursor()
        cursor.execute(query)
        result = cursor.fetchall()

        for value, in result:
            typeList.append(value)

        return typeList

    def getTableList(self, table):
        typeList = [
            '',
        ]

        query = 'SELECT "Description" FROM {}'.format(table)
        QgsMessageLog.logMessage(
            "In generateMTRForm::getTableList. query is " + query,
            tag="TOMs panel")

        cursor = self.dbConn.cursor()
        cursor.execute(query)
        result = cursor.fetchall()

        for value, in result:
            typeList.append(value)

        return typeList
Example #14
0
    def processAlgorithm(self, parameters, context, feedback):
        network = self.parameterAsSource(parameters, self.INPUT, context)
        if network is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUT))

        startPoint = self.parameterAsPoint(parameters, self.START_POINT,
                                           context, network.sourceCrs())
        strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)
        travelCost = self.parameterAsDouble(parameters, self.TRAVEL_COST,
                                            context)

        directionFieldName = self.parameterAsString(parameters,
                                                    self.DIRECTION_FIELD,
                                                    context)
        forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD,
                                              context)
        backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD,
                                               context)
        bothValue = self.parameterAsString(parameters, self.VALUE_BOTH,
                                           context)
        defaultDirection = self.parameterAsEnum(parameters,
                                                self.DEFAULT_DIRECTION,
                                                context)
        speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD,
                                                context)
        defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED,
                                              context)
        tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)

        include_bounds = True  # default to true to maintain 3.0 API
        if self.INCLUDE_BOUNDS in parameters:
            include_bounds = self.parameterAsBool(parameters,
                                                  self.INCLUDE_BOUNDS, context)

        directionField = -1
        if directionFieldName:
            directionField = network.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName:
            speedField = network.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(network, directionField,
                                          forwardValue, backwardValue,
                                          bothValue, defaultDirection)

        distUnit = context.project().crs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(
            distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(network.sourceCrs(), True, tolerance)
        feedback.pushInfo(
            QCoreApplication.translate('ServiceAreaFromPoint',
                                       'Building graph…'))
        snappedPoints = director.makeGraph(builder, [startPoint], feedback)

        feedback.pushInfo(
            QCoreApplication.translate('ServiceAreaFromPoint',
                                       'Calculating service area…'))
        graph = builder.graph()
        idxStart = graph.findVertex(snappedPoints[0])

        tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
        vertices = set()
        points = []
        lines = []

        for vertex, start_vertex_cost in enumerate(cost):
            inbound_edge_index = tree[vertex]
            if inbound_edge_index == -1 and vertex != idxStart:
                # unreachable vertex
                continue

            if start_vertex_cost > travelCost:
                # vertex is too expensive, discard
                continue

            vertices.add(vertex)
            start_point = graph.vertex(vertex).point()

            # find all edges coming from this vertex
            for edge_id in graph.vertex(vertex).outgoingEdges():
                edge = graph.edge(edge_id)
                end_vertex_cost = start_vertex_cost + edge.cost(0)
                end_point = graph.vertex(edge.toVertex()).point()
                if end_vertex_cost <= travelCost:
                    # end vertex is cheap enough to include
                    vertices.add(edge.toVertex())
                    lines.append([start_point, end_point])
                else:
                    # travelCost sits somewhere on this edge, interpolate position
                    interpolated_end_point = QgsGeometryUtils.interpolatePointOnLineByValue(
                        start_point.x(), start_point.y(), start_vertex_cost,
                        end_point.x(), end_point.y(), end_vertex_cost,
                        travelCost)
                    points.append(interpolated_end_point)
                    lines.append([start_point, interpolated_end_point])

        for i in vertices:
            points.append(graph.vertex(i).point())

        feedback.pushInfo(
            QCoreApplication.translate('ServiceAreaFromPoint',
                                       'Writing results…'))

        fields = QgsFields()
        fields.append(QgsField('type', QVariant.String, '', 254, 0))
        fields.append(QgsField('start', QVariant.String, '', 254, 0))

        feat = QgsFeature()
        feat.setFields(fields)

        (point_sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                                     context, fields,
                                                     QgsWkbTypes.MultiPoint,
                                                     network.sourceCrs())

        results = {}

        if point_sink is not None:
            results[self.OUTPUT] = dest_id
            geomPoints = QgsGeometry.fromMultiPointXY(points)
            feat.setGeometry(geomPoints)
            feat['type'] = 'within'
            feat['start'] = startPoint.toString()
            point_sink.addFeature(feat, QgsFeatureSink.FastInsert)

            if include_bounds:
                upperBoundary = []
                lowerBoundary = []

                vertices = []
                for i, v in enumerate(cost):
                    if v > travelCost and tree[i] != -1:
                        vertexId = graph.edge(tree[i]).fromVertex()
                        if cost[vertexId] <= travelCost:
                            vertices.append(i)

                for i in vertices:
                    upperBoundary.append(
                        graph.vertex(graph.edge(tree[i]).toVertex()).point())
                    lowerBoundary.append(
                        graph.vertex(graph.edge(tree[i]).fromVertex()).point())

                geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary)
                geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary)

                feat.setGeometry(geomUpper)
                feat['type'] = 'upper'
                feat['start'] = startPoint.toString()
                point_sink.addFeature(feat, QgsFeatureSink.FastInsert)

                feat.setGeometry(geomLower)
                feat['type'] = 'lower'
                feat['start'] = startPoint.toString()
                point_sink.addFeature(feat, QgsFeatureSink.FastInsert)

        (line_sink,
         line_dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LINES,
                                              context, fields,
                                              QgsWkbTypes.MultiLineString,
                                              network.sourceCrs())
        if line_sink is not None:
            results[self.OUTPUT_LINES] = line_dest_id
            geom_lines = QgsGeometry.fromMultiPolylineXY(lines)
            feat.setGeometry(geom_lines)
            feat['type'] = 'lines'
            feat['start'] = startPoint.toString()
            line_sink.addFeature(feat, QgsFeatureSink.FastInsert)

        return results
Example #15
0
    def processAlgorithm(self, parameters, context, feedback):
        network = self.parameterAsSource(parameters, self.INPUT, context)
        startPoints = self.parameterAsSource(parameters, self.START_POINTS,
                                             context)
        endPoint = self.parameterAsPoint(parameters, self.END_POINT, context)
        strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)

        directionFieldName = self.parameterAsString(parameters,
                                                    self.DIRECTION_FIELD,
                                                    context)
        forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD,
                                              context)
        backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD,
                                               context)
        bothValue = self.parameterAsString(parameters, self.VALUE_BOTH,
                                           context)
        defaultDirection = self.parameterAsEnum(parameters,
                                                self.DEFAULT_DIRECTION,
                                                context)
        speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD,
                                                context)
        defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED,
                                              context)
        tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)

        fields = QgsFields()
        fields.append(QgsField('start', QVariant.String, '', 254, 0))
        fields.append(QgsField('end', QVariant.String, '', 254, 0))
        fields.append(QgsField('cost', QVariant.Double, '', 20, 7))

        feat = QgsFeature()
        feat.setFields(fields)

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, fields,
                                               QgsWkbTypes.LineString,
                                               network.sourceCrs())

        directionField = -1
        if directionFieldName:
            directionField = network.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName:
            speedField = network.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(network, directionField,
                                          forwardValue, backwardValue,
                                          bothValue, defaultDirection)

        distUnit = context.project().crs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(
            distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)
            multiplier = 3600

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(context.project().crs(), True, tolerance)

        feedback.pushInfo(self.tr('Loading start points...'))
        request = QgsFeatureRequest()
        request.setFlags(request.flags()
                         ^ QgsFeatureRequest.SubsetOfAttributes)
        request.setDestinationCrs(network.sourceCrs())
        features = startPoints.getFeatures(request)
        total = 100.0 / startPoints.featureCount() if startPoints.featureCount(
        ) else 0

        points = [endPoint]
        for current, f in enumerate(features):
            if feedback.isCanceled():
                break

            points.append(f.geometry().asPoint())
            feedback.setProgress(int(current * total))

        feedback.pushInfo(self.tr('Building graph...'))
        snappedPoints = director.makeGraph(builder, points, feedback)

        feedback.pushInfo(self.tr('Calculating shortest paths...'))
        graph = builder.graph()

        idxEnd = graph.findVertex(snappedPoints[0])
        route = []

        nPoints = len(snappedPoints)
        total = 100.0 / nPoints if nPoints else 1
        for i in range(1, count + 1):
            if feedback.isCanceled():
                break

            idxStart = graph.findVertex(snappedPoints[i])
            tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)

            if tree[idxEnd] == -1:
                msg = self.tr(
                    'There is no route from start point ({}) to end point ({}).'
                    .format(points[i].toString(), endPoint.toString()))
                feedback.setProgressText(msg)
                QgsMessageLog.logMessage(msg, self.tr('Processing'),
                                         QgsMessageLog.WARNING)
                continue

            cost = 0.0
            current = idxEnd
            while current != idxStart:
                cost += graph.edge(tree[current]).cost(0)
                route.append(
                    graph.vertex(graph.edge(tree[current]).inVertex()).point())
                current = graph.edge(tree[current]).outVertex()

            route.append(snappedPoints[i])
            route.reverse()

            geom = QgsGeometry.fromPolyline(route)
            feat.setGeometry(geom)
            feat['start'] = points[i].toString()
            feat['end'] = endPoint.toString()
            feat['cost'] = cost / multiplier
            sink.addFeature(feat, QgsFeatureSink.FastInsert)

            route[:] = []

            feedback.setProgress(int(i * total))

        return {self.OUTPUT: dest_id}
    def processAlgorithm(self, parameters, context, feedback):
        network = self.parameterAsSource(parameters, self.INPUT, context)
        startPoint = self.parameterAsPoint(parameters, self.START_POINT,
                                           context, network.sourceCrs())
        endPoints = self.parameterAsSource(parameters, self.END_POINTS,
                                           context)
        strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)

        directionFieldName = self.parameterAsString(parameters,
                                                    self.DIRECTION_FIELD,
                                                    context)
        forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD,
                                              context)
        backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD,
                                               context)
        bothValue = self.parameterAsString(parameters, self.VALUE_BOTH,
                                           context)
        defaultDirection = self.parameterAsEnum(parameters,
                                                self.DEFAULT_DIRECTION,
                                                context)
        speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD,
                                                context)
        defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED,
                                              context)
        tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)

        fields = endPoints.fields()
        fields.append(QgsField('start', QVariant.String, '', 254, 0))
        fields.append(QgsField('end', QVariant.String, '', 254, 0))
        fields.append(QgsField('cost', QVariant.Double, '', 20, 7))

        feat = QgsFeature()
        feat.setFields(fields)

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, fields,
                                               QgsWkbTypes.LineString,
                                               network.sourceCrs())

        directionField = -1
        if directionFieldName:
            directionField = network.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName:
            speedField = network.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(network, directionField,
                                          forwardValue, backwardValue,
                                          bothValue, defaultDirection)

        distUnit = context.project().crs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(
            distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)
            multiplier = 3600

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(network.sourceCrs(), True, tolerance)

        feedback.pushInfo(self.tr('Loading end points...'))
        request = QgsFeatureRequest()
        request.setDestinationCrs(network.sourceCrs(),
                                  context.transformContext())
        features = endPoints.getFeatures(request)
        total = 100.0 / endPoints.featureCount() if endPoints.featureCount(
        ) else 0

        points = [startPoint]
        source_attributes = {}
        i = 1
        for current, f in enumerate(features):
            if feedback.isCanceled():
                break

            if not f.hasGeometry():
                continue

            for p in f.geometry().vertices():
                points.append(QgsPointXY(p))
                source_attributes[i] = f.attributes()
                i += 1

            feedback.setProgress(int(current * total))

        feedback.pushInfo(self.tr('Building graph...'))
        snappedPoints = director.makeGraph(builder, points, feedback)

        feedback.pushInfo(self.tr('Calculating shortest paths...'))
        graph = builder.graph()

        idxStart = graph.findVertex(snappedPoints[0])
        tree, costs = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)

        nPoints = len(snappedPoints)
        total = 100.0 / nPoints if nPoints else 1
        for i in range(1, nPoints):
            if feedback.isCanceled():
                break

            idxEnd = graph.findVertex(snappedPoints[i])

            if tree[idxEnd] == -1:
                msg = self.tr(
                    'There is no route from start point ({}) to end point ({}).'
                    .format(startPoint.toString(), points[i].toString()))
                feedback.reportError(msg)
                # add feature with no geometry
                feat.clearGeometry()
                attrs = source_attributes[i]
                attrs.extend([NULL, points[i].toString()])
                feat.setAttributes(attrs)
                sink.addFeature(feat, QgsFeatureSink.FastInsert)
                continue

            route = [graph.vertex(idxEnd).point()]
            cost = costs[idxEnd]
            current = idxEnd
            while current != idxStart:
                current = graph.edge(tree[current]).fromVertex()
                route.append(graph.vertex(current).point())

            route.reverse()

            geom = QgsGeometry.fromPolylineXY(route)
            attrs = source_attributes[i]
            attrs.extend([
                startPoint.toString(), points[i].toString(), cost / multiplier
            ])
            feat.setAttributes(attrs)
            feat.setGeometry(geom)
            sink.addFeature(feat, QgsFeatureSink.FastInsert)

            feedback.setProgress(int(i * total))

        return {self.OUTPUT: dest_id}
Example #17
0
    def processAlgorithm(self, parameters, context, feedback):
        network = self.parameterAsSource(parameters, self.INPUT, context)
        if network is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUT))

        startPoint = self.parameterAsPoint(parameters, self.START_POINT,
                                           context, network.sourceCrs())
        endPoint = self.parameterAsPoint(parameters, self.END_POINT, context,
                                         network.sourceCrs())
        strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)

        directionFieldName = self.parameterAsString(parameters,
                                                    self.DIRECTION_FIELD,
                                                    context)
        forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD,
                                              context)
        backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD,
                                               context)
        bothValue = self.parameterAsString(parameters, self.VALUE_BOTH,
                                           context)
        defaultDirection = self.parameterAsEnum(parameters,
                                                self.DEFAULT_DIRECTION,
                                                context)
        speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD,
                                                context)
        defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED,
                                              context)
        tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)

        fields = QgsFields()
        fields.append(QgsField('start', QVariant.String, '', 254, 0))
        fields.append(QgsField('end', QVariant.String, '', 254, 0))
        fields.append(QgsField('cost', QVariant.Double, '', 20, 7))

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, fields,
                                               QgsWkbTypes.LineString,
                                               network.sourceCrs())
        if sink is None:
            raise QgsProcessingException(
                self.invalidSinkError(parameters, self.OUTPUT))

        directionField = -1
        if directionField:
            directionField = network.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName:
            speedField = network.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(network, directionField,
                                          forwardValue, backwardValue,
                                          bothValue, defaultDirection)

        distUnit = context.project().crs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(
            distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)
            multiplier = 3600

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(network.sourceCrs(), True, tolerance)
        feedback.pushInfo(
            QCoreApplication.translate('ShortestPathPointToPoint',
                                       'Building graph…'))
        snappedPoints = director.makeGraph(builder, [startPoint, endPoint],
                                           feedback)

        feedback.pushInfo(
            QCoreApplication.translate('ShortestPathPointToPoint',
                                       'Calculating shortest path…'))
        graph = builder.graph()
        idxStart = graph.findVertex(snappedPoints[0])
        idxEnd = graph.findVertex(snappedPoints[1])

        tree, costs = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
        if tree[idxEnd] == -1:
            raise QgsProcessingException(
                self.tr('There is no route from start point to end point.'))

        route = [graph.vertex(idxEnd).point()]
        cost = costs[idxEnd]
        current = idxEnd
        while current != idxStart:
            current = graph.edge(tree[current]).fromVertex()
            route.append(graph.vertex(current).point())

        route.reverse()

        feedback.pushInfo(
            QCoreApplication.translate('ShortestPathPointToPoint',
                                       'Writing results…'))
        geom = QgsGeometry.fromPolylineXY(route)
        feat = QgsFeature()
        feat.setFields(fields)
        feat['start'] = startPoint.toString()
        feat['end'] = endPoint.toString()
        feat['cost'] = cost / multiplier
        feat.setGeometry(geom)
        sink.addFeature(feat, QgsFeatureSink.FastInsert)

        results = {}
        results[self.TRAVEL_COST] = cost / multiplier
        results[self.OUTPUT] = dest_id
        return results
Example #18
0
    def processAlgorithm(self, feedback):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_VECTOR))
        startPoints = dataobjects.getObjectFromUri(
            self.getParameterValue(self.START_POINTS))
        strategy = self.getParameterValue(self.STRATEGY)
        travelCost = self.getParameterValue(self.TRAVEL_COST)

        directionFieldName = self.getParameterValue(self.DIRECTION_FIELD)
        forwardValue = self.getParameterValue(self.VALUE_FORWARD)
        backwardValue = self.getParameterValue(self.VALUE_BACKWARD)
        bothValue = self.getParameterValue(self.VALUE_BOTH)
        defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION)
        bothValue = self.getParameterValue(self.VALUE_BOTH)
        defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION)
        speedFieldName = self.getParameterValue(self.SPEED_FIELD)
        defaultSpeed = self.getParameterValue(self.DEFAULT_SPEED)
        tolerance = self.getParameterValue(self.TOLERANCE)

        fields = QgsFields()
        fields.append(QgsField('type', QVariant.String, '', 254, 0))
        fields.append(QgsField('start', QVariant.String, '', 254, 0))

        feat = QgsFeature()
        feat.setFields(fields)

        writerPoints = self.getOutputFromName(
            self.OUTPUT_POINTS).getVectorWriter(
                fields,
                QgsWkbTypes.MultiPoint,
                layer.crs())

        writerPolygons = self.getOutputFromName(
            self.OUTPUT_POLYGON).getVectorWriter(
                fields,
                QgsWkbTypes.Polygon,
                layer.crs())

        directionField = -1
        if directionFieldName is not None:
            directionField = layer.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName is not None:
            speedField = layer.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(layer,
                                          directionField,
                                          forwardValue,
                                          backwardValue,
                                          bothValue,
                                          defaultDirection)

        distUnit = iface.mapCanvas().mapSettings().destinationCrs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField,
                                               defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(iface.mapCanvas().mapSettings().destinationCrs(),
                                  iface.mapCanvas().hasCrsTransformEnabled(),
                                  tolerance)

        feedback.pushInfo(self.tr('Loading start points...'))
        request = QgsFeatureRequest()
        request.setFlags(request.flags() ^ QgsFeatureRequest.SubsetOfAttributes)
        features = vector.features(startPoints, request)
        points = []
        for f in features:
            points.append(f.geometry().asPoint())

        feedback.pushInfo(self.tr('Building graph...'))
        snappedPoints = director.makeGraph(builder, points)

        feedback.pushInfo(self.tr('Calculating service areas...'))
        graph = builder.graph()

        vertices = []
        upperBoundary = []
        lowerBoundary = []
        total = 100.0 / len(snappedPoints)
        for i, p in enumerate(snappedPoints):
            idxStart = graph.findVertex(snappedPoints[i])
            origPoint = points[i].toString()

            tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
            for j, v in enumerate(cost):
                if v > travelCost and tree[j] != -1:
                    vertexId = graph.edge(tree[j]).outVertex()
                    if cost[vertexId] <= travelCost:
                        vertices.append(j)

            for j in vertices:
                upperBoundary.append(graph.vertex(graph.edge(tree[j]).inVertex()).point())
                lowerBoundary.append(graph.vertex(graph.edge(tree[j]).outVertex()).point())

            geomUpper = QgsGeometry.fromMultiPoint(upperBoundary)
            geomLower = QgsGeometry.fromMultiPoint(lowerBoundary)

            feat.setGeometry(geomUpper)
            feat['type'] = 'upper'
            feat['start'] = origPoint
            writerPoints.addFeature(feat)

            feat.setGeometry(geomLower)
            feat['type'] = 'lower'
            feat['start'] = origPoint
            writerPoints.addFeature(feat)

            upperBoundary.append(startPoint)
            lowerBoundary.append(startPoint)
            geomUpper = QgsGeometry.fromMultiPoint(upperBoundary)
            geomLower = QgsGeometry.fromMultiPoint(lowerBoundary)

            geom = geomUpper.convexHull()
            feat.setGeometry(geom)
            feat['type'] = 'upper'
            feat['start'] = origPoint
            writerPolygons.addFeature(feat)

            geom = geomLower.convexHull()
            feat.setGeometry(geom)
            feat['type'] = 'lower'
            feat['start'] = origPoint
            writerPolygons.addFeature(feat)

            vertices[:] = []
            upperBoundary[:] = []
            lowerBoundary[:] = []

            feedback.setProgress(int(i * total))

        del writerPoints
        del writerPolygons
Example #19
0
    def processAlgorithm(self, parameters, context, feedback):
        network = self.parameterAsSource(parameters, self.INPUT, context)
        startPoints = self.parameterAsSource(parameters, self.START_POINTS, context)
        strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)
        travelCost = self.parameterAsDouble(parameters, self.TRAVEL_COST, context)

        directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context)
        forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context)
        backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context)
        bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context)
        defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context)
        speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context)
        defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context)
        tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)

        fields = startPoints.fields()
        fields.append(QgsField('type', QVariant.String, '', 254, 0))
        fields.append(QgsField('start', QVariant.String, '', 254, 0))

        feat = QgsFeature()
        feat.setFields(fields)

        directionField = -1
        if directionFieldName:
            directionField = network.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName:
            speedField = network.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(network,
                                          directionField,
                                          forwardValue,
                                          backwardValue,
                                          bothValue,
                                          defaultDirection)

        distUnit = context.project().crs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField,
                                               defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(network.sourceCrs(),
                                  True,
                                  tolerance)

        feedback.pushInfo(QCoreApplication.translate('ServiceAreaFromLayer', 'Loading start points…'))
        request = QgsFeatureRequest()
        request.setDestinationCrs(network.sourceCrs(), context.transformContext())
        features = startPoints.getFeatures(request)
        total = 100.0 / startPoints.featureCount() if startPoints.featureCount() else 0

        points = []
        source_attributes = {}
        i = 0
        for current, f in enumerate(features):
            if feedback.isCanceled():
                break

            if not f.hasGeometry():
                continue

            for p in f.geometry().vertices():
                points.append(QgsPointXY(p))
                source_attributes[i] = f.attributes()
                i += 1

            feedback.setProgress(int(current * total))

        feedback.pushInfo(QCoreApplication.translate('ServiceAreaFromLayer', 'Building graph…'))
        snappedPoints = director.makeGraph(builder, points, feedback)

        feedback.pushInfo(QCoreApplication.translate('ServiceAreaFromLayer', 'Calculating service areas…'))
        graph = builder.graph()

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               fields, QgsWkbTypes.MultiPoint, network.sourceCrs())

        vertices = []
        upperBoundary = []
        lowerBoundary = []
        total = 100.0 / len(snappedPoints) if snappedPoints else 1
        for i, p in enumerate(snappedPoints):
            if feedback.isCanceled():
                break

            idxStart = graph.findVertex(snappedPoints[i])
            origPoint = points[i].toString()

            tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
            for j, v in enumerate(cost):
                if v > travelCost and tree[j] != -1:
                    vertexId = graph.edge(tree[j]).fromVertex()
                    if cost[vertexId] <= travelCost:
                        vertices.append(j)

            for j in vertices:
                upperBoundary.append(graph.vertex(graph.edge(tree[j]).toVertex()).point())
                lowerBoundary.append(graph.vertex(graph.edge(tree[j]).fromVertex()).point())

            geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary)
            geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary)

            feat.setGeometry(geomUpper)

            attrs = source_attributes[i]
            attrs.extend(['upper', origPoint])
            feat.setAttributes(attrs)
            sink.addFeature(feat, QgsFeatureSink.FastInsert)

            feat.setGeometry(geomLower)
            attrs[-2] = 'lower'
            feat.setAttributes(attrs)
            sink.addFeature(feat, QgsFeatureSink.FastInsert)

            vertices[:] = []
            upperBoundary[:] = []
            lowerBoundary[:] = []

            feedback.setProgress(int(i * total))

        return {self.OUTPUT: dest_id}
Example #20
0
    def processAlgorithm(self, parameters, context, feedback):
        network = self.parameterAsSource(parameters, self.INPUT, context)
        startPoints = self.parameterAsSource(parameters, self.START_POINTS, context)
        strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)
        travelCost = self.parameterAsDouble(parameters, self.TRAVEL_COST, context)

        directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context)
        forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context)
        backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context)
        bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context)
        defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context)
        speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context)
        defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context)
        tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)

        fields = startPoints.fields()
        fields.append(QgsField('type', QVariant.String, '', 254, 0))
        fields.append(QgsField('start', QVariant.String, '', 254, 0))

        feat = QgsFeature()
        feat.setFields(fields)

        directionField = -1
        if directionFieldName:
            directionField = network.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName:
            speedField = network.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(network,
                                          directionField,
                                          forwardValue,
                                          backwardValue,
                                          bothValue,
                                          defaultDirection)

        distUnit = context.project().crs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField,
                                               defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(network.sourceCrs(),
                                  True,
                                  tolerance)

        feedback.pushInfo(self.tr('Loading start points...'))
        request = QgsFeatureRequest()
        request.setDestinationCrs(network.sourceCrs())
        features = startPoints.getFeatures(request)
        total = 100.0 / startPoints.featureCount() if startPoints.featureCount() else 0

        points = []
        source_attributes = {}
        i = 0
        for current, f in enumerate(features):
            if feedback.isCanceled():
                break

            if not f.hasGeometry():
                continue

            for p in f.geometry().vertices():
                points.append(QgsPointXY(p))
                source_attributes[i] = f.attributes()
                i += 1

            feedback.setProgress(int(current * total))

        feedback.pushInfo(self.tr('Building graph...'))
        snappedPoints = director.makeGraph(builder, points, feedback)

        feedback.pushInfo(self.tr('Calculating service areas...'))
        graph = builder.graph()

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               fields, QgsWkbTypes.MultiPoint, network.sourceCrs())

        vertices = []
        upperBoundary = []
        lowerBoundary = []
        total = 100.0 / len(snappedPoints) if snappedPoints else 1
        for i, p in enumerate(snappedPoints):
            if feedback.isCanceled():
                break

            idxStart = graph.findVertex(snappedPoints[i])
            origPoint = points[i].toString()

            tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
            for j, v in enumerate(cost):
                if v > travelCost and tree[j] != -1:
                    vertexId = graph.edge(tree[j]).fromVertex()
                    if cost[vertexId] <= travelCost:
                        vertices.append(j)

            for j in vertices:
                upperBoundary.append(graph.vertex(graph.edge(tree[j]).toVertex()).point())
                lowerBoundary.append(graph.vertex(graph.edge(tree[j]).fromVertex()).point())

            geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary)
            geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary)

            feat.setGeometry(geomUpper)

            attrs = source_attributes[i]
            attrs.extend(['upper', origPoint])
            feat.setAttributes(attrs)
            sink.addFeature(feat, QgsFeatureSink.FastInsert)

            feat.setGeometry(geomLower)
            attrs[-2] = 'lower'
            feat.setAttributes(attrs)
            sink.addFeature(feat, QgsFeatureSink.FastInsert)

            vertices[:] = []
            upperBoundary[:] = []
            lowerBoundary[:] = []

            feedback.setProgress(int(i * total))

        return {self.OUTPUT: dest_id}
    def processAlgorithm(self, feedback):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_VECTOR))
        startPoints = dataobjects.getObjectFromUri(
            self.getParameterValue(self.START_POINTS))
        endPoint = self.getParameterValue(self.END_POINT)
        strategy = self.getParameterValue(self.STRATEGY)

        directionFieldName = self.getParameterValue(self.DIRECTION_FIELD)
        forwardValue = self.getParameterValue(self.VALUE_FORWARD)
        backwardValue = self.getParameterValue(self.VALUE_BACKWARD)
        bothValue = self.getParameterValue(self.VALUE_BOTH)
        defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION)
        bothValue = self.getParameterValue(self.VALUE_BOTH)
        defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION)
        speedFieldName = self.getParameterValue(self.SPEED_FIELD)
        defaultSpeed = self.getParameterValue(self.DEFAULT_SPEED)
        tolerance = self.getParameterValue(self.TOLERANCE)

        fields = QgsFields()
        fields.append(QgsField('start', QVariant.String, '', 254, 0))
        fields.append(QgsField('end', QVariant.String, '', 254, 0))
        fields.append(QgsField('cost', QVariant.Double, '', 20, 7))

        feat = QgsFeature()
        feat.setFields(fields)

        writer = self.getOutputFromName(self.OUTPUT_LAYER).getVectorWriter(
            fields.toList(), QgsWkbTypes.LineString, layer.crs())

        tmp = endPoint.split(',')
        endPoint = QgsPoint(float(tmp[0]), float(tmp[1]))

        directionField = -1
        if directionFieldName is not None:
            directionField = layer.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName is not None:
            speedField = layer.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(layer, directionField, forwardValue,
                                          backwardValue, bothValue,
                                          defaultDirection)

        distUnit = iface.mapCanvas().mapSettings().destinationCrs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(
            distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)
            multiplier = 3600

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(
            iface.mapCanvas().mapSettings().destinationCrs(), True, tolerance)

        feedback.pushInfo(self.tr('Loading start points...'))
        request = QgsFeatureRequest()
        request.setFlags(request.flags()
                         ^ QgsFeatureRequest.SubsetOfAttributes)
        features = vector.features(startPoints, request)
        count = len(features)

        points = [endPoint]
        for f in features:
            points.append(f.geometry().asPoint())

        feedback.pushInfo(self.tr('Building graph...'))
        snappedPoints = director.makeGraph(builder, points)

        feedback.pushInfo(self.tr('Calculating shortest paths...'))
        graph = builder.graph()

        idxEnd = graph.findVertex(snappedPoints[0])
        route = []

        total = 100.0 / count
        for i in range(1, count + 1):
            idxStart = graph.findVertex(snappedPoints[i])
            tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)

            if tree[idxEnd] == -1:
                msg = self.tr(
                    'There is no route from start point ({}) to end point ({}).'
                    .format(points[i].toString(), endPoint.toString()))
                feedback.setProgressText(msg)
                ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, msg)
                continue

            cost = 0.0
            current = idxEnd
            while current != idxStart:
                cost += graph.edge(tree[current]).cost(0)
                route.append(
                    graph.vertex(graph.edge(tree[current]).inVertex()).point())
                current = graph.edge(tree[current]).outVertex()

            route.append(snappedPoints[i])
            route.reverse()

            geom = QgsGeometry.fromPolyline(route)
            feat.setGeometry(geom)
            feat['start'] = points[i].toString()
            feat['end'] = endPoint.toString()
            feat['cost'] = cost / multiplier
            writer.addFeature(feat)

            route[:] = []

            feedback.setProgress(int(i * total))

        del writer
Example #22
0
    def processAlgorithm(self, parameters, context, feedback):
        network = self.parameterAsSource(parameters, self.INPUT, context)
        if network is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

        startPoints = self.parameterAsSource(parameters, self.START_POINTS, context)
        if startPoints is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.START_POINTS))

        endPoint = self.parameterAsPoint(parameters, self.END_POINT, context, network.sourceCrs())
        strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)

        directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context)
        forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context)
        backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context)
        bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context)
        defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context)
        speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context)
        defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context)
        tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)

        fields = startPoints.fields()
        fields.append(QgsField('start', QVariant.String, '', 254, 0))
        fields.append(QgsField('end', QVariant.String, '', 254, 0))
        fields.append(QgsField('cost', QVariant.Double, '', 20, 7))

        feat = QgsFeature()
        feat.setFields(fields)

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               fields, QgsWkbTypes.LineString, network.sourceCrs())
        if sink is None:
            raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))

        directionField = -1
        if directionFieldName:
            directionField = network.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName:
            speedField = network.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(network,
                                          directionField,
                                          forwardValue,
                                          backwardValue,
                                          bothValue,
                                          defaultDirection)

        distUnit = context.project().crs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField,
                                               defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)
            multiplier = 3600

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(network.sourceCrs(),
                                  True,
                                  tolerance)

        feedback.pushInfo(QCoreApplication.translate('ShortestPathLayerToPoint', 'Loading start points…'))
        request = QgsFeatureRequest()
        request.setDestinationCrs(network.sourceCrs(), context.transformContext())
        features = startPoints.getFeatures(request)
        total = 100.0 / startPoints.featureCount() if startPoints.featureCount() else 0

        points = [endPoint]
        source_attributes = {}
        i = 1
        for current, f in enumerate(features):
            if feedback.isCanceled():
                break

            if not f.hasGeometry():
                continue

            for p in f.geometry().vertices():
                points.append(QgsPointXY(p))
                source_attributes[i] = f.attributes()
                i += 1

            feedback.setProgress(int(current * total))

        feedback.pushInfo(QCoreApplication.translate('ShortestPathLayerToPoint', 'Building graph…'))
        snappedPoints = director.makeGraph(builder, points, feedback)

        feedback.pushInfo(QCoreApplication.translate('ShortestPathLayerToPoint', 'Calculating shortest paths…'))
        graph = builder.graph()

        idxEnd = graph.findVertex(snappedPoints[0])

        nPoints = len(snappedPoints)
        total = 100.0 / nPoints if nPoints else 1
        for i in range(1, nPoints):
            if feedback.isCanceled():
                break

            idxStart = graph.findVertex(snappedPoints[i])

            tree, costs = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)

            if tree[idxEnd] == -1:
                msg = self.tr('There is no route from start point ({}) to end point ({}).'.format(points[i].toString(), endPoint.toString()))
                feedback.reportError(msg)
                # add feature with no geometry
                feat.clearGeometry()
                attrs = source_attributes[i]
                attrs.append(points[i].toString())
                feat.setAttributes(attrs)
                sink.addFeature(feat, QgsFeatureSink.FastInsert)
                continue

            route = [graph.vertex(idxEnd).point()]
            cost = costs[idxEnd]
            current = idxEnd
            while current != idxStart:
                current = graph.edge(tree[current]).fromVertex()
                route.append(graph.vertex(current).point())

            route.reverse()

            geom = QgsGeometry.fromPolylineXY(route)
            feat.setGeometry(geom)
            attrs = source_attributes[i]
            attrs.extend([points[i].toString(), endPoint.toString(), cost / multiplier])
            feat.setAttributes(attrs)
            sink.addFeature(feat, QgsFeatureSink.FastInsert)

            feedback.setProgress(int(i * total))

        return {self.OUTPUT: dest_id}
Example #23
0
    def processAlgorithm(self, feedback):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_VECTOR))
        startPoint = self.getParameterValue(self.START_POINT)
        strategy = self.getParameterValue(self.STRATEGY)
        travelCost = self.getParameterValue(self.TRAVEL_COST)

        directionFieldName = self.getParameterValue(self.DIRECTION_FIELD)
        forwardValue = self.getParameterValue(self.VALUE_FORWARD)
        backwardValue = self.getParameterValue(self.VALUE_BACKWARD)
        bothValue = self.getParameterValue(self.VALUE_BOTH)
        defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION)
        bothValue = self.getParameterValue(self.VALUE_BOTH)
        defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION)
        speedFieldName = self.getParameterValue(self.SPEED_FIELD)
        defaultSpeed = self.getParameterValue(self.DEFAULT_SPEED)
        tolerance = self.getParameterValue(self.TOLERANCE)

        tmp = startPoint.split(',')
        startPoint = QgsPoint(float(tmp[0]), float(tmp[1]))

        directionField = -1
        if directionFieldName is not None:
            directionField = layer.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName is not None:
            speedField = layer.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(layer, directionField, forwardValue,
                                          backwardValue, bothValue,
                                          defaultDirection)

        distUnit = iface.mapCanvas().mapSettings().destinationCrs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(
            distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(
            iface.mapCanvas().mapSettings().destinationCrs(), True, tolerance)
        feedback.pushInfo(self.tr('Building graph...'))
        snappedPoints = director.makeGraph(builder, [startPoint])

        feedback.pushInfo(self.tr('Calculating service area...'))
        graph = builder.graph()
        idxStart = graph.findVertex(snappedPoints[0])

        tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
        vertices = []
        for i, v in enumerate(cost):
            if v > travelCost and tree[i] != -1:
                vertexId = graph.edge(tree[i]).outVertex()
                if cost[vertexId] <= travelCost:
                    vertices.append(i)

        upperBoundary = []
        lowerBoundary = []
        for i in vertices:
            upperBoundary.append(
                graph.vertex(graph.edge(tree[i]).inVertex()).point())
            lowerBoundary.append(
                graph.vertex(graph.edge(tree[i]).outVertex()).point())

        feedback.pushInfo(self.tr('Writing results...'))

        fields = QgsFields()
        fields.append(QgsField('type', QVariant.String, '', 254, 0))
        fields.append(QgsField('start', QVariant.String, '', 254, 0))

        feat = QgsFeature()
        feat.setFields(fields)

        geomUpper = QgsGeometry.fromMultiPoint(upperBoundary)
        geomLower = QgsGeometry.fromMultiPoint(lowerBoundary)

        writer = self.getOutputFromName(self.OUTPUT_POINTS).getVectorWriter(
            fields, QgsWkbTypes.MultiPoint, layer.crs())

        feat.setGeometry(geomUpper)
        feat['type'] = 'upper'
        feat['start'] = startPoint.toString()
        writer.addFeature(feat)

        feat.setGeometry(geomLower)
        feat['type'] = 'lower'
        feat['start'] = startPoint.toString()
        writer.addFeature(feat)

        del writer

        upperBoundary.append(startPoint)
        lowerBoundary.append(startPoint)
        geomUpper = QgsGeometry.fromMultiPoint(upperBoundary)
        geomLower = QgsGeometry.fromMultiPoint(lowerBoundary)

        writer = self.getOutputFromName(self.OUTPUT_POLYGON).getVectorWriter(
            fields, QgsWkbTypes.Polygon, layer.crs())

        geom = geomUpper.convexHull()
        feat.setGeometry(geom)
        feat['type'] = 'upper'
        feat['start'] = startPoint.toString()
        writer.addFeature(feat)

        geom = geomLower.convexHull()
        feat.setGeometry(geom)
        feat['type'] = 'lower'
        feat['start'] = startPoint.toString()
        writer.addFeature(feat)
        del writer
Example #24
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_VECTOR))
        startPoint = self.getParameterValue(self.START_POINT)
        endPoints = dataobjects.getObjectFromUri(
            self.getParameterValue(self.END_POINTS))
        strategy = self.getParameterValue(self.STRATEGY)

        directionFieldName = self.getParameterValue(self.DIRECTION_FIELD)
        forwardValue = self.getParameterValue(self.VALUE_FORWARD)
        backwardValue = self.getParameterValue(self.VALUE_BACKWARD)
        bothValue = self.getParameterValue(self.VALUE_BOTH)
        defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION)
        bothValue = self.getParameterValue(self.VALUE_BOTH)
        defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION)
        speedFieldName = self.getParameterValue(self.SPEED_FIELD)
        defaultSpeed = self.getParameterValue(self.DEFAULT_SPEED)
        tolerance = self.getParameterValue(self.TOLERANCE)

        fields = QgsFields()
        fields.append(QgsField('start', QVariant.String, '', 254, 0))
        fields.append(QgsField('end', QVariant.String, '', 254, 0))
        fields.append(QgsField('cost', QVariant.Double, '', 20, 7))

        feat = QgsFeature()
        feat.setFields(fields)

        writer = self.getOutputFromName(
            self.OUTPUT_LAYER).getVectorWriter(
                fields.toList(),
                QgsWkbTypes.LineString,
                layer.crs())

        tmp = startPoint.split(',')
        startPoint = QgsPoint(float(tmp[0]), float(tmp[1]))

        directionField = -1
        if directionFieldName is not None:
            directionField = layer.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName is not None:
            speedField = layer.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(layer,
                                          directionField,
                                          forwardValue,
                                          backwardValue,
                                          bothValue,
                                          defaultDirection)

        distUnit = iface.mapCanvas().mapSettings().destinationCrs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField,
                                               defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)
            multiplier = 3600

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(iface.mapCanvas().mapSettings().destinationCrs(),
                                  iface.mapCanvas().hasCrsTransformEnabled(),
                                  tolerance)

        progress.setInfo(self.tr('Loading end points...'))
        request = QgsFeatureRequest()
        request.setFlags(request.flags() ^ QgsFeatureRequest.SubsetOfAttributes)
        features = vector.features(endPoints, request)
        count = len(features)

        points = [startPoint]
        for f in features:
            points.append(f.geometry().asPoint())

        progress.setInfo(self.tr('Building graph...'))
        snappedPoints = director.makeGraph(builder, points)

        progress.setInfo(self.tr('Calculating shortest paths...'))
        graph = builder.graph()

        idxStart = graph.findVertex(snappedPoints[0])
        tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
        route = []

        total = 100.0 / count
        for i in range(1, count + 1):
            idxEnd = graph.findVertex(snappedPoints[i])

            if tree[idxEnd] == -1:
                msg = self.tr('There is no route from start point ({}) to end point ({}).'.format(startPoint.toString(), points[i].toString()))
                progress.setText(msg)
                ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, msg)
                continue

            cost = 0.0
            current = idxEnd
            while current != idxStart:
                cost += graph.edge(tree[current]).cost(0)
                route.append(graph.vertex(graph.edge(tree[current]).inVertex()).point())
                current = graph.edge(tree[current]).outVertex()

            route.append(snappedPoints[0])
            route.reverse()

            geom = QgsGeometry.fromPolyline(route)
            feat.setGeometry(geom)
            feat['start'] = startPoint.toString()
            feat['end'] = points[i].toString()
            feat['cost'] = cost / multiplier
            writer.addFeature(feat)

            route[:] = []

            progress.setPercentage(int(i * total))

        del writer
Example #25
0
    def processAlgorithm(self, parameters, context, feedback):
        network = self.parameterAsSource(parameters, self.INPUT, context)
        startPoint = self.parameterAsPoint(parameters, self.START_POINT,
                                           context)
        strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)
        travelCost = self.parameterAsDouble(parameters, self.TRAVEL_COST,
                                            context)

        directionFieldName = self.parameterAsString(parameters,
                                                    self.DIRECTION_FIELD,
                                                    context)
        forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD,
                                              context)
        backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD,
                                               context)
        bothValue = self.parameterAsString(parameters, self.VALUE_BOTH,
                                           context)
        defaultDirection = self.parameterAsEnum(parameters,
                                                self.DEFAULT_DIRECTION,
                                                context)
        speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD,
                                                context)
        defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED,
                                              context)
        tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)

        directionField = -1
        if directionFieldName:
            directionField = network.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName:
            speedField = network.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(network, directionField,
                                          forwardValue, backwardValue,
                                          bothValue, defaultDirection)

        distUnit = context.project().crs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(
            distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(context.project().crs(), True, tolerance)
        feedback.pushInfo(self.tr('Building graph...'))
        snappedPoints = director.makeGraph(builder, [startPoint], feedback)

        feedback.pushInfo(self.tr('Calculating service area...'))
        graph = builder.graph()
        idxStart = graph.findVertex(snappedPoints[0])

        tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
        vertices = []
        for i, v in enumerate(cost):
            if v > travelCost and tree[i] != -1:
                vertexId = graph.edge(tree[i]).outVertex()
                if cost[vertexId] <= travelCost:
                    vertices.append(i)

        upperBoundary = []
        lowerBoundary = []
        for i in vertices:
            upperBoundary.append(
                graph.vertex(graph.edge(tree[i]).inVertex()).point())
            lowerBoundary.append(
                graph.vertex(graph.edge(tree[i]).outVertex()).point())

        feedback.pushInfo(self.tr('Writing results...'))

        fields = QgsFields()
        fields.append(QgsField('type', QVariant.String, '', 254, 0))
        fields.append(QgsField('start', QVariant.String, '', 254, 0))

        feat = QgsFeature()
        feat.setFields(fields)

        geomUpper = QgsGeometry.fromMultiPoint(upperBoundary)
        geomLower = QgsGeometry.fromMultiPoint(lowerBoundary)

        (sinkPoints, pointsId) = self.parameterAsSink(parameters,
                                                      self.OUTPUT_POINTS,
                                                      context, fields,
                                                      QgsWkbTypes.MultiPoint,
                                                      network.sourceCrs())

        (sinkPolygon,
         polygonId) = self.parameterAsSink(parameters, self.OUTPUT_POLYGON,
                                           context, fields,
                                           QgsWkbTypes.Polygon,
                                           network.sourceCrs())
        results = {}
        if sinkPoints:
            feat.setGeometry(geomUpper)
            feat['type'] = 'upper'
            feat['start'] = startPoint.toString()
            sinkPoints.addFeature(feat, QgsFeatureSink.FastInsert)

            feat.setGeometry(geomLower)
            feat['type'] = 'lower'
            feat['start'] = startPoint.toString()
            sinkPoints.addFeature(feat, QgsFeatureSink.FastInsert)

            upperBoundary.append(startPoint)
            lowerBoundary.append(startPoint)
            geomUpper = QgsGeometry.fromMultiPoint(upperBoundary)
            geomLower = QgsGeometry.fromMultiPoint(lowerBoundary)

            results[self.OUTPUT_POINTS] = pointsId

        if sinkPolygon:
            geom = geomUpper.convexHull()
            feat.setGeometry(geom)
            feat['type'] = 'upper'
            feat['start'] = startPoint.toString()
            sinkPolygon.addFeature(feat, QgsFeatureSink.FastInsert)

            geom = geomLower.convexHull()
            feat.setGeometry(geom)
            feat['type'] = 'lower'
            feat['start'] = startPoint.toString()
            sinkPolygon.addFeature(feat, QgsFeatureSink.FastInsert)

            results[self.OUTPUT_POLYGON] = polygonId

        return results
Example #26
0
    def processAlgorithm(self, parameters, context, feedback):
        network = self.parameterAsSource(parameters, self.INPUT, context)
        if network is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

        startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs())
        strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)
        travelCost = self.parameterAsDouble(parameters, self.TRAVEL_COST, context)

        directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context)
        forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context)
        backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context)
        bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context)
        defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context)
        speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context)
        defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context)
        tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)

        include_bounds = True # default to true to maintain 3.0 API
        if self.INCLUDE_BOUNDS in parameters:
            include_bounds = self.parameterAsBool(parameters, self.INCLUDE_BOUNDS, context)

        directionField = -1
        if directionFieldName:
            directionField = network.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName:
            speedField = network.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(network,
                                          directionField,
                                          forwardValue,
                                          backwardValue,
                                          bothValue,
                                          defaultDirection)

        distUnit = context.project().crs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField,
                                               defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(network.sourceCrs(),
                                  True,
                                  tolerance)
        feedback.pushInfo(QCoreApplication.translate('ServiceAreaFromPoint', 'Building graph…'))
        snappedPoints = director.makeGraph(builder, [startPoint], feedback)

        feedback.pushInfo(QCoreApplication.translate('ServiceAreaFromPoint', 'Calculating service area…'))
        graph = builder.graph()
        idxStart = graph.findVertex(snappedPoints[0])

        tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
        vertices = set()
        points = []
        lines = []

        for vertex, start_vertex_cost in enumerate(cost):
            inbound_edge_index = tree[vertex]
            if inbound_edge_index == -1 and vertex != idxStart:
                # unreachable vertex
                continue

            if start_vertex_cost > travelCost:
                # vertex is too expensive, discard
                continue

            vertices.add(vertex)
            start_point = graph.vertex(vertex).point()

            # find all edges coming from this vertex
            for edge_id in graph.vertex(vertex).outgoingEdges():
                edge = graph.edge(edge_id)
                end_vertex_cost = start_vertex_cost + edge.cost(0)
                end_point = graph.vertex(edge.toVertex()).point()
                if end_vertex_cost <= travelCost:
                    # end vertex is cheap enough to include
                    vertices.add(edge.toVertex())
                    lines.append([start_point, end_point])
                else:
                    # travelCost sits somewhere on this edge, interpolate position
                    interpolated_end_point = QgsGeometryUtils.interpolatePointOnLineByValue(start_point.x(), start_point.y(), start_vertex_cost,
                                                                                            end_point.x(), end_point.y(), end_vertex_cost, travelCost)
                    points.append(interpolated_end_point)
                    lines.append([start_point, interpolated_end_point])

        for i in vertices:
            points.append(graph.vertex(i).point())

        feedback.pushInfo(QCoreApplication.translate('ServiceAreaFromPoint', 'Writing results…'))

        fields = QgsFields()
        fields.append(QgsField('type', QVariant.String, '', 254, 0))
        fields.append(QgsField('start', QVariant.String, '', 254, 0))

        feat = QgsFeature()
        feat.setFields(fields)

        (point_sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                                     fields, QgsWkbTypes.MultiPoint, network.sourceCrs())

        results = {}

        if point_sink is not None:
            results[self.OUTPUT] = dest_id
            geomPoints = QgsGeometry.fromMultiPointXY(points)
            feat.setGeometry(geomPoints)
            feat['type'] = 'within'
            feat['start'] = startPoint.toString()
            point_sink.addFeature(feat, QgsFeatureSink.FastInsert)

            if include_bounds:
                upperBoundary = []
                lowerBoundary = []

                vertices = []
                for i, v in enumerate(cost):
                    if v > travelCost and tree[i] != -1:
                        vertexId = graph.edge(tree[i]).fromVertex()
                        if cost[vertexId] <= travelCost:
                            vertices.append(i)

                for i in vertices:
                    upperBoundary.append(graph.vertex(graph.edge(tree[i]).toVertex()).point())
                    lowerBoundary.append(graph.vertex(graph.edge(tree[i]).fromVertex()).point())

                geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary)
                geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary)

                feat.setGeometry(geomUpper)
                feat['type'] = 'upper'
                feat['start'] = startPoint.toString()
                point_sink.addFeature(feat, QgsFeatureSink.FastInsert)

                feat.setGeometry(geomLower)
                feat['type'] = 'lower'
                feat['start'] = startPoint.toString()
                point_sink.addFeature(feat, QgsFeatureSink.FastInsert)

        (line_sink, line_dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LINES, context,
                                                         fields, QgsWkbTypes.MultiLineString, network.sourceCrs())
        if line_sink is not None:
            results[self.OUTPUT_LINES] = line_dest_id
            geom_lines = QgsGeometry.fromMultiPolylineXY(lines)
            feat.setGeometry(geom_lines)
            feat['type'] = 'lines'
            feat['start'] = startPoint.toString()
            line_sink.addFeature(feat, QgsFeatureSink.FastInsert)

        return results
# Get index of cost field
network_fields = network.pendingFields()
network_cost_index = network_fields.indexFromName(cost_field)

# Setting up graph build director
director = QgsLineVectorLayerDirector(network, -1, '', '', '', 3)

# Determining cost calculation
if cost_field != 'length':
    properter = CustomCost(network_cost_index, 0.01)
else:
    properter = QgsDistanceArcProperter()

# Creating graph builder
director.addProperter(properter)
builder = QgsGraphBuilder(crs, otf, tolerance, epsg)

# Reading origins and making list of coordinates
graph_origin_points = []

# Loop through the origin points and add graph vertex indices
for index, origin in enumerate(origins):
    graph_origin_points.append(origins[index]['geom'].asPoint())

# Get origin graph vertex index
tied_origin_vertices = director.makeGraph(builder, graph_origin_points)

# Build the graph
graph = builder.graph()

# Create dictionary of origin names and tied origins