Example #1
0
    def processAlgorithm(self, parameters, context: QgsProcessingContext,
                         feedback: QgsProcessingFeedback):
        """Here is where the processing itself takes place."""

        feedback.setProgress(0)

        # init params
        reach_layer = self.parameterAsVectorLayer(parameters, self.REACH_LAYER,
                                                  context)
        wastewater_node_layer = self.parameterAsVectorLayer(
            parameters, self.WASTEWATER_NODE_LAYER, context)
        value_expression = self.parameterAsExpression(parameters,
                                                      self.VALUE_EXPRESSION,
                                                      context)
        reach_pk_name = self.parameterAsFields(parameters, self.REACH_PK_NAME,
                                               context)[0]
        node_pk_name = self.parameterAsFields(parameters, self.NODE_PK_NAME,
                                              context)[0]
        node_from_fk_name = self.parameterAsFields(parameters,
                                                   self.NODE_FROM_FK_NAME,
                                                   context)[0]
        node_to_fk_name = self.parameterAsFields(parameters,
                                                 self.NODE_TO_FK_NAME,
                                                 context)[0]
        branch_behavior = self.parameterAsEnum(parameters,
                                               self.BRANCH_BEHAVIOR, context)
        create_loop_layer = self.parameterAsBool(parameters,
                                                 self.CREATE_LOOP_LAYER,
                                                 context)

        if branch_behavior == 0:
            aggregate_method = lambda values: min(values) if values else 0
        elif branch_behavior == 1:
            aggregate_method = lambda values: max(values) if values else 0
        elif branch_behavior == 2:
            aggregate_method = lambda values: statistics.mean(
                values) if values else 0
        else:
            aggregate_method = lambda values: feedback.pushError(
                'Aggregate method not implemented')

        # create feature sink
        fields = wastewater_node_layer.fields()
        fields.append(QgsField('value', QVariant.Double))
        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, fields,
                                               QgsWkbTypes.Point,
                                               reach_layer.sourceCrs())

        loop_sink = None
        loop_dest_id = None
        if create_loop_layer:
            (loop_sink,
             loop_dest_id) = self.parameterAsSink(parameters, self.LOOP_OUTPUT,
                                                  context, fields,
                                                  QgsWkbTypes.Point,
                                                  reach_layer.sourceCrs())

        if sink is None:
            raise QgsProcessingException(
                self.invalidSinkError(parameters, self.OUTPUT))

        feature_count = reach_layer.featureCount()

        reaches_by_from_node = dict()
        reaches_by_id = dict()

        expression = QgsExpression(value_expression)
        context = QgsExpressionContext(
            QgsExpressionContextUtils.globalProjectLayerScopes(reach_layer))
        expression.prepare(context)

        progress = 0
        feedback.setProgressText(self.tr('Indexing reaches'))
        for reach in reach_layer.getFeatures(QgsFeatureRequest()):
            if reach[node_from_fk_name] == NULL:
                continue

            context.setFeature(reach)
            value = expression.evaluate(context)
            reach_obj = Reach(reach[node_from_fk_name], reach[node_to_fk_name],
                              value, reach.geometry())
            reaches_by_from_node.setdefault(reach_obj.from_id,
                                            []).append(reach_obj)
            reaches_by_id[reach[reach_pk_name]] = reach_obj

            feedback.setProgress(progress / feature_count * 10)
            progress += 1

        loop_nodes = []
        current_feature = 0
        calculated_values = {}

        feedback.setProgressText(self.tr('Analyzing network'))
        for node in wastewater_node_layer.getFeatures():

            from_node_id = node[node_pk_name]

            processed_nodes = []
            times = []
            if from_node_id in reaches_by_from_node.keys():
                for reach in reaches_by_from_node[from_node_id]:
                    times.append(
                        self.calculate_branch(reach, reaches_by_from_node,
                                              reaches_by_id,
                                              list(processed_nodes),
                                              calculated_values,
                                              aggregate_method, loop_nodes,
                                              feedback))

            if times:
                time = aggregate_method(times)
            else:
                time = 0

            current_feature += 1

            calculated_values[node[node_pk_name]] = time
            new_node = QgsFeature(node)
            new_node.setFields(fields)
            new_node.setAttributes(node.attributes() + [time])

            sink.addFeature(new_node, QgsFeatureSink.FastInsert)

            if create_loop_layer and from_node_id in loop_nodes:
                loop_sink.addFeature(node, QgsFeatureSink.FastInsert)

            feedback.setProgress(10 + current_feature / feature_count * 90)

        result = {self.OUTPUT: dest_id}
        if create_loop_layer:
            result[self.LOOP_OUTPUT] = loop_dest_id

        return result