示例#1
0
    def processAlgorithm(self, parameters, context, feedback):

        source = self.parameterAsSource(parameters, self.INPUT, context)

        expressionContext = self.createExpressionContext(
            parameters, context, source)

        x_expression = self.parameterAsString(parameters, self.XEXPRESSION,
                                              context)
        x_expression = QgsExpression(x_expression)

        if x_expression.hasParserError():
            x_expression.prepare(expressionContext)
            raise QgsProcessingException(x_expression.parserErrorString())

        y_expression = self.parameterAsString(parameters, self.YEXPRESSION,
                                              context)
        y_expression = QgsExpression(y_expression)

        if y_expression.hasParserError():
            y_expression.prepare(expressionContext)
            raise QgsProcessingException(y_expression.parserErrorString())

        size = self.parameterAsDouble(parameters, self.SIZE, context)
        size_property = None
        if QgsProcessingParameters.isDynamic(parameters, "SIZE"):
            size_property = parameters["SIZE"]

        color = self.parameterAsColor(parameters, self.COLOR, context)
        color_property = None
        if QgsProcessingParameters.isDynamic(parameters, "COLOR"):
            color_property = parameters["COLOR"]

        facet_row = self.parameterAsString(parameters, self.FACET_ROW, context)
        facet_row_expression = QgsExpression(facet_row)

        if facet_row and facet_row_expression.hasParserError():
            facet_row_expression.prepare(expressionContext)
            raise QgsProcessingException(
                facet_row_expression.parserErrorString())

        facet_col = self.parameterAsString(parameters, self.FACET_COL, context)
        facet_col_expression = QgsExpression(facet_col)

        if facet_col and facet_col_expression.hasParserError():
            facet_col_expression.prepare(expressionContext)
            raise QgsProcessingException(
                facet_col_expression.parserErrorString())

        offline = self.parameterAsBool(parameters, self.OFFLINE, context)
        if offline is not True:
            offline = 'cdn'

        output_html = self.parameterAsFileOutput(parameters,
                                                 self.OUTPUT_HTML_FILE,
                                                 context)

        output_json = self.parameterAsFileOutput(parameters,
                                                 self.OUTPUT_JSON_FILE,
                                                 context)

        colnames = ['x', 'y', 'customdata']
        data = []

        request = QgsFeatureRequest()
        request.setFlags(QgsFeatureRequest.NoGeometry)

        for current, f in enumerate(source.getFeatures(request)):

            tl = []

            expressionContext.setFeature(f)

            x_val = x_expression.evaluate(expressionContext)
            y_val = y_expression.evaluate(expressionContext)
            ids = f.id()

            tl.append(x_val)
            tl.append(y_val)
            tl.append(ids)

            if facet_row:
                facet_row_val = facet_row_expression.evaluate(
                    expressionContext)
                tl.append(facet_row_val)

            if facet_col:
                facet_col_val = facet_col_expression.evaluate(
                    expressionContext)
                tl.append(facet_col_val)

            if size_property:
                the_size, _ = size_property.valueAsDouble(
                    expressionContext, size)
                tl.append(the_size)

            if color_property:
                the_color, _ = color_property.value(expressionContext, color)
                tl.append(the_color)

            data.append(tl)

        if facet_row:
            colnames.append('facet_row')

        if facet_col:
            colnames.append('facet_col')

        if size_property:
            colnames.append('size')

        if color_property:
            colnames.append('color')

        df = pd.DataFrame(data=data, columns=colnames)

        feedback.pushDebugInfo(f'{df}')

        fig = px.scatter(df,
                         x='x',
                         y='y',
                         size='size' if size_property else None,
                         color='color' if color_property else None,
                         facet_row="facet_row" if facet_row else None,
                         facet_col="facet_col" if facet_col else None)

        if size_property is None:
            fig.update_traces(marker_size=size)

        if color_property is None:
            fig.update_traces(marker_color=color.name())

        fig.update_layout(showlegend=True)

        results = {}

        fig.write_html(output_html, include_plotlyjs=offline)
        results[self.OUTPUT_HTML_FILE] = output_html

        if output_json:
            fig.write_json(output_json, pretty=True)
            results[self.OUTPUT_JSON_FILE] = output_json

        return results
示例#2
0
 def testCanEvaluateFunction(self):
     QgsExpression.registerFunction(self.testfun)
     exp = QgsExpression('testfun(1)')
     result = exp.evaluate()
     self.assertEqual('Testing_1', result)
示例#3
0
 def testReferencedColumnsSet(self):
     QgsExpression.registerFunction(self.referenced_columns_set)
     exp = QgsExpression('referenced_columns_set()')
     self.assertEqual(set(exp.referencedColumns()), set(['a', 'b']))
示例#4
0
    def processAlgorithm(self, parameters, context, feedback):
        layer = self.getParameterValue(self.INPUT_LAYER)
        mapping = self.getParameterValue(self.FIELDS_MAPPING)
        output = self.getOutputFromName(self.OUTPUT_LAYER)

        layer = QgsProcessingUtils.mapLayerFromString(layer, context)
        fields = QgsFields()
        expressions = []

        da = QgsDistanceArea()
        da.setSourceCrs(layer.crs())
        da.setEllipsoid(context.project().ellipsoid())

        exp_context = layer.createExpressionContext()

        for field_def in mapping:
            fields.append(
                QgsField(field_def['name'], field_def['type'],
                         field_def['length'], field_def['precision']))

            expression = QgsExpression(field_def['expression'])
            expression.setGeomCalculator(da)
            expression.setDistanceUnits(context.project().distanceUnits())
            expression.setAreaUnits(context.project().areaUnits())
            expression.prepare(exp_context)
            if expression.hasParserError():
                raise GeoAlgorithmExecutionException(
                    self.tr(u'Parser error in expression "{}": {}').format(
                        str(expression.expression()),
                        str(expression.parserErrorString())))
            expressions.append(expression)

        writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs(),
                                        context)

        # Create output vector layer with new attributes
        error_exp = None
        inFeat = QgsFeature()
        outFeat = QgsFeature()
        features = QgsProcessingUtils.getFeatures(layer, context)
        count = QgsProcessingUtils.featureCount(layer, context)
        if count > 0:
            total = 100.0 / count
            for current, inFeat in enumerate(features):
                rownum = current + 1

                geometry = inFeat.geometry()
                outFeat.setGeometry(geometry)

                attrs = []
                for i in range(0, len(mapping)):
                    field_def = mapping[i]
                    expression = expressions[i]
                    exp_context.setFeature(inFeat)
                    exp_context.lastScope().setVariable("row_number", rownum)
                    value = expression.evaluate(exp_context)
                    if expression.hasEvalError():
                        error_exp = expression
                        break

                    attrs.append(value)
                outFeat.setAttributes(attrs)

                writer.addFeature(outFeat, QgsFeatureSink.FastInsert)

                feedback.setProgress(int(current * total))
        else:
            feedback.setProgress(100)

        del writer

        if error_exp is not None:
            raise GeoAlgorithmExecutionException(
                self.tr(u'Evaluation error in expression "{}": {}').format(
                    str(error_exp.expression()),
                    str(error_exp.parserErrorString())))
示例#5
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        if source is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUT))

        strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)
        minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE,
                                             context)

        expression = QgsExpression(
            self.parameterAsString(parameters, self.EXPRESSION, context))
        if expression.hasParserError():
            raise QgsProcessingException(expression.parserErrorString())

        expressionContext = self.createExpressionContext(
            parameters, context, source)
        expression.prepare(expressionContext)

        fields = QgsFields()
        fields.append(QgsField('id', QVariant.Int, '', 10, 0))

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

        da = QgsDistanceArea()
        da.setSourceCrs(source.sourceCrs(), context.transformContext())
        da.setEllipsoid(context.project().ellipsoid())

        total = 100.0 / source.featureCount() if source.featureCount() else 0
        current_progress = 0
        for current, f in enumerate(source.getFeatures()):
            if feedback.isCanceled():
                break

            if not f.hasGeometry():
                continue

            current_progress = total * current
            feedback.setProgress(current_progress)

            expressionContext.setFeature(f)
            value = expression.evaluate(expressionContext)
            if expression.hasEvalError():
                feedback.pushInfo(
                    self.tr('Evaluation error for feature ID {}: {}').format(
                        f.id(), expression.evalErrorString()))
                continue

            fGeom = f.geometry()
            engine = QgsGeometry.createGeometryEngine(fGeom.constGet())
            engine.prepareGeometry()

            bbox = fGeom.boundingBox()
            if strategy == 0:
                pointCount = int(value)
            else:
                pointCount = int(round(value * da.measureArea(fGeom)))

            if pointCount == 0:
                feedback.pushInfo(
                    "Skip feature {} as number of points for it is 0.".format(
                        f.id()))
                continue

            index = QgsSpatialIndex()
            points = dict()

            nPoints = 0
            nIterations = 0
            maxIterations = pointCount * 200
            feature_total = total / pointCount if pointCount else 1

            random.seed()

            while nIterations < maxIterations and nPoints < pointCount:
                if feedback.isCanceled():
                    break

                rx = bbox.xMinimum() + bbox.width() * random.random()
                ry = bbox.yMinimum() + bbox.height() * random.random()

                p = QgsPointXY(rx, ry)
                geom = QgsGeometry.fromPointXY(p)
                if engine.contains(geom.constGet()) and \
                        vector.checkMinDistance(p, index, minDistance, points):
                    f = QgsFeature(nPoints)
                    f.initAttributes(1)
                    f.setFields(fields)
                    f.setAttribute('id', nPoints)
                    f.setGeometry(geom)
                    sink.addFeature(f, QgsFeatureSink.FastInsert)
                    index.insertFeature(f)
                    points[nPoints] = p
                    nPoints += 1
                    feedback.setProgress(current_progress +
                                         int(nPoints * feature_total))
                nIterations += 1

            if nPoints < pointCount:
                feedback.pushInfo(
                    self.tr('Could not generate requested number of random '
                            'points. Maximum number of attempts exceeded.'))

        feedback.setProgress(100)

        return {self.OUTPUT: dest_id}
示例#6
0
    def showExpressionsBuilder(self):
        context = createExpressionContext()
        dlg = QgsExpressionBuilderDialog(None, str(self.leText.text()), self,
                                         'generic', context)

        context.popScope()
        values = self.modelParametersDialog.getAvailableValuesOfType(
            QgsProcessingParameterNumber, QgsProcessingOutputNumber)
        variables = {}
        for value in values:
            if isinstance(value,
                          QgsProcessingModelAlgorithm.ChildParameterSource):
                if value.source(
                ) == QgsProcessingModelAlgorithm.ChildParameterSource.ModelParameter:
                    name = value.parameterName()
                    element = self.modelParametersDialog.model.parameterDefinition(
                        name)
                    desc = element.description()
                elif value.source(
                ) == QgsProcessingModelAlgorithm.ChildParameterSource.ChildOutput:
                    name = "%s_%s" % (value.outputChildId(),
                                      value.outputName())
                    alg = self.modelParametersDialog.model.childAlgorithm(
                        value.outputChildId())
                    out = alg.algorithm().outputDefinition(value.outputName())
                    desc = self.tr("Output '{0}' from algorithm '{1}'").format(
                        out.description(), alg.description())
            variables[name] = desc
        values = self.modelParametersDialog.getAvailableValuesOfType([
            QgsProcessingParameterFeatureSource,
            QgsProcessingParameterRasterLayer
        ], [QgsProcessingOutputVectorLayer, QgsProcessingOutputRasterLayer])
        for value in values:
            if isinstance(value,
                          QgsProcessingModelAlgorithm.ChildParameterSource):
                if value.source(
                ) == QgsProcessingModelAlgorithm.ChildParameterSource.ModelParameter:
                    name = value.parameterName()
                    element = self.modelParametersDialog.model.parameterDefinition(
                        name)
                    desc = element.description()
                elif value.source(
                ) == QgsProcessingModelAlgorithm.ChildParameterSource.ChildOutput:
                    name = "%s_%s" % (value.outputChildId(),
                                      value.outputName())
                    alg = self.modelParametersDialog.model.childAlgorithm(
                        value.outputChildId())
                    out = alg.algorithm().outputDefinition(value.outputName())
                    desc = self.tr("Output '{0}' from algorithm '{1}'").format(
                        out.description(), alg.description())
            variables['%s_minx' %
                      name] = self.tr("Minimum X of {0}").format(desc)
            variables['%s_miny' %
                      name] = self.tr("Minimum Y of {0}").format(desc)
            variables['%s_maxx' %
                      name] = self.tr("Maximum X of {0}").format(desc)
            variables['%s_maxy' %
                      name] = self.tr("Maximum Y of {0}").format(desc)
            if isinstance(element, (QgsProcessingParameterRasterLayer,
                                    QgsProcessingOutputRasterLayer)):
                variables['%s_min' %
                          name] = self.tr("Minimum value of {0}").format(desc)
                variables['%s_max' %
                          name] = self.tr("Maximum value of {0}").format(desc)
                variables['%s_avg' %
                          name] = self.tr("Mean value of {0}").format(desc)
                variables['%s_stddev' % name] = self.tr(
                    "Standard deviation of {0}").format(desc)
        for variable, desc in variables.items():
            dlg.expressionBuilder().registerItem("Modeler",
                                                 variable,
                                                 "@" + variable,
                                                 desc,
                                                 highlightedItem=True)

        dlg.setWindowTitle(self.tr('Expression based input'))
        if dlg.exec_() == QDialog.Accepted:
            exp = QgsExpression(dlg.expressionText())
            if not exp.hasParserError():
                self.setValue(dlg.expressionText())
示例#7
0
    def processAlgorithm(self, progress):
        layer = self.getParameterValue(self.INPUT_LAYER)
        mapping = self.getParameterValue(self.FIELDS_MAPPING)
        output = self.getOutputFromName(self.OUTPUT_LAYER)

        layer = dataobjects.getObjectFromUri(layer)
        provider = layer.dataProvider()
        fields = []
        expressions = []
        for field_def in mapping:
            fields.append(QgsField(name=field_def['name'],
                                   type=field_def['type'],
                                   len=field_def['length'],
                                   prec=field_def['precision']))

            expression = QgsExpression(field_def['expression'])
            if expression.hasParserError():
                raise GeoAlgorithmExecutionException(
                    self.tr(u'Parser error in expression "{}": {}')
                    .format(unicode(field_def['expression']),
                            unicode(expression.parserErrorString())))
            expression.prepare(provider.fields())
            if expression.hasEvalError():
                raise GeoAlgorithmExecutionException(
                    self.tr(u'Evaluation error in expression "{}": {}')
                    .format(unicode(field_def['expression']),
                            unicode(expression.evalErrorString())))
            expressions.append(expression)

        writer = output.getVectorWriter(fields,
                                        provider.geometryType(),
                                        layer.crs())

        # Create output vector layer with new attributes
        error = ''
        calculationSuccess = True
        inFeat = QgsFeature()
        outFeat = QgsFeature()
        features = vector.features(layer)
        count = len(features)
        for current, inFeat in enumerate(features):
            rownum = current + 1

            outFeat.setGeometry(inFeat.geometry())

            attrs = []
            for i in xrange(0, len(mapping)):
                field_def = mapping[i]
                expression = expressions[i]
                expression.setCurrentRowNumber(rownum)
                value = expression.evaluate(inFeat)
                if expression.hasEvalError():
                    calculationSuccess = False
                    error = expression.evalErrorString()
                    break

                attrs.append(value)
            outFeat.setAttributes(attrs)

            writer.addFeature(outFeat)

            current += 1
            progress.setPercentage(100 * current / float(count))

        del writer

        if not calculationSuccess:
            raise GeoAlgorithmExecutionException(
                self.tr('An error occurred while evaluating the calculation'
                        ' string:\n') + error)
示例#8
0
    def evaluate(self, params: Dict[str, str], response: QgsServerResponse,
                 project: QgsProject) -> None:
        """ Evaluate expressions against layer or features
        In parameters:
            LAYER=wms-layer-name
            EXPRESSION=An expression to evaluate
            or
            EXPRESSIONS=["first expression", "second expression"]
            or
            EXPRESSIONS={"key1": "first expression", "key2": "second expression"}
            // optionals
            FEATURE={"type": "Feature", "geometry": {}, "properties": {}}
            or
            FEATURES=[{"type": "Feature", "geometry": {}, "properties": {}}, {"type": "Feature", "geometry": {}, "properties": {}}]
            FORM_SCOPE=boolean to add formScope based on provided features
        """

        layername = params.get('LAYER', '')
        if not layername:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'Evaluate' REQUEST: LAYER parameter is mandatory",
                400)

        # get layer
        layer = findVectorLayer(layername, project)
        # layer not found
        if not layer:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid LAYER parameter for 'Evaluate': {} provided".format(
                    layername), 400)

        # get expressions
        expressions = params.get('EXPRESSIONS', '')
        if not expressions:
            expression = params.get('EXPRESSION', '')
            if not expression:
                raise ExpressionServiceError(
                    "Bad request error",
                    "Invalid 'Evaluate' REQUEST: EXPRESSION or EXPRESSIONS parameter is mandatory",
                    400)
            expressions = '["{}"]'.format(expression)

        # try to load expressions list or dict
        exp_json = None
        try:
            exp_json = json.loads(expressions)
        except Exception:
            QgsMessageLog.logMessage(
                "JSON loads expressions '{}' exception:\n{}".format(
                    expressions, traceback.format_exc()), "lizmap",
                Qgis.Critical)
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'Evaluate' REQUEST: EXPRESSIONS '{}' are not well formed"
                .format(expressions), 400)

        # create expression context
        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(
            QgsExpressionContextUtils.projectScope(project))
        exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer))

        # create distance area context
        da = QgsDistanceArea()
        da.setSourceCrs(layer.crs(), project.transformContext())
        da.setEllipsoid(project.ellipsoid())

        # parse expressions
        exp_map = {}
        exp_parser_errors = []
        exp_items = []
        if isinstance(exp_json, list):
            exp_items = enumerate(exp_json)
        elif isinstance(exp_json, dict):
            exp_items = exp_json.items()
        for k, e in exp_items:
            exp = QgsExpression(e)
            exp.setGeomCalculator(da)
            exp.setDistanceUnits(project.distanceUnits())
            exp.setAreaUnits(project.areaUnits())

            if exp.hasParserError():
                exp_parser_errors.append('Error "{}": {}'.format(
                    e, exp.parserErrorString()))
                continue

            if not exp.isValid():
                exp_parser_errors.append('Expression not valid "{}"'.format(e))
                continue

            exp.prepare(exp_context)
            exp_map[k] = exp

        # expression parser errors found
        if exp_parser_errors:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid EXPRESSIONS for 'Evaluate':\n{}".format(
                    '\n'.join(exp_parser_errors)), 400)

        # get features
        features = params.get('FEATURES', '')
        if not features:
            feature = params.get('FEATURE', '')
            if feature:
                features = '[' + feature + ']'

        # create the body
        body = {
            'status': 'success',
            'results': [],
            'errors': [],
            'features': 0
        }

        # without features just evaluate expression with layer context
        if not features:
            result = {}
            error = {}
            for k, exp in exp_map.items():
                value = exp.evaluate(exp_context)
                if exp.hasEvalError():
                    result[k] = None
                    error[k] = exp.evalErrorString()
                else:
                    result[k] = json.loads(QgsJsonUtils.encodeValue(value))
            body['results'].append(result)
            body['errors'].append(error)
            write_json_response(body, response)
            return

        # Check features
        geojson = []
        try:
            geojson = json.loads(features)
        except Exception:
            QgsMessageLog.logMessage(
                "JSON loads features '{}' exception:\n{}".format(
                    features, traceback.format_exc()), "lizmap", Qgis.Critical)
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'Evaluate' REQUEST: FEATURES '{}' are not well formed"
                .format(features), 400)

        if not geojson or not isinstance(geojson, list) or len(geojson) == 0:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'Evaluate' REQUEST: FEATURES '{}' are not well formed"
                .format(features), 400)

        if ('type' not in geojson[0]) or geojson[0]['type'] != 'Feature':
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'Evaluate' REQUEST: FEATURES '{}' are not well formed: type not defined or not Feature."
                .format(features), 400)

        # try to load features
        # read fields
        feature_fields = QgsJsonUtils.stringToFields(
            '{ "type": "FeatureCollection","features":' + features + '}',
            QTextCodec.codecForName("UTF-8"))
        # read features
        feature_list = QgsJsonUtils.stringToFeatureList(
            '{ "type": "FeatureCollection","features":' + features + '}',
            feature_fields, QTextCodec.codecForName("UTF-8"))

        # features not well formed
        if not feature_list:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid FEATURES for 'Evaluate': not GeoJSON features array provided\n{}"
                .format(features), 400)

        # Extend layer fields with this provided in GeoJSON Features
        feat_fields = QgsFields(layer.fields())
        feat_fields.extend(feature_fields)

        # form scope
        addFormScope = params.get('FORM_SCOPE',
                                  '').lower() in ['true', '1', 't']

        # loop through provided features to evaluate expressions
        for f in feature_list:
            # clone the features with all attributes
            # those defined in layer + fields from GeoJSON Features
            feat = QgsFeature(feat_fields)
            feat.setGeometry(f.geometry())
            for field in f.fields():
                fname = field.name()
                if feat_fields.indexOf(fname) != -1:
                    feat.setAttribute(fname, f[fname])

            # Add form scope to expression context
            if addFormScope:
                exp_context.appendScope(
                    QgsExpressionContextUtils.formScope(feat))

            exp_context.setFeature(feat)
            exp_context.setFields(feat.fields())

            # Evaluate expressions with the new feature
            result = {}
            error = {}
            for k, exp in exp_map.items():
                if addFormScope:  # need to prepare the expression because the context as been updated with a new scope
                    exp.prepare(exp_context)
                value = exp.evaluate(exp_context)
                if exp.hasEvalError():
                    result[k] = None
                    error[k] = exp.evalErrorString()
                else:
                    result[k] = json.loads(QgsJsonUtils.encodeValue(value))
                    error[k] = exp.expression()
            body['results'].append(result)
            body['errors'].append(error)

        write_json_response(body, response)
        return
示例#9
0
    def getFeatureWithFormScope(self, params: Dict[str, str],
                                response: QgsServerResponse,
                                project: QgsProject) -> None:
        """ Get filtered features with a form scope
        In parameters:
            LAYER=wms-layer-name
            FILTER=An expression to filter layer
            FORM_FEATURE={"type": "Feature", "geometry": {}, "properties": {}}
            // optionals
            FIELDS=list of requested field separated by comma
            WITH_GEOMETRY=False
        """
        layername = params.get('LAYER', '')
        if not layername:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'GetFeatureWithFormScope' REQUEST: LAYER parameter is mandatory",
                400)

        # get layer
        layer = findVectorLayer(layername, project)
        # layer not found
        if not layer:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid LAYER parameter for 'VirtualField': {} provided".
                format(layername), 400)

        # get filter
        exp_filter = params.get('FILTER', '')
        if not exp_filter:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'GetFeatureWithFormScope' REQUEST: FILTER parameter is mandatory",
                400)

        # get form feature
        form_feature = params.get('FORM_FEATURE', '')
        if not form_feature:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'GetFeatureWithFormScope' REQUEST: FORM_FEATURE parameter is mandatory",
                400)

        # Check features
        geojson = {}
        try:
            geojson = json.loads(form_feature)
        except Exception:
            QgsMessageLog.logMessage(
                "JSON loads form feature '{}' exception:\n{}".format(
                    form_feature, traceback.format_exc()), "lizmap",
                Qgis.Critical)
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'GetFeatureWithFormScope' REQUEST: FORM_FEATURE '{}' are not well formed"
                .format(form_feature), 400)

        if not geojson or not isinstance(geojson, dict):
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'GetFeatureWithFormScope' REQUEST: FORM_FEATURE '{}' are not well formed"
                .format(form_feature), 400)

        if ('type' not in geojson) or geojson['type'] != 'Feature':
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'GetFeatureWithFormScope' REQUEST: FORM_FEATURE '{}' are not well formed: type not defined or not Feature."
                .format(form_feature), 400)

        # try to load form feature
        # read fields
        form_feature_fields = QgsJsonUtils.stringToFields(
            form_feature, QTextCodec.codecForName("UTF-8"))
        # read features
        form_feature_list = QgsJsonUtils.stringToFeatureList(
            form_feature, form_feature_fields,
            QTextCodec.codecForName("UTF-8"))

        # features not well formed
        if not form_feature_list:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid FORM_FEATURE for 'GetFeatureWithFormScope': not GeoJSON feature provided\n{}"
                .format(form_feature), 400)

        if len(form_feature_list) != 1:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid FORM_FEATURE for 'GetFeatureWithFormScope': not GeoJSON feature provided\n{}"
                .format(form_feature), 400)

        # Get the form feature
        form_feat = form_feature_list[0]

        # create expression context
        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(
            QgsExpressionContextUtils.projectScope(project))
        exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer))
        exp_context.appendScope(QgsExpressionContextUtils.formScope(form_feat))

        # create distance area context
        da = QgsDistanceArea()
        da.setSourceCrs(layer.crs(), project.transformContext())
        da.setEllipsoid(project.ellipsoid())

        # Get filter expression
        exp_f = QgsExpression(exp_filter)
        exp_f.setGeomCalculator(da)
        exp_f.setDistanceUnits(project.distanceUnits())
        exp_f.setAreaUnits(project.areaUnits())

        if exp_f.hasParserError():
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid FILTER for 'GetFeatureWithFormScope': Error \"{}\": {}"
                .format(exp_filter, exp_f.parserErrorString()), 400)

        if not exp_f.isValid():
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid FILTER for 'GetFeatureWithFormScope': Expression not valid \"{}\""
                .format(exp_filter), 400)

        exp_f.prepare(exp_context)

        req = QgsFeatureRequest(exp_f, exp_context)

        # With geometry
        withGeom = params.get('WITH_GEOMETRY',
                              '').lower() in ['true', '1', 't']
        if not withGeom:
            req.setFlags(QgsFeatureRequest.NoGeometry)

        # Fields
        pkAttributes = layer.primaryKeyAttributes()
        attributeList = [i for i in pkAttributes]
        fields = layer.fields()
        r_fields = [
            f.strip() for f in params.get('FIELDS', '').split(',') if f
        ]
        for f in r_fields:
            attributeList.append(fields.indexOf(f))

        # response
        response.setStatusCode(200)
        response.setHeader("Content-Type", "application/json")
        response.write('{ "type": "FeatureCollection","features":[')
        response.flush()

        jsonExporter = QgsJsonExporter(layer)
        if attributeList:
            jsonExporter.setAttributes(attributeList)

        separator = ''
        for feat in layer.getFeatures(req):
            fid = layername + '.' + getServerFid(feat, pkAttributes)
            response.write(separator +
                           jsonExporter.exportFeature(feat, {}, fid))
            response.flush()
            separator = ',\n'
        response.write(']}')
        return
示例#10
0
def execute_in_place_run(alg,
                         active_layer,
                         parameters,
                         context=None,
                         feedback=None,
                         raise_exceptions=False):
    """Executes an algorithm modifying features in-place in the input layer.

    The input layer must be editable or an exception is raised.

    :param alg: algorithm to run
    :type alg: QgsProcessingAlgorithm
    :param active_layer: the editable layer
    :type active_layer: QgsVectoLayer
    :param parameters: parameters of the algorithm
    :type parameters: dict
    :param context: context, defaults to None
    :param context: QgsProcessingContext, optional
    :param feedback: feedback, defaults to None
    :param feedback: QgsProcessingFeedback, optional
    :raises QgsProcessingException: raised when the layer is not editable or the layer cannot be found in the current project
    :return: a tuple with true if success and results
    :rtype: tuple
    """

    if feedback is None:
        feedback = QgsProcessingFeedback()
    if context is None:
        context = dataobjects.createContext(feedback)

    if active_layer is None or not active_layer.isEditable():
        raise QgsProcessingException(
            tr("Layer is not editable or layer is None."))

    if not alg.supportInPlaceEdit(active_layer):
        raise QgsProcessingException(
            tr("Selected algorithm and parameter configuration are not compatible with in-place modifications."
               ))

    parameters['OUTPUT'] = 'memory:'

    try:
        new_feature_ids = []

        active_layer.beginEditCommand(alg.name())

        req = QgsFeatureRequest(QgsExpression(r"$id < 0"))
        req.setFlags(QgsFeatureRequest.NoGeometry)
        req.setSubsetOfAttributes([])

        # Checks whether the algorithm has a processFeature method
        if hasattr(alg, 'processFeature'):  # in-place feature editing
            # Make a clone or it will crash the second time the dialog
            # is opened and run
            alg = alg.create()
            if not alg.prepare(parameters, context, feedback):
                raise QgsProcessingException(
                    tr("Could not prepare selected algorithm."))
            # Check again for compatibility after prepare
            if not alg.supportInPlaceEdit(active_layer):
                raise QgsProcessingException(
                    tr("Selected algorithm and parameter configuration are not compatible with in-place modifications."
                       ))
            field_idxs = range(len(active_layer.fields()))
            feature_iterator = active_layer.getFeatures(
                QgsFeatureRequest(active_layer.selectedFeatureIds())
            ) if parameters[
                'INPUT'].selectedFeaturesOnly else active_layer.getFeatures()
            for f in feature_iterator:
                new_features = alg.processFeature(f, context, feedback)
                new_features = make_features_compatible(
                    new_features, active_layer)
                if len(new_features) == 0:
                    active_layer.deleteFeature(f.id())
                elif len(new_features) == 1:
                    new_f = new_features[0]
                    if not f.geometry().equals(new_f.geometry()):
                        active_layer.changeGeometry(f.id(), new_f.geometry())
                    if f.attributes() != new_f.attributes():
                        active_layer.changeAttributeValues(
                            f.id(), dict(zip(field_idxs, new_f.attributes())),
                            dict(zip(field_idxs, f.attributes())))
                    new_feature_ids.append(f.id())
                else:
                    active_layer.deleteFeature(f.id())
                    # Get the new ids
                    old_ids = set(
                        [f.id() for f in active_layer.getFeatures(req)])
                    if not active_layer.addFeatures(new_features):
                        raise QgsProcessingException(
                            tr("Error adding processed features back into the layer."
                               ))
                    new_ids = set(
                        [f.id() for f in active_layer.getFeatures(req)])
                    new_feature_ids += list(new_ids - old_ids)

            results, ok = {}, True

        else:  # Traditional 'run' with delete and add features cycle
            results, ok = alg.run(parameters, context, feedback)

            if ok:
                result_layer = QgsProcessingUtils.mapLayerFromString(
                    results['OUTPUT'], context)
                # TODO: check if features have changed before delete/add cycle
                active_layer.deleteFeatures(active_layer.selectedFeatureIds())
                new_features = []
                for f in result_layer.getFeatures():
                    new_features.extend(
                        make_features_compatible([f], active_layer))

                # Get the new ids
                old_ids = set([f.id() for f in active_layer.getFeatures(req)])
                if not active_layer.addFeatures(new_features):
                    raise QgsProcessingException(
                        tr("Error adding processed features back into the layer."
                           ))
                new_ids = set([f.id() for f in active_layer.getFeatures(req)])
                new_feature_ids += list(new_ids - old_ids)

        active_layer.endEditCommand()

        if ok and new_feature_ids:
            active_layer.selectByIds(new_feature_ids)
        elif not ok:
            active_layer.rollBack()

        return ok, results

    except QgsProcessingException as e:
        active_layer.endEditCommand()
        active_layer.rollBack()
        if raise_exceptions:
            raise e
        QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing',
                                 Qgis.Critical)
        if feedback is not None:
            feedback.reportError(getattr(e, 'msg', str(e)))

    return False, {}
示例#11
0
文件: defaults.py 项目: FSAS-NUS/Roam
def layer_value(feature, layer, defaultconfig):
    if not canvas:
        roam.utils.warning(
            "No canvas set for using layer_values default function")
        return None
    layers = []
    # layer name can also be a list of layers to search
    layername = defaultconfig['layer']
    if isinstance(layername, basestring):
        layers.append(layername)
    else:
        layers = layername

    expression = defaultconfig['expression']
    field = defaultconfig['field']

    for searchlayer in layers:
        try:
            searchlayer = QgsMapLayerRegistry.instance().mapLayersByName(
                searchlayer)[0]
        except IndexError:
            RoamEvents.raisemessage(
                "Missing layer",
                "Unable to find layer used in widget expression {}".format(
                    searchlayer),
                level=1)
            roam.utils.warning(
                "Unable to find expression layer {}".format(searchlayer))
            return
        if feature.geometry():
            rect = feature.geometry().boundingBox()
            if layer.geometryType() == QGis.Point:
                point = feature.geometry().asPoint()
                rect = QgsRectangle(point.x(), point.y(),
                                    point.x() + 10,
                                    point.y() + 10)

            rect.scale(20)

            rect = canvas.mapRenderer().mapToLayerCoordinates(layer, rect)
            rq = QgsFeatureRequest().setFilterRect(rect)\
                                    .setFlags(QgsFeatureRequest.ExactIntersect)
            features = searchlayer.getFeatures(rq)
        else:
            features = searchlayer.getFeatures()

        exp = QgsExpression(expression)
        exp.prepare(searchlayer.pendingFields())
        if exp.hasParserError():
            error = exp.parserErrorString()
            roam.utils.warning(error)

        for f in features:
            value = exp.evaluate(f)
            if exp.hasEvalError():
                error = exp.evalErrorString()
                roam.utils.warning(error)
            if value:
                return f[field]

    raise DefaultError('No features found')
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        ueberhoehung = self.parameterAsInt(parameters, self.INPUTZFACTOR, context)
        rasterLayer = self.parameterAsRasterLayer(parameters, self.INPUTRASTER, context)
        baseLineLayer = self.parameterAsVectorLayer(parameters, self.INPUTBASELINE, context)
        lineLayer =  self.parameterAsVectorLayer(parameters, self.INPUTINTERSECTIONLAYER, context)
        exprBaselineID = self.parameterAsExpression(parameters, self.SOURCE_BASLINE_ID, context)
        
        outputGeomType = 1 #Output Geometry Type Point

        # Retrieve the feature source and sink. The 'dest_id' variable is used
        # to uniquely identify the feature sink, and must be included in the
        # dictionary returned by the processAlgorithm function.
        fields=lineLayer.fields()
        fields.append( QgsField( "station" ,  QVariant.Double) ) # will be added and filled by Subprocess (algorithm_TransformToProfil_LineIntersection.py)
        fields.append( QgsField( "z_factor" ,  QVariant.Int) ) 
        fields.append( QgsField( "profil_id" ,  QVariant.Int) ) 

        # If source was not found, throw an exception to indicate that the algorithm
        # encountered a fatal error. The exception text can be any string, but in this
        # case we use the pre-built invalidSourceError method to return a standard
        # helper text for when a source cannot be evaluated
        if lineLayer is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUTINTERSECTIONLAYER))

        (sink, dest_id) = self.parameterAsSink(
            parameters,
            self.OUTPUT,
            context,
            fields,
            outputGeomType,
            lineLayer.sourceCrs()
        )
        try:

            # Send some information to the user
            #feedback.pushInfo('CRS is {}'.format(lineLayer.sourceCrs().authid()))

            # If sink was not created, throw an exception to indicate that the algorithm
            # encountered a fatal error. The exception text can be any string, but in this
            # case we use the pre-built invalidSinkError method to return a standard
            # helper text for when a sink cannot be evaluated
            if sink is None:
                raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))

            features=[] #QgsFeatureIterator
            if len( baseLineLayer.selectedFeatures() ) > 0:
                features = baseLineLayer.selectedFeatures()
            else:
                features = [feat for feat in baseLineLayer.getFeatures()]
            feedback.pushInfo( 'Features {} used'.format( len( features ) ) )

            # Compute the number of steps to display within the progress bar and
            # get features from source
            total = 100.0 / len( features ) if len( features ) else 0
            #names = [field.name()+"; " for field in fields]
            #feedback.pushInfo(''.join( names ) )
            #Clear Selection
            baseLineLayer.removeSelection()
            counter=0
            for current, feature in enumerate(features):
                # Stop the algorithm if cancel button has been clicked
                if feedback.isCanceled():
                    break
                
                expr = QgsExpression( exprBaselineID )
                exprContext = QgsExpressionContext()
                exprContext.setFeature(feature)
                
                profilID = expr.evaluate ( exprContext ) #, baseLineLayer.fields() )
                feedback.pushInfo(str(exprBaselineID) + ": Profil-ID: " + str(profilID) )
                #select to current feature
                baseLineLayer.select( feature.id() )
                #create profile feature for selected line 
                #if False:
                #feedback.pushInfo( "Selection " + str( lineLayer.selectedFeatureCount() ) + " Objects"  )
                feedback.pushInfo("Counter: " + str(counter) )
                profil_features = None
                try:
                    profil_features = self.runLineIntersection( lineLayer, baseLineLayer, rasterLayer, ueberhoehung, context, feedback)
                    count=0
                    for grFeature in profil_features:
                        #feedback.pushInfo("Type: " + str(type(grFeature)) )
                        if not str(type(grFeature)) == "<class 'qgis._core.QgsFeature'>":
                            feedback.pushInfo("Abbruch Type: " + str(type(grFeature)) )
                            break
                        feedback.pushInfo("Abbruch Type: " + str( grFeature.attributes() ) )

                        newFeature = QgsFeature( fields )
                        attrs = grFeature.attributes()
                        attrs.append( ueberhoehung )
                        attrs.append( profilID )
                    
                        newFeature.setAttributes( attrs )
                        newFeature.setGeometry( grFeature.geometry() )
                        # Add a feature in the sink
                        sink.addFeature( newFeature, QgsFeatureSink.FastInsert)
                        count=count+1
                    print( "Count: " + str(count) + ' at profile ' + str( profilID ) )
                    feedback.pushInfo("Count: " + str(count) + ' at profile ' + str( profilID ) )
                except Exception as err:
                    print("ERROR at profile " + str( profilID ) + ': '+ str(err.args) + " " + str(repr( err )) + " Fehler: "  )
                    feedback.pushInfo("ERROR at profile " + str( profilID ) + ': '+ str(err.args) + " " + str(repr( err )) + " Fehler: "  )


                #Clear Selection
                baseLineLayer.removeSelection()

                # Update the progress bar
                feedback.setProgress(int(current * total))
                counter=counter+1
        except Exception as err:
            feedback.pushInfo("ERROR: "+ str(err.args) + " " + str(repr( err )) + " Fehler: "  )
        #
        #    print("ERROR:", err.args, repr( err ), "Fehler: " )
        
        
        # To run another Processing algorithm as part of this algorithm, you can use
        # processing.run(...). Make sure you pass the current context and feedback
        # to processing.run to ensure that all temporary layer outputs are available
        # to the executed algorithm, and that the executed algorithm can send feedback
        # reports to the user (and correctly handle cancelation and progress reports!)

        # Return the results of the algorithm. In this case our only result is
        # the feature sink which contains the processed features, but some
        # algorithms may return multiple feature sinks, calculated numeric
        # statistics, etc. These should all be included in the returned
        # dictionary, with keys matching the feature corresponding parameter
        # or output names.
        return {self.OUTPUT: dest_id}
示例#13
0
    def populateByExpression(self, adding=False):
        """
        Populates the panel using an expression
        """
        context = dataobjects.createContext()
        expression_context = context.expressionContext()

        # use the first row parameter values as a preview during expression creation
        params, ok = self.panel.parametersForRow(0, warnOnInvalid=False)
        alg_scope = QgsExpressionContextUtils.processingAlgorithmScope(
            self.panel.alg, params, context)

        # create explicit variables corresponding to every parameter
        for k, v in params.items():
            alg_scope.setVariable(k, v, True)

        # add batchCount in the alg scope to be used in the expressions. 0 is only an example value
        alg_scope.setVariable('row_number', 0, False)

        expression_context.appendScope(alg_scope)

        # mark the parameter variables as highlighted for discoverability
        highlighted_vars = expression_context.highlightedVariables()
        highlighted_vars.extend(list(params.keys()))
        highlighted_vars.append('row_number')
        expression_context.setHighlightedVariables(highlighted_vars)

        dlg = QgsExpressionBuilderDialog(layer=None,
                                         context=context.expressionContext())
        if adding:
            dlg.setExpectedOutputFormat(
                self.tr(
                    'An array of values corresponding to each new row to add'))

        if not dlg.exec_():
            return

        if adding:
            exp = QgsExpression(dlg.expressionText())
            res = exp.evaluate(expression_context)

            if type(res) is not list:
                res = [res]

            first_row = self.panel.batchRowCount(
            ) if self.panel.batchRowCount() > 1 else 0
            self.panel.addRow(len(res))
            self.panel.tblParameters.setUpdatesEnabled(False)
            for row, value in enumerate(res):
                self.setRowValue(row + first_row, value, context)
            self.panel.tblParameters.setUpdatesEnabled(True)
        else:
            self.panel.tblParameters.setUpdatesEnabled(False)
            for row in range(self.panel.batchRowCount()):
                params, ok = self.panel.parametersForRow(row,
                                                         warnOnInvalid=False)

                # remove previous algorithm scope -- we need to rebuild this completely, using the
                # other parameter values from the current row
                expression_context.popScope()
                alg_scope = QgsExpressionContextUtils.processingAlgorithmScope(
                    self.panel.alg, params, context)

                for k, v in params.items():
                    alg_scope.setVariable(k, v, True)

                # add batch row number as evaluable variable in algorithm scope
                alg_scope.setVariable('row_number', row, False)

                expression_context.appendScope(alg_scope)

                # rebuild a new expression every time -- we don't want the expression compiler to replace
                # variables with precompiled values
                exp = QgsExpression(dlg.expressionText())
                value = exp.evaluate(expression_context)
                self.setRowValue(row, value, context)
            self.panel.tblParameters.setUpdatesEnabled(True)
示例#14
0
    def processAlgorithm(self, feedback):
        layer = self.getParameterValue(self.INPUT_LAYER)
        mapping = self.getParameterValue(self.FIELDS_MAPPING)
        output = self.getOutputFromName(self.OUTPUT_LAYER)

        layer = dataobjects.getObjectFromUri(layer)
        fields = []
        expressions = []

        da = QgsDistanceArea()
        da.setSourceCrs(layer.crs().srsid())
        da.setEllipsoidalMode(
            iface.mapCanvas().mapSettings().hasCrsTransformEnabled())
        da.setEllipsoid(QgsProject.instance().readEntry(
            'Measure', '/Ellipsoid', GEO_NONE)[0])

        exp_context = layer.createExpressionContext()

        for field_def in mapping:
            fields.append(
                QgsField(name=field_def['name'],
                         type=field_def['type'],
                         len=field_def['length'],
                         prec=field_def['precision']))

            expression = QgsExpression(field_def['expression'])
            expression.setGeomCalculator(da)
            expression.setDistanceUnits(QgsProject.instance().distanceUnits())
            expression.setAreaUnits(QgsProject.instance().areaUnits())
            expression.prepare(exp_context)
            if expression.hasParserError():
                raise GeoAlgorithmExecutionException(
                    self.tr(u'Parser error in expression "{}": {}').format(
                        unicode(expression.expression()),
                        unicode(expression.parserErrorString())))
            expressions.append(expression)

        writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs())

        # Create output vector layer with new attributes
        error_exp = None
        inFeat = QgsFeature()
        outFeat = QgsFeature()
        features = vector.features(layer)
        total = 100.0 / len(features)
        for current, inFeat in enumerate(features):
            rownum = current + 1

            geometry = inFeat.geometry()
            outFeat.setGeometry(geometry)

            attrs = []
            for i in range(0, len(mapping)):
                field_def = mapping[i]
                expression = expressions[i]
                exp_context.setFeature(inFeat)
                exp_context.lastScope().setVariable("row_number", rownum)
                value = expression.evaluate(exp_context)
                if expression.hasEvalError():
                    error_exp = expression
                    break

                attrs.append(value)
            outFeat.setAttributes(attrs)

            writer.addFeature(outFeat)

            feedback.setProgress(int(current * total))

        del writer

        if error_exp is not None:
            raise GeoAlgorithmExecutionException(
                self.tr(u'Evaluation error in expression "{}": {}').format(
                    unicode(error_exp.expression()),
                    unicode(error_exp.parserErrorString())))
示例#15
0
    def showExpressionsBuilder(self):
        context = self.param.expressionContext()
        dlg = QgsExpressionBuilderDialog(None, str(self.leText.text()), self,
                                         'generic', context)

        context.popScope()
        values = self.modelParametersDialog.getAvailableValuesOfType(
            ParameterNumber, OutputNumber)
        variables = {}
        for value in values:
            if isinstance(value, ValueFromInput):
                name = value.name
                element = self.modelParametersDialog.model.inputs[name].param
                desc = element.description
            else:
                name = "%s_%s" % (value.alg, value.output)
                alg = self.modelParametersDialog.model.algs[value.alg]
                out = alg.algorithm.getOutputFromName(value.output)
                desc = self.tr("Output '{0}' from algorithm '{1}'").format(
                    out.description, alg.description)
            variables[name] = desc
        values = self.modelParametersDialog.getAvailableValuesOfType(
            ParameterVector, OutputVector)
        values.extend(
            self.modelParametersDialog.getAvailableValuesOfType(
                ParameterRaster, OutputRaster))
        for value in values:
            if isinstance(value, ValueFromInput):
                name = value.name
                element = self.modelParametersDialog.model.inputs[name].param
                desc = element.description
            else:
                name = "%s_%s" % (value.alg, value.output)
                alg = self.modelParametersDialog.model.algs[value.alg]
                element = alg.algorithm.getOutputFromName(value.output)
                desc = self.tr("Output '{0}' from algorithm '{1}'").format(
                    element.description, alg.description)
            variables['%s_minx' %
                      name] = self.tr("Minimum X of {0}").format(desc)
            variables['%s_miny' %
                      name] = self.tr("Minimum Y of {0}").format(desc)
            variables['%s_maxx' %
                      name] = self.tr("Maximum X of {0}").format(desc)
            variables['%s_maxy' %
                      name] = self.tr("Maximum Y of {0}").format(desc)
            if isinstance(element, (ParameterRaster, OutputRaster)):
                variables['%s_min' %
                          name] = self.tr("Minimum value of {0}").format(desc)
                variables['%s_max' %
                          name] = self.tr("Maximum value of {0}").format(desc)
                variables['%s_avg' %
                          name] = self.tr("Mean value of {0}").format(desc)
                variables['%s_stddev' % name] = self.tr(
                    "Standard deviation of {0}").format(desc)
        for variable, desc in variables.items():
            dlg.expressionBuilder().registerItem("Modeler",
                                                 variable,
                                                 "@" + variable,
                                                 desc,
                                                 highlightedItem=True)

        dlg.setWindowTitle(self.tr('Expression based input'))
        if dlg.exec_() == QDialog.Accepted:
            exp = QgsExpression(dlg.expressionText())
            if not exp.hasParserError():
                self.setValue(dlg.expressionText())
示例#16
0
    def virtualFields(self, params: Dict[str,
                                         str], response: QgsServerResponse,
                      project: QgsProject) -> None:
        """ Get virtual fields for features
        In parameters:
            LAYER=wms-layer-name
            VIRTUALS={"key1": "first expression", "key2": "second expression"}
            // optionals
            FILTER=An expression to filter layer
            FIELDS=list of requested field separated by comma
            WITH_GEOMETRY=False
        """
        layername = params.get('LAYER', '')
        if not layername:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'VirtualFields' REQUEST: LAYER parameter is mandatory",
                400)

        # get layer
        layer = findVectorLayer(layername, project)
        # layer not found
        if not layer:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid LAYER parameter for 'VirtualFields': {} provided".
                format(layername), 400)

        # get virtuals
        virtuals = params.get('VIRTUALS', '')
        if not virtuals:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'VirtualFields' REQUEST: VIRTUALS parameter is mandatory",
                400)

        # try to load virtuals dict
        vir_json = None
        try:
            vir_json = json.loads(virtuals)
        except Exception:
            QgsMessageLog.logMessage(
                "JSON loads virtuals '{}' exception:\n{}".format(
                    virtuals, traceback.format_exc()), "lizmap", Qgis.Critical)
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'VirtualFields' REQUEST: VIRTUALS '{}' are not well formed"
                .format(virtuals), 400)

        if not isinstance(vir_json, dict):
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'VirtualFields' REQUEST: VIRTUALS '{}' are not well formed"
                .format(virtuals), 400)

        # create expression context
        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(
            QgsExpressionContextUtils.projectScope(project))
        exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer))

        # create distance area context
        da = QgsDistanceArea()
        da.setSourceCrs(layer.crs(), project.transformContext())
        da.setEllipsoid(project.ellipsoid())

        # parse virtuals
        exp_map = {}
        exp_parser_errors = []
        for k, e in vir_json.items():
            exp = QgsExpression(e)
            exp.setGeomCalculator(da)
            exp.setDistanceUnits(project.distanceUnits())
            exp.setAreaUnits(project.areaUnits())

            if exp.hasParserError():
                exp_parser_errors.append('Error "{}": {}'.format(
                    e, exp.parserErrorString()))
                continue

            if not exp.isValid():
                exp_parser_errors.append('Expression not valid "{}"'.format(e))
                continue

            exp.prepare(exp_context)
            exp_map[k] = exp

        # expression parser errors found
        if exp_parser_errors:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid VIRTUALS for 'VirtualFields':\n{}".format(
                    '\n'.join(exp_parser_errors)), 400)

        req = QgsFeatureRequest()

        # get filter
        req_filter = params.get('FILTER', '')
        if req_filter:
            req_exp = QgsExpression(req_filter)
            req_exp.setGeomCalculator(da)
            req_exp.setDistanceUnits(project.distanceUnits())
            req_exp.setAreaUnits(project.areaUnits())

            if req_exp.hasParserError():
                raise ExpressionServiceError(
                    "Bad request error",
                    "Invalid FILTER for 'VirtualFields' Error \"{}\": {}".
                    format(req_filter, req_exp.parserErrorString()), 400)

            if not req_exp.isValid():
                raise ExpressionServiceError(
                    "Bad request error",
                    "Invalid FILTER for 'VirtualFields' Expression not valid \"{}\""
                    .format(req_filter), 400)

            req_exp.prepare(exp_context)
            req = QgsFeatureRequest(req_exp, exp_context)

        # With geometry
        withGeom = params.get('WITH_GEOMETRY',
                              '').lower() in ['true', '1', 't']
        if not withGeom:
            req.setFlags(QgsFeatureRequest.NoGeometry)

        # Fields
        pkAttributes = layer.primaryKeyAttributes()
        attributeList = [i for i in pkAttributes]
        fields = layer.fields()
        r_fields = [
            f.strip() for f in params.get('FIELDS', '').split(',') if f
        ]
        for f in r_fields:
            attributeList.append(fields.indexOf(f))

        # response
        response.setStatusCode(200)
        response.setHeader("Content-Type", "application/json")
        response.write('{ "type": "FeatureCollection","features":[')
        response.flush()

        jsonExporter = QgsJsonExporter(layer)
        if attributeList:
            jsonExporter.setAttributes(attributeList)

        separator = ''
        for feat in layer.getFeatures(req):
            fid = layername + '.' + getServerFid(feat, pkAttributes)

            extra = {}

            # Update context
            exp_context.setFeature(feat)
            exp_context.setFields(feat.fields())

            # Evaluate expressions for virtual fields
            errors = {}
            for k, exp in exp_map.items():
                value = exp.evaluate(exp_context)
                if exp.hasEvalError():
                    extra[k] = None
                    errors[k] = exp.evalErrorString()
                else:
                    extra[k] = json.loads(QgsJsonUtils.encodeValue(value))
                    errors[k] = exp.expression()

            response.write(separator +
                           jsonExporter.exportFeature(feat, extra, fid))
            response.flush()
            separator = ',\n'
        response.write(']}')
        return
示例#17
0
    def __ok(self, withVertex, withPoint):
        """
        To realize the interpolation
        :param withVertex: if we want a new interpolated vertex
        :param withPoint: if we want a new interpolated point
        """
        line_v2, curved = GeometryV2.asLineV2(
            self.__selectedFeature.geometry(), self.__iface)
        vertex_v2 = QgsPointV2()
        vertex_id = QgsVertexId()
        line_v2.closestSegment(QgsPointV2(self.__mapPoint), vertex_v2,
                               vertex_id, 0)

        x0 = line_v2.xAt(vertex_id.vertex - 1)
        y0 = line_v2.yAt(vertex_id.vertex - 1)
        d0 = Finder.sqrDistForCoords(x0, vertex_v2.x(), y0, vertex_v2.y())
        x1 = line_v2.xAt(vertex_id.vertex)
        y1 = line_v2.yAt(vertex_id.vertex)
        d1 = Finder.sqrDistForCoords(x1, vertex_v2.x(), y1, vertex_v2.y())
        z0 = line_v2.zAt(vertex_id.vertex - 1)
        z1 = line_v2.zAt(vertex_id.vertex)
        vertex_v2.addZValue(old_div((d0 * z1 + d1 * z0), (d0 + d1)))

        if withPoint:
            pt_feat = QgsFeature(self.__layer.pendingFields())
            pt_feat.setGeometry(QgsGeometry(vertex_v2))
            for i in range(len(self.__layer.pendingFields())):
                # default = self.__layer.defaultValue(i, pt_feat)
                # if default is not None:
                #     print(pt_feat.fields().at(i).name(), pt_feat.fields().at(i).defaultValueExpression(), default)
                #     print(self.__layer.defaultValueExpression(i), self.__layer.expressionField(i))

                e = QgsExpression(self.__layer.defaultValueExpression(i))
                default = e.evaluate(pt_feat)
                pt_feat.setAttribute(i, default)

            if self.__layer.editFormConfig().suppress(
            ) == QgsEditFormConfig.SuppressOn:
                self.__layer.addFeature(pt_feat)
            else:
                self.__iface.openFeatureForm(self.__layer, pt_feat)

        if withVertex:
            line_v2.insertVertex(vertex_id, vertex_v2)
            self.__lastLayer.changeGeometry(self.__selectedFeature.id(),
                                            QgsGeometry(line_v2))

            found_features = self.__lastLayer.selectedFeatures()
            if len(found_features) > 0:
                if len(found_features) > 1:
                    self.__iface.messageBar().pushMessage(
                        QCoreApplication.translate("VDLTools",
                                                   "One feature at a time"),
                        level=QgsMessageBar.INFO)
                else:
                    self.__selectedFeature = found_features[0]
            else:
                self.__iface.messageBar().pushMessage(
                    QCoreApplication.translate("VDLTools",
                                               "No more feature selected"),
                    level=QgsMessageBar.INFO)

        self.__iface.mapCanvas().refresh()

        self.__done()
        self.__findVertex = True
 def testReferencedAttributeIndexesNonExistingField(self):
     e = QgsExpression()
     e.setExpression("foo = 1")
     self.assertTrue(e.isValid())
     self.assertEqual(len(e.referencedAttributeIndexes(QgsFields())), 0)
示例#19
0
def execute_in_place_run(alg,
                         parameters,
                         context=None,
                         feedback=None,
                         raise_exceptions=False):
    """Executes an algorithm modifying features in-place in the input layer.

    :param alg: algorithm to run
    :type alg: QgsProcessingAlgorithm
    :param parameters: parameters of the algorithm
    :type parameters: dict
    :param context: context, defaults to None
    :type context: QgsProcessingContext, optional
    :param feedback: feedback, defaults to None
    :type feedback: QgsProcessingFeedback, optional
    :param raise_exceptions: useful for testing, if True exceptions are raised, normally exceptions will be forwarded to the feedback
    :type raise_exceptions: boo, default to False
    :raises QgsProcessingException: raised when there is no active layer, or it cannot be made editable
    :return: a tuple with true if success and results
    :rtype: tuple
    """

    if feedback is None:
        feedback = QgsProcessingFeedback()
    if context is None:
        context = dataobjects.createContext(feedback)

    # Only feature based algs have sourceFlags
    try:
        if alg.sourceFlags(
        ) & QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks:
            context.setInvalidGeometryCheck(QgsFeatureRequest.GeometryNoCheck)
    except AttributeError:
        pass

    active_layer = parameters['INPUT']

    # Run some checks and prepare the layer for in-place execution by:
    # - getting the active layer and checking that it is a vector
    # - making the layer editable if it was not already
    # - selecting all features if none was selected
    # - checking in-place support for the active layer/alg/parameters
    # If one of the check fails and raise_exceptions is True an exception
    # is raised, else the execution is aborted and the error reported in
    # the feedback
    try:
        if active_layer is None:
            raise QgsProcessingException(tr("There is not active layer."))

        if not isinstance(active_layer, QgsVectorLayer):
            raise QgsProcessingException(
                tr("Active layer is not a vector layer."))

        if not active_layer.isEditable():
            if not active_layer.startEditing():
                raise QgsProcessingException(
                    tr("Active layer is not editable (and editing could not be turned on)."
                       ))

        if not alg.supportInPlaceEdit(active_layer):
            raise QgsProcessingException(
                tr("Selected algorithm and parameter configuration are not compatible with in-place modifications."
                   ))
    except QgsProcessingException as e:
        if raise_exceptions:
            raise e
        QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing',
                                 Qgis.Critical)
        if feedback is not None:
            feedback.reportError(getattr(e, 'msg', str(e)), fatalError=True)
        return False, {}

    if not active_layer.selectedFeatureIds():
        active_layer.selectAll()

    # Make sure we are working on selected features only
    parameters['INPUT'] = QgsProcessingFeatureSourceDefinition(
        active_layer.id(), True)
    parameters['OUTPUT'] = 'memory:'

    req = QgsFeatureRequest(QgsExpression(r"$id < 0"))
    req.setFlags(QgsFeatureRequest.NoGeometry)
    req.setSubsetOfAttributes([])

    # Start the execution
    # If anything goes wrong and raise_exceptions is True an exception
    # is raised, else the execution is aborted and the error reported in
    # the feedback
    try:
        new_feature_ids = []

        active_layer.beginEditCommand(alg.displayName())

        # Checks whether the algorithm has a processFeature method
        if hasattr(alg, 'processFeature'):  # in-place feature editing
            # Make a clone or it will crash the second time the dialog
            # is opened and run
            alg = alg.create()
            if not alg.prepare(parameters, context, feedback):
                raise QgsProcessingException(
                    tr("Could not prepare selected algorithm."))
            # Check again for compatibility after prepare
            if not alg.supportInPlaceEdit(active_layer):
                raise QgsProcessingException(
                    tr("Selected algorithm and parameter configuration are not compatible with in-place modifications."
                       ))
            field_idxs = range(len(active_layer.fields()))
            iterator_req = QgsFeatureRequest(active_layer.selectedFeatureIds())
            iterator_req.setInvalidGeometryCheck(
                context.invalidGeometryCheck())
            feature_iterator = active_layer.getFeatures(iterator_req)
            step = 100 / len(active_layer.selectedFeatureIds()
                             ) if active_layer.selectedFeatureIds() else 1
            for current, f in enumerate(feature_iterator):
                feedback.setProgress(current * step)
                if feedback.isCanceled():
                    break

                # need a deep copy, because python processFeature implementations may return
                # a shallow copy from processFeature
                input_feature = QgsFeature(f)
                new_features = alg.processFeature(input_feature, context,
                                                  feedback)
                new_features = QgsVectorLayerUtils.makeFeaturesCompatible(
                    new_features, active_layer)

                if len(new_features) == 0:
                    active_layer.deleteFeature(f.id())
                elif len(new_features) == 1:
                    new_f = new_features[0]
                    if not f.geometry().equals(new_f.geometry()):
                        active_layer.changeGeometry(f.id(), new_f.geometry())
                    if f.attributes() != new_f.attributes():
                        active_layer.changeAttributeValues(
                            f.id(), dict(zip(field_idxs, new_f.attributes())),
                            dict(zip(field_idxs, f.attributes())))
                    new_feature_ids.append(f.id())
                else:
                    active_layer.deleteFeature(f.id())
                    # Get the new ids
                    old_ids = set(
                        [f.id() for f in active_layer.getFeatures(req)])
                    if not active_layer.addFeatures(new_features):
                        raise QgsProcessingException(
                            tr("Error adding processed features back into the layer."
                               ))
                    new_ids = set(
                        [f.id() for f in active_layer.getFeatures(req)])
                    new_feature_ids += list(new_ids - old_ids)

            results, ok = {}, True

        else:  # Traditional 'run' with delete and add features cycle

            # There is no way to know if some features have been skipped
            # due to invalid geometries
            if context.invalidGeometryCheck(
            ) == QgsFeatureRequest.GeometrySkipInvalid:
                selected_ids = active_layer.selectedFeatureIds()
            else:
                selected_ids = []

            results, ok = alg.run(parameters, context, feedback)

            if ok:
                result_layer = QgsProcessingUtils.mapLayerFromString(
                    results['OUTPUT'], context)
                # TODO: check if features have changed before delete/add cycle

                new_features = []

                # Check if there are any skipped features
                if context.invalidGeometryCheck(
                ) == QgsFeatureRequest.GeometrySkipInvalid:
                    missing_ids = list(
                        set(selected_ids) - set(result_layer.allFeatureIds()))
                    if missing_ids:
                        for f in active_layer.getFeatures(
                                QgsFeatureRequest(missing_ids)):
                            if not f.geometry().isGeosValid():
                                new_features.append(f)

                active_layer.deleteFeatures(active_layer.selectedFeatureIds())

                for f in result_layer.getFeatures():
                    new_features.extend(
                        QgsVectorLayerUtils.makeFeaturesCompatible(
                            [f], active_layer))

                # Get the new ids
                old_ids = set([f.id() for f in active_layer.getFeatures(req)])
                if not active_layer.addFeatures(new_features):
                    raise QgsProcessingException(
                        tr("Error adding processed features back into the layer."
                           ))
                new_ids = set([f.id() for f in active_layer.getFeatures(req)])
                new_feature_ids += list(new_ids - old_ids)

        active_layer.endEditCommand()

        if ok and new_feature_ids:
            active_layer.selectByIds(new_feature_ids)
        elif not ok:
            active_layer.rollBack()

        return ok, results

    except QgsProcessingException as e:
        active_layer.endEditCommand()
        active_layer.rollBack()
        if raise_exceptions:
            raise e
        QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing',
                                 Qgis.Critical)
        if feedback is not None:
            feedback.reportError(getattr(e, 'msg', str(e)), fatalError=True)

    return False, {}
示例#20
0
def get_igac_basic_query(names, ladm_units):
    required_address_fields = [
        DomainOwnField(names.EXT_ADDRESS_S_ADDRESS_TYPE_F, "Tipo dirección", names.EXT_ADDRESS_TYPE_D),
        OwnField(names.EXT_ADDRESS_S_POSTAL_CODE_F, 'Código postal'),
        EvalExpressionOwnField("Dirección",
                               QgsExpression("""trim(
                                coalesce(get_domain_value_from_code( '{dominio_clase_via_principal}',  "{clase_via_principal}" , False, False)||' ', '') ||
                                coalesce({valor_via_principal} || ' ', '') ||
                                coalesce({letra_via_principal} || ' ', '') ||
                                coalesce(get_domain_value_from_code( '{dominio_sector_ciudad}',  "{sector_ciudad}", False, False)||' ', '') ||
                                coalesce({valor_via_generadora} || ' ', '') ||
                                coalesce({letra_via_generadora} || ' ', '') ||
                                coalesce({numero_predio} || ' ', '') ||
                                coalesce(get_domain_value_from_code( '{dominio_sector_predio}',  "{sector_predio}", False, False)||' ', '') ||
                                coalesce({complemento} || ' ', '') ||
                                coalesce({nombre_predio}, '')
                            )""".format(
                             dominio_clase_via_principal=names.EXT_ADDRESS_TYPE_MAIN_ROAD_CLASS_D,
                             clase_via_principal=names.EXT_ADDRESS_S_MAIN_ROAD_CLASS_F,
                             valor_via_principal=names.EXT_ADDRESS_S_VALUE_MAIN_ROAD_F,
                             letra_via_principal=names.EXT_ADDRESS_S_LETTER_MAIN_ROAD_F,
                             dominio_sector_ciudad=names.EXT_ADDRESS_TYPE_CITY_SECTOR_D,
                             sector_ciudad=names.EXT_ADDRESS_S_CITY_SECTOR_F,
                             valor_via_generadora=names.EXT_ADDRESS_S_VALUE_GENERATOR_ROAD_F,
                             letra_via_generadora=names.EXT_ADDRESS_S_LETTER_GENERATOR_ROAD_F,
                             numero_predio=names.EXT_ADDRESS_S_PARCEL_NUMBER_F,
                             dominio_sector_predio=names.EXT_ADDRESS_TYPE_PARCEL_SECTOR_D,
                             sector_predio=names.EXT_ADDRESS_S_PARCEL_SECTOR_F,
                             complemento=names.EXT_ADDRESS_S_COMPLEMENT_F,
                             nombre_predio=names.EXT_ADDRESS_S_PARCEL_NAME_F)))]

    query = {
        QueryNames.LEVEL_TABLE: {
            QueryNames.LEVEL_TABLE_NAME: names.LC_PLOT_T,
            QueryNames.LEVEL_TABLE_ALIAS: names.LC_PLOT_T,
            QueryNames.FILTER_SUB_LEVEL: FilterSubLevel(names.T_ID_F, names.LC_PLOT_T, names.T_ID_F),
            QueryNames.TABLE_FIELDS: [OwnField(names.LC_PLOT_T_PLOT_AREA_F, get_full_alias("Área", ladm_units, names.LC_PLOT_T, names.LC_PLOT_T_PLOT_AREA_F)),
                                      RelatedOwnFieldObject(names.EXT_ADDRESS_S, names.EXT_ADDRESS_S,
                                                            required_address_fields,
                                                            names.EXT_ADDRESS_S_LC_PLOT_F)],
            QueryNames.LEVEL_TABLE: {
                QueryNames.LEVEL_TABLE_NAME: names.LC_PARCEL_T,
                QueryNames.LEVEL_TABLE_ALIAS: names.LC_PARCEL_T,
                QueryNames.FILTER_SUB_LEVEL: FilterSubLevel(names.COL_UE_BAUNIT_T_PARCEL_F,
                                                            names.COL_UE_BAUNIT_T,
                                                            names.COL_UE_BAUNIT_T_LC_PLOT_F),
                QueryNames.TABLE_FIELDS: [
                    OwnField(names.COL_BAUNIT_T_NAME_F, "Nombre"),
                    OwnField(names.LC_PARCEL_T_DEPARTMENT_F, "Departamento"),
                    OwnField(names.LC_PARCEL_T_MUNICIPALITY_F, "Municipio"),
                    OwnField(names.LC_PARCEL_T_NUPRE_F, "NUPRE"),
                    OwnField(names.LC_PARCEL_T_ID_OPERATION_F, "Id operación"),
                    OwnField(names.LC_PARCEL_T_FMI_F, "FMI"),
                    OwnField(names.LC_PARCEL_T_PARCEL_NUMBER_F, "Número predial"),
                    OwnField(names.LC_PARCEL_T_PREVIOUS_PARCEL_NUMBER_F, "Número predial anterior"),
                    DomainOwnField(names.LC_PARCEL_T_TYPE_F, "Tipo", names.COL_BAUNIT_TYPE_D)
                ],
                QueryNames.LEVEL_TABLE: {
                    QueryNames.LEVEL_TABLE_NAME: names.LC_BUILDING_T,
                    QueryNames.LEVEL_TABLE_ALIAS: names.LC_BUILDING_T,
                    QueryNames.FILTER_SUB_LEVEL: FilterSubLevel(names.COL_UE_BAUNIT_T_LC_BUILDING_F,
                                                                names.COL_UE_BAUNIT_T,
                                                                names.COL_UE_BAUNIT_T_PARCEL_F),
                    QueryNames.TABLE_FIELDS: [
                        OwnField(names.LC_BUILDING_T_BUILDING_AREA_F, "Área"),
                        RelatedOwnFieldObject(names.EXT_ADDRESS_S, names.EXT_ADDRESS_S,
                                              required_address_fields, names.EXT_ADDRESS_S_LC_BUILDING_F)
                    ],
                    QueryNames.LEVEL_TABLE: {
                        QueryNames.LEVEL_TABLE_NAME: names.LC_BUILDING_UNIT_T,
                        QueryNames.LEVEL_TABLE_ALIAS: names.LC_BUILDING_UNIT_T,
                        QueryNames.FILTER_SUB_LEVEL: FilterSubLevel(names.T_ID_F, names.LC_BUILDING_UNIT_T,
                                                                    names.LC_BUILDING_UNIT_T_BUILDING_F),
                        QueryNames.TABLE_FIELDS: [
                            OwnField(names.LC_BUILDING_UNIT_T_TOTAL_FLOORS_F, "Número de pisos"),
                            OwnField(names.LC_BUILDING_UNIT_T_TOTAL_ROOMS_F, "Número de habitaciones"),
                            OwnField(names.LC_BUILDING_UNIT_T_TOTAL_BATHROOMS_F, "Número de baños"),
                            OwnField(names.LC_BUILDING_UNIT_T_TOTAL_LOCALS_F, "Número de locales"),
                            DomainOwnField(names.LC_BUILDING_UNIT_T_BUILDING_TYPE_F, "Tipo construcción",
                                           names.LC_BUILDING_TYPE_D),
                            DomainOwnField(names.LC_BUILDING_UNIT_T_BUILDING_UNIT_TYPE_F,
                                           "Tipo unidad de construcción", names.LC_BUILDING_UNIT_TYPE_D),
                            DomainOwnField(names.LC_BUILDING_UNIT_T_FLOOR_TYPE_F, "Tipo de planta",
                                           names.LC_BUILDING_FLOOR_TYPE_D),
                            DomainOwnField(names.LC_BUILDING_UNIT_T_DOMAIN_TYPE_F, "Tipo dominio",
                                           names.LC_DOMAIN_BUILDING_TYPE_D),
                            OwnField(names.LC_BUILDING_UNIT_T_FLOOR_F, "Ubicación en el piso"),
                            OwnField(names.LC_BUILDING_UNIT_T_BUILT_AREA_F, get_full_alias("Área construida", ladm_units, names.LC_BUILDING_UNIT_T, names.LC_BUILDING_UNIT_T_BUILT_AREA_F)),
                            DomainOwnField(names.LC_BUILDING_UNIT_T_USE_F, "Uso",
                                           names.LC_BUILDING_UNIT_USE_D),
                            RelatedOwnFieldObject(names.EXT_ADDRESS_S, names.EXT_ADDRESS_S,
                                                  required_address_fields, names.EXT_ADDRESS_S_LC_BUILDING_UNIT_F)
                        ]
                    }
                }
            }
        }
    }

    return query
示例#21
0
    def responseComplete(self):
        '''
        Send new response
        '''
        self.handler = self.serverIface.requestHandler()
        params = self.handler.parameterMap( )

        # Check if needed params are passed
        # If not, do not change QGIS Server response
        if params['SERVICE'].lower() != 'wms':
            return

        # Check if getprintatlas request. If not, just send the response
        if 'REQUEST' not in params or params['REQUEST'].lower() not in ['getprintatlas', 'getcapabilitiesatlas']:
            return

        # Get capabilities
        if params['REQUEST'].lower() == 'getcapabilitiesatlas':
            body = {
                'status': 'success',
                'metadata': self.metadata
            }
            self.setJsonResponse( '200', body)
            return

        # Check if needed params are set
        if 'TEMPLATE' not in params or 'FORMAT' not in params or 'DPI' not in params or 'MAP' not in params or 'EXP_FILTER' not in params:
            body = {
                'status': 'fail',
                'message': 'Missing parameters: TEMPLATE, FORMAT, DPI, MAP, EXP_FILTER are required '
            }
            self.setJsonResponse( '200', body)
            return


        self.project_path = self.serverInterface().configFilePath()
        self.composer_name = params['TEMPLATE']
        self.feature_filter = params['EXP_FILTER']

        # check expression
        qExp = QgsExpression(self.feature_filter)
        if not qExp.hasParserError():
            qReq = QgsFeatureRequest(qExp)
            qReq.setLimit(1)
            ok = True
        else:
            body = {
                'status': 'fail',
                'message': 'An error occured while parsing the given expression: %s' % qExp.parserErrorString()
            }
            syslog.syslog(syslog.LOG_ERR, "ATLAS - ERROR EXPRESSION: %s" % qExp.parserErrorString())
            self.setJsonResponse( '200', body)
            return

        try:
            pdf = self.print_atlas(
                project_path=self.project_path,
                composer_name=self.composer_name,
                predefined_scales=self.predefined_scales,
                feature_filter=self.feature_filter
            )
        except:
            pdf = None

        if not pdf:
            body = {
                'status': 'fail',
                'message': 'ATLAS - Error while generating the PDF'
            }
            QgsMessageLog.logMessage("ATLAS - No PDF generated in %s" % pdf, 'atlasprint', Qgis.Info)
            self.setJsonResponse( '200', body)
            return

        # Send PDF
        self.handler.clear()
        self.handler.setResponseHeader('Content-type', 'application/pdf')
        self.handler.setResponseHeader('Status', '200')
        try:
            with open(pdf, 'rb') as f:
                loads = f.readlines()
                ba = QByteArray(b''.join(loads))
                self.handler.appendBody(ba)
        except:
            body = {
                'status': 'fail',
                'message': 'Error occured while reading PDF file',
            }
            self.setJsonResponse( '200', body)
        finally:
            os.remove(pdf)

        return
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        ueberhoehung = self.parameterAsDouble(parameters, self.INPUTZFACTOR,
                                              context)
        baseLineLayer = self.parameterAsVectorLayer(parameters,
                                                    self.INPUTBASELINE,
                                                    context)
        vectorLayer = self.parameterAsVectorLayer(parameters,
                                                  self.INPUTVECTORLAYER,
                                                  context)
        baselineIDFieldName = self.parameterAsExpression(
            parameters, self.PROFIL_BASELINE_ID, context)
        offsetFieldName = self.parameterAsString(parameters, self.OFFSETFIELD,
                                                 context)
        vectorLayerBaselineIDFieldName = self.parameterAsExpression(
            parameters, self.INPUTVECTORLAYER_BASLINE_ID, context)

        outputGeomType = vectorLayer.wkbType()  #Output Geometry Type Point

        offsetExpr = QgsExpression(offsetFieldName)
        if offsetExpr.hasParserError():
            feedback.reportError("Offset Expression failed: " +
                                 offsetExpr.parserErrorString())
            offsetExpr = "0"

        # Retrieve the feature source and sink. The 'dest_id' variable is used
        # to uniquely identify the feature sink, and must be included in the
        # dictionary returned by the processAlgorithm function.
        fields = vectorLayer.fields()
        #fields.append( QgsField( "station" ,  QVariant.Double ) ) # will be added and filled by Subprocess (algorithm_TransformToProfil_LineIntersection.py)
        #.append( QgsField( "abstand" ,  QVariant.Double ) ) # will be added and filled by Subprocess (algorithm_TransformToProfil_LineIntersection.py)
        #fields.append( QgsField( "z_factor" ,  QVariant.Int ) )   # will be added and filled by Subprocess (algorithm_TransformToProfil_LineIntersection.py)
        #fields.append( QgsField( "profil_id" ,  QVariant.Int ) )

        if vectorLayer is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUTVECTORLAYER))
        if vectorLayer is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.OUTPUT))

        #check if vectorlayer has Features
        if vectorLayer.featureCount() == 0:
            msg = self.tr("Error: Layer ", vectorLayer.name(), "is emty! ")
            feedback.reportError(msg)
            raise QgsProcessingException(msg)

        #check if baselineLayer has Features
        if baseLineLayer.featureCount() == 0:
            msg = self.tr("Error: Layer ", baseLineLayer.name(), "is emty! ")
            feedback.reportError(msg)
            raise QgsProcessingException(msg)

        #take CRS from Project
        crsProject = QgsProject.instance().crs()

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, fields, outputGeomType,
                                               vectorLayer.sourceCrs())

        # If sink was not created, throw an exception to indicate that the algorithm
        # encountered a fatal error. The exception text can be any string, but in this
        # case we use the pre-built invalidSinkError method to return a standard
        # helper text for when a sink cannot be evaluated
        if sink is None:
            raise QgsProcessingException(
                self.invalidSinkError(parameters, self.OUTPUT))

        offsetExprContext = QgsExpressionContext()
        # Send some information to the user
        #feedback.pushInfo('CRS is {}'.format(vectorLayer.sourceCrs().authid()))

        features = []  #QgsFeatureIterator
        if len(vectorLayer.selectedFeatures()) > 0:
            features = vectorLayer.selectedFeatures()
        else:
            features = [feat for feat in vectorLayer.getFeatures()]
        feedback.pushInfo('Features {} used'.format(len(features)))

        # Compute the number of steps to display within the progress bar and
        # get features from source
        total = 100.0 / len(features) if len(features) else 0
        #names = [field.name()+"; " for field in fields]
        #feedback.pushInfo(''.join( names ) )
        #Clear Selection
        vectorLayer.removeSelection()
        i = 0
        for current, feature in enumerate(features):

            try:

                # Stop the algorithm if cancel button has been clicked
                if feedback.isCanceled():
                    break

                # Offset
                abstand = 0
                offsetExprContext.setFeature(feature)
                try:
                    abstand = offsetExpr.evaluate(offsetExprContext)
                except:
                    msg = self.tr(
                        "Error while calculating Offset from Expression. Feature "
                        + str(feat.attributes()))
                    feedback.reportError(msg)
                    raise QgsProcessingException(msg)
                try:
                    #check for numeric Expression Data type
                    a = int(abstand)
                    b = float(abstand)
                except:
                    msg = self.tr(
                        "Feature(" + feature.id() + "): " +
                        "Error Offset Experession result must be numeric, not "
                        + str(type(abstand)))
                    feedback.reportError(msg)
                    raise QgsProcessingException(msg)

                # get Profile Baseline by ID

                #profil_id of the profile feature
                expr = QgsExpression(vectorLayerBaselineIDFieldName)
                exprContext = QgsExpressionContext()
                exprContext.setFeature(feature)
                profil_id = expr.evaluate(exprContext)

                # baseline ID
                exprBaseLineID = QgsExpression(baselineIDFieldName)

                # remove quotes ""
                if baselineIDFieldName.startswith('\"'):
                    baselineIDFieldName = baselineIDFieldName.replace('\"', '')

                exprText = baselineIDFieldName + '=' + str(profil_id)
                #feedback.pushInfo('waehle Basislinie: ' + exprText )
                exprBaseLine = QgsExpression(exprText)

                selection = baseLineLayer.getFeatures(
                    QgsFeatureRequest(exprBaseLine))

                baseLineFeature = next(selection)
                linRef = LinearReferencingMaschine(baseLineFeature.geometry(),
                                                   crsProject, feedback)

                #feedback.pushInfo("Profil_id: " + str( profil_id ) + ' feature: ' + str( feature.attributes() ) )
                geom = feature.geometry()

                feedback.pushInfo("srcgeom: " + str(geom.asWkt()))

                subFeatureList = []

                layerUtils = LayerUtils(crsProject, feedback)
                subFeatureList = layerUtils.multiPartToSinglePartFeature(
                    feature)
                feedback.pushInfo("subFeatureList: " +
                                  str(len(subFeatureList)))

                #preparation of profile geometrys
                prepSubFeatureList = []
                for iP, f in enumerate(subFeatureList):
                    if linRef.isSimpleLine or vectorLayer.geometryType(
                    ) == 0 or vectorLayer.geometryType(
                    ) == 1:  #Point (Line nur temporär):
                        prepSubFeatureList.append(f)  #keep old feature
                    else:
                        # Basisline hat Knickpunkte, Profilgeometrien müssen ggf. mit zusätzlichen Stützpunkten gefüllt werden
                        # Baseline has breakpoints, we have to fill the profile geometrys with additional vertices
                        filledSingleGeom = None
                        if vectorLayer.geometryType() == 2:  #Polygon
                            filledSingleGeomList = self.fillPolygonVertices(
                                f.geometry(), linRef, crsProject, feedback)
                        #elif vectorLayer.geometryType() == 1: #Line

                        if len(filledSingleGeomList) > 0:
                            for g in filledSingleGeomList:
                                #create a feature for each filled sub geometry
                                filledFeature = QgsFeature(f)
                                filledFeature.setGeometry(g)
                                filledFeature.setAttributes(f.attributes())
                                prepSubFeatureList.append(filledFeature)
                        else:
                            prepSubFeatureList.append(f)  #keep old feature
                            feedback.reportError(
                                "Feature geometry can not be filled: " +
                                str(f.attributes()))

                feedback.pushInfo("prepSubFeatureList: " +
                                  str(len(prepSubFeatureList)))

                #Back to Real World Transformation for each sub Feature
                realWorldSubFeatureList = []
                for pFeat in prepSubFeatureList:

                    #Create Real World geometry with LinearReferencingMaschine
                    realWorldFeat = linRef.transformProfileFeatureToRealWorld(
                        pFeat, vectorLayer.crs(), feedback, abstand,
                        ueberhoehung)
                    realWorldSubFeatureList.append(realWorldFeat)
                    feedback.pushInfo(str(realWorldFeat.geometry().asWkt()))

                ##### ggf features könnten hier wieder gruppiert werden ######

                #write real worl Features to output layer
                for rwFeat in realWorldSubFeatureList:
                    sink.addFeature(rwFeat, QgsFeatureSink.FastInsert)

                i = i + 1
                # Update the progress bar
                feedback.setProgress(int(i * total))

            except:
                msg = self.tr("Error on Feature " + str(i) + " " +
                              str(feature.attributes()))
                feedback.reportError(msg)
                raise QgsProcessingException(msg)

        msgInfo = self.tr(
            str(i) + " Features were transformed to real world coordinates")
        feedback.pushInfo(msgInfo)
        # Return the results of the algorithm. In this case our only result is
        return {self.OUTPUT: dest_id}
        #
        #    print("ERROR:", err.args, repr( err ), "Fehler: " )

        # To run another Processing algorithm as part of this algorithm, you can use
        # processing.run(...). Make sure you pass the current context and feedback
        # to processing.run to ensure that all temporary layer outputs are available
        # to the executed algorithm, and that the executed algorithm can send feedback
        # reports to the user (and correctly handle cancelation and progress reports!)

        # Return the results of the algorithm. In this case our only result is
        # the feature sink which contains the processed features, but some
        # algorithms may return multiple feature sinks, calculated numeric
        # statistics, etc. These should all be included in the returned
        # dictionary, with keys matching the feature corresponding parameter
        # or output names.
        feedback.pushInfo(str(counter) + " Profile Baslines processed")

        return {self.OUTPUT: dest_id}
示例#23
0
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        sourceL = self.parameterAsSource(parameters, self.INPUT_L, context)

        sourceF = self.parameterAsMatrix(parameters, self.INPUT_F, context)

        filtro = self.parameterAsString(parameters, self.GROUP_BY, context)

        titolo = self.parameterAsString(parameters, self.INPUT_T, context)

        html = self.parameterAsFileOutput(parameters, self.OUTPUT, context)

        source_path = self.parameterAsString(parameters, self.INPUT_L, context)

        f_base = self.parameterAsString(parameters, self.INPUT_D, context)

        icona = self.parameterAsString(parameters, self.INPUT_I, context)

        fogliocss = self.parameterAsString(parameters, self.INPUT_S, context)

        rel_path = self.parameterAsBool(parameters, self.INPUT_ABS, context)

        #FASE #01 - cerco la path del progetto
        if QgsProject.instance().homePath():
            path_proj = QgsProject.instance().homePath()
            #windowizzo la path quale che sia
            path_proj = str(Path(path_proj))
            #rimuovo geopakage: se presente
            path_proj = path_proj.replace('geopackage:', '')
            #print('path proj ', path_proj)
        else:
            feedback.reportError(
                'WARNING NO PROJECT PATH: the html file may not work correctly\n'
            )
            #print('***** no project path')
            path_proj = ''
        #tolgo %20 e metto spazio
        path_proj = path_proj.replace('%20', ' ')

        #FASE #02 - cerco la path del file di input
        path_file = (self.parameterDefinition('INPUT_L').valueAsPythonString(
            parameters['INPUT_L'], context))
        path_file = path_file[1:path_file.rfind('/') + 1]
        if 'memory' in path_file:
            file_mem = True
            path_file = ''
            #print('temporary file')
        else:
            file_mem = False
            #windowizzo la path quale che sia
            path_file = str(Path(path_file))
            #print('file path ', path_file)
        #tolgo %20 e metto spazio
        path_file = path_file.replace('%20', ' ')

        #FASE #03 - scelgo la path da usare tra le due: prioritaria quella di progetto
        if path_proj:
            path_dir = path_proj
            if path_proj not in path_file and path_file != '':
                feedback.reportError('WARNING PATH FILE ' + path_file)
                feedback.reportError('OUTSIDE PROJECT PATH ' + path_proj)
                feedback.reportError('MOST LIKELY IT WON' 'T WORK' + '\n')
            elif path_file == '':
                feedback.reportError('WARNING TEMPORARY LAYER WITHOUT PATH\n')
        else:
            path_dir = path_file
            if path_dir:
                feedback.reportError(
                    'WARNING use the path of the input file ' + path_dir +
                    '\n')
            else:
                feedback.reportError('WARNING TEMPORARY LAYER WITHOUT PATH\n')

        #FASE #04 - controllo se si sta salvando file con percorsi relativi nella cartella di progetto
        if path_dir not in str(Path(html)) and 'processing' not in str(
                Path(html)):
            #print('html ', str(Path(html)))
            feedback.reportError(
                'WARNING HTML WITH RELATIVE PATH SAVED OUTSIDE THE PROJECT PATH DOES NOT WORK PROPERLY\n'
            )
        if 'processing' in str(Path(html)):
            #print('html ', str(Path(html)))
            feedback.reportError(
                'WARNING TEMPORARY HTML WORK PROPERLY ONLY WITH ABSOLUTE PATH\n'
            )

        #FASE #05 - controllo se icona e css sono entro la cartella progetto
        if fogliocss and (path_dir not in fogliocss):
            feedback.reportError(
                'WARNING css PATH OUTSIDE PROJECT PATH: the html file may not work correctly\n'
            )
        if icona and path_dir not in icona:
            feedback.reportError(
                'WARNING icon PATH OUTSIDE PROJECT PATH: the html file may not work correctly\n'
            )

        #FASE #06 - aggiungo terminatore di percorso se non è un file temporaneo
        if path_dir != '':
            path_dir = path_dir + '\\'
        #print('Final path ', path_dir)

        #FASE #07 - modifica se csv in input
        if source_path.find(".csv"):
            source_path = 'file:///' + source_path[0:source_path.rfind('/') +
                                                   1]

        #FASE #08 recupero dimensioni foto e icona, titolo e riordino a causa di un bug
        wi, hi, wf, hf = f_base.split(';')
        titolo = titolo.replace('\"', '')

        intestazione = titolo.replace('"', '')
        intestazione = titolo.replace('\'', '')

        #riordino campi come da selezione per bug
        cleanlist = []
        [cleanlist.append(x) for x in sourceF if x not in cleanlist]
        sourceF = cleanlist

        #FASE #09 - inizializzo variabile per barra % esecuzione script
        # Compute the number of steps to display within the progress bar and
        # get features from source
        total = 100.0 / sourceL.featureCount() if sourceL.featureCount() else 0

        #FASE #10 - filtra dati se richiesto
        if len(filtro) > 0:
            request = QgsFeatureRequest(QgsExpression(filtro))
            features = sourceL.getFeatures(request)
        else:
            features = sourceL.getFeatures()

        #FASE #11 - produco il file in uscita
        with open(html, 'w') as output_file:
            # write header
            line = '<html>\r'
            output_file.write(line)

            #FASE #11.01 - se richiesto inserisco foglio css
            if fogliocss:
                if not rel_path or 'processing' in html:
                    fogliocss = 'file:///' + fogliocss
                else:
                    fogliocss = str(Path(fogliocss))
                    fogliocss = fogliocss.replace(path_dir, '')
                line = '<head>\r<link rel="stylesheet" href="' + fogliocss + '">\r</head>'
                output_file.write(line)

            #FASE #11.02 - se richiesto inserisco icona e titolo
            if icona or titolo:
                line = '<div>'
                if icona:
                    if not rel_path or 'processing' in html:
                        icona = 'file:///' + icona
                    else:
                        icona = str(Path(icona))
                        icona = icona.replace(path_dir, '')
                    line = '<img src="' + icona + '" style="width:' + wi + ';height:' + hi + ';">'
                    output_file.write(line)
                    line = ''
                if titolo:
                    if icona:
                        line = line + '<b>' + '&nbsp&nbsp' + titolo + '</b>'
                    else:
                        line = line + '<b>' + titolo + '</b>'
                    output_file.write(line)
                line = '</div>'
                output_file.write(line)
                line = None

            #FASE #11.03 - compongo tabella
            line = '<table class="Table">\r<thead>\r<tr>\r'
            output_file.write(line)

            #titoli colonne
            line = ''.join(('<th style="width:auto">' + str(name) + '</<th>\r')
                           for name in sourceF) + '</tr>\r'
            output_file.write(line)

            line = '</thead>\r<tbody>\r'
            output_file.write(line)

            #righe tabella
            for current, f in enumerate(features):
                line = '<tr>\r'
                output_file.write(line)

                for name in sourceF:
                    #controllo se si tratta di una immagine
                    try:
                        img_type = f[name].split(".")
                        img_type = img_type[len(img_type) - 1]
                        #print('img ok ', name, f[name], img_type)
                    except:
                        img_type = ''
                        #print('img no ', name, f[name], img_type)

                    #se è un'immagine e/o ha un percorso
                    if img_type in [
                            "JPEG", "jpeg", "JPG", "jpg", "PNG", "png"
                    ]:
                        #se non è un file temporaneo o non voglio riferimenti relativi
                        if not rel_path or 'processing' in html:
                            if file_mem:
                                img_name = 'file:///'
                            else:
                                img_name = ''
                            if path_dir not in str(Path(f[name])):
                                img_name = img_name + path_dir
                            img_name = img_name + f[name]
                        else:
                            #se voglio riferimenti relativi
                            img_name = str(Path(f[name]))
                            img_name = img_name.replace(path_dir, '')
                        line = ''.join('<td><center><img src =' + "'" +
                                       img_name + "'" + 'alt=' + "'" +
                                       img_name + "'" + 'width="' + wf +
                                       '" height="' + hf +
                                       '"></center></td>\r')
                    else:
                        try:
                            line = ''.join('<td>' +
                                           f[name].toString("dd.MM.yyyy") +
                                           '</td>\r')
                        except:
                            line = ''.join('<td>' + str(f[name]) + '</td>\r')
                    output_file.write(line)

                line = '</tr>\r'
                output_file.write(line)

                # Update the progress bar
                feedback.setProgress(int(current * total))

            line = '</tbody>\r</table>\r</html>'
            output_file.write(line)

        return {self.OUTPUT: html}
示例#24
0
 def testQgsExpressionRepr(self):
     e = QgsExpression('my expression')
     self.assertEqual(e.__repr__(), "<QgsExpression: 'my expression'>")
示例#25
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        if source is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUT))

        layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
        field_name = self.parameterAsString(parameters, self.FIELD_NAME,
                                            context)
        field_type = self.TYPES[self.parameterAsEnum(parameters,
                                                     self.FIELD_TYPE, context)]
        width = self.parameterAsInt(parameters, self.FIELD_LENGTH, context)
        precision = self.parameterAsInt(parameters, self.FIELD_PRECISION,
                                        context)
        new_field = self.parameterAsBool(parameters, self.NEW_FIELD, context)
        formula = self.parameterAsString(parameters, self.FORMULA, context)

        expression = QgsExpression(formula)
        da = QgsDistanceArea()
        da.setSourceCrs(source.sourceCrs(), context.transformContext())
        da.setEllipsoid(context.project().ellipsoid())
        expression.setGeomCalculator(da)

        expression.setDistanceUnits(context.project().distanceUnits())
        expression.setAreaUnits(context.project().areaUnits())

        fields = source.fields()
        field_index = fields.lookupField(field_name)
        if new_field or field_index < 0:
            fields.append(
                QgsField(field_name, field_type, '', width, precision))

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

        exp_context = self.createExpressionContext(parameters, context)
        if layer is not None:
            exp_context.appendScope(
                QgsExpressionContextUtils.layerScope(layer))

        expression.prepare(exp_context)

        features = source.getFeatures()
        total = 100.0 / source.featureCount() if source.featureCount() else 0

        for current, f in enumerate(features):
            if feedback.isCanceled():
                break

            rownum = current + 1
            exp_context.setFeature(f)
            exp_context.lastScope().setVariable("row_number", rownum)
            value = expression.evaluate(exp_context)
            if expression.hasEvalError():
                feedback.reportError(expression.evalErrorString())
            else:
                attrs = f.attributes()
                if new_field or field_index < 0:
                    attrs.append(value)
                else:
                    attrs[field_index] = value
                f.setAttributes(attrs)
                sink.addFeature(f, QgsFeatureSink.FastInsert)
            feedback.setProgress(int(current * total))

        return {self.OUTPUT: dest_id}
示例#26
0
 def testReferencedColumnsNoSet(self):
     success = QgsExpression.registerFunction(
         self.no_referenced_columns_set)
     exp = QgsExpression('no_referenced_columns_set()')
     self.assertEqual(exp.referencedColumns(),
                      {QgsFeatureRequest.AllAttributes})
示例#27
0
 def testReferencedColumnsNoSet(self):
     QgsExpression.registerFunction(self.no_referenced_columns_set)
     exp = QgsExpression('no_referenced_columns_set()')
     self.assertEqual(exp.referencedColumns(),
                      {QgsFeatureRequest.ALL_ATTRIBUTES})
示例#28
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_LAYER))
        fieldName = self.getParameterValue(self.FIELD_NAME)
        fieldType = self.TYPES[self.getParameterValue(self.FIELD_TYPE)]
        width = self.getParameterValue(self.FIELD_LENGTH)
        precision = self.getParameterValue(self.FIELD_PRECISION)
        newField = self.getParameterValue(self.NEW_FIELD)
        formula = self.getParameterValue(self.FORMULA)

        output = self.getOutputFromName(self.OUTPUT_LAYER)

        if output.value == '':
            ext = output.getDefaultFileExtension(self)
            output.value = system.getTempFilenameInTempFolder(output.name +
                                                              '.' + ext)

        provider = layer.dataProvider()
        fields = layer.pendingFields()
        if newField:
            fields.append(QgsField(fieldName, fieldType, '', width, precision))

        writer = output.getVectorWriter(fields, provider.geometryType(),
                                        layer.crs())

        exp = QgsExpression(formula)

        da = QgsDistanceArea()
        da.setSourceCrs(layer.crs().srsid())
        da.setEllipsoidalMode(
            iface.mapCanvas().mapSettings().hasCrsTransformEnabled())
        da.setEllipsoid(QgsProject.instance().readEntry(
            'Measure', '/Ellipsoid', GEO_NONE)[0])
        exp.setGeomCalculator(da)

        if not exp.prepare(layer.pendingFields()):
            raise GeoAlgorithmExecutionException(
                self.tr('Evaluation error: %s' % exp.evalErrorString()))

        outFeature = QgsFeature()
        outFeature.initAttributes(len(fields))
        outFeature.setFields(fields)

        error = ''
        calculationSuccess = True

        current = 0
        features = vector.features(layer)
        total = 100.0 / len(features)

        rownum = 1
        for current, f in enumerate(features):
            rownum = current + 1
            exp.setCurrentRowNumber(rownum)
            value = exp.evaluate(f)
            if exp.hasEvalError():
                calculationSuccess = False
                error = exp.evalErrorString()
                break
            else:
                outFeature.setGeometry(f.geometry())
                for fld in f.fields():
                    outFeature[fld.name()] = f[fld.name()]
                outFeature[fieldName] = value
                writer.addFeature(outFeature)

            progress.setPercentage(int(current * total))
        del writer

        if not calculationSuccess:
            raise GeoAlgorithmExecutionException(
                self.tr('An error occured while evaluating the calculation '
                        'string:\n%s' % error))
示例#29
0
    def processAlgorithm(self, feedback):
        layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT_LAYER))
        fieldName = self.getParameterValue(self.FIELD_NAME)
        fieldType = self.TYPES[self.getParameterValue(self.FIELD_TYPE)]
        width = self.getParameterValue(self.FIELD_LENGTH)
        precision = self.getParameterValue(self.FIELD_PRECISION)
        newField = self.getParameterValue(self.NEW_FIELD)
        formula = self.getParameterValue(self.FORMULA)

        output = self.getOutputFromName(self.OUTPUT_LAYER)

        fields = layer.fields()
        if newField:
            fields.append(QgsField(fieldName, fieldType, '', width, precision))

        writer = output.getVectorWriter(fields, layer.wkbType(),
                                        layer.crs())

        exp = QgsExpression(formula)

        da = QgsDistanceArea()
        da.setSourceCrs(layer.crs())
        da.setEllipsoidalMode(True)
        da.setEllipsoid(QgsProject.instance().ellipsoid())
        exp.setGeomCalculator(da)
        exp.setDistanceUnits(QgsProject.instance().distanceUnits())
        exp.setAreaUnits(QgsProject.instance().areaUnits())

        exp_context = QgsExpressionContext(QgsExpressionContextUtils.globalProjectLayerScopes(layer))

        if not exp.prepare(exp_context):
            raise GeoAlgorithmExecutionException(
                self.tr('Evaluation error: {0}').format(exp.evalErrorString()))

        outFeature = QgsFeature()
        outFeature.initAttributes(len(fields))
        outFeature.setFields(fields)

        error = ''
        calculationSuccess = True

        features = vector.features(layer)
        total = 100.0 / len(features)

        rownum = 1
        for current, f in enumerate(features):
            rownum = current + 1
            exp_context.setFeature(f)
            exp_context.lastScope().setVariable("row_number", rownum)
            value = exp.evaluate(exp_context)
            if exp.hasEvalError():
                calculationSuccess = False
                error = exp.evalErrorString()
                break
            else:
                outFeature.setGeometry(f.geometry())
                for fld in f.fields():
                    outFeature[fld.name()] = f[fld.name()]
                outFeature[fieldName] = value
                writer.addFeature(outFeature)

            feedback.setProgress(int(current * total))
        del writer

        if not calculationSuccess:
            raise GeoAlgorithmExecutionException(
                self.tr('An error occurred while evaluating the calculation '
                        'string:\n{0}').format(error))
    def processAlgorithm(self, parameters, context, feedback):
        path = self.parameterAsFile(parameters, self.INPUT, context)
        t_file = self.parameterAsVectorLayer(
            parameters,
            self.FILE_TABLE,
            context
        )
        t_troncon = self.parameterAsVectorLayer(
            parameters,
            self.SEGMENT_TABLE,
            context
        )
        t_obs = self.parameterAsVectorLayer(
            parameters,
            self.OBSERVATIONS_TABLE,
            context
        )
        t_regard = self.parameterAsVectorLayer(
            parameters,
            self.MANHOLES_TABLE,
            context
        )

        paths = path.split(';')
        if len(paths) != 1:
            raise QgsProcessingException(
                tr('* ERREUR: 1 fichier a la fois {}.').format(path)
            )

        if not os.path.exists(path):
            raise QgsProcessingException(
                tr('* ERREUR: {} n\'existe pas.').format(path)
            )

        # add date fields to itv file table
        # relation_aggregate(
        #     'itv_tronco_id_file_itv_file20_id',
        #     'max',
        #     "abf"
        # )
        if 'date_debut' not in t_file.dataProvider().fields().names():
            with edit(t_file):
                res = t_file.dataProvider().addAttributes([
                    QgsField("date_debut", QVariant.String),
                    QgsField("date_fin", QVariant.String)
                ])
                if res:
                    t_file.updateFields()

        feat_file = None
        with open(path, 'rb') as f:
            basename = os.path.basename(path)
            md = hashlib.md5()
            md.update(f.read())
            hashcontent = md.hexdigest()

            feat_file = QgsVectorLayerUtils.createFeature(t_file)
            feat_file.setAttribute('basename', basename)
            feat_file.setAttribute('hashcontent', hashcontent)

        if not feat_file:
            raise QgsProcessingException(
                tr(
                    '* ERREUR: le fichier {} n\'a pas été lu '
                    'correctement.'
                ).format(path)
            )

        exp_context = QgsExpressionContext()
        exp_context.appendScope(
            QgsExpressionContextUtils.globalScope()
        )
        exp_context.appendScope(
            QgsExpressionContextUtils.projectScope(context.project())
        )
        exp_context.appendScope(
            QgsExpressionContextUtils.layerScope(t_file)
        )

        exp_str = QgsExpression.createFieldEqualityExpression(
            'basename', feat_file['basename']
        ) + ' AND ' + QgsExpression.createFieldEqualityExpression(
            'hashcontent', feat_file['hashcontent']
        )
        exp = QgsExpression(exp_str)

        exp.prepare(exp_context)
        if exp.hasEvalError():
            raise QgsProcessingException(
                tr('* ERROR: Expression {} has eval error: {}').format(
                    exp.expression(), exp.evalErrorString()
                )
            )

        request = QgsFeatureRequest(exp, exp_context)
        request.setLimit(1)

        for _t in t_file.getFeatures(request):
            raise QgsProcessingException(
                tr('* ERREUR: le fichier {} a deja ete lu').format(
                    path
                )
            )

        exp_str = QgsExpression.createFieldEqualityExpression(
            'hashcontent', feat_file['hashcontent']
        )
        exp = QgsExpression(exp_str)

        exp.prepare(exp_context)
        if exp.hasEvalError():
            raise QgsProcessingException(
                tr('* ERROR: Expression {} has eval error: {}').format(
                    (exp.expression(), exp.evalErrorString())
                )
            )

        request = QgsFeatureRequest(exp, exp_context)
        request.setLimit(1)

        for _t in t_file.getFeatures(request):
            raise QgsProcessingException(
                tr(
                    '* ERREUR: le fichier {} semble deja avoir ete lu'
                ).format(path)
            )

        exp_context = QgsExpressionContext()
        exp_context.appendScope(
            QgsExpressionContextUtils.globalScope()
        )
        exp_context.appendScope(
            QgsExpressionContextUtils.projectScope(context.project())
        )
        exp_context.appendScope(
            QgsExpressionContextUtils.layerScope(t_troncon)
        )

        exp_str = 'maximum("id")'
        exp = QgsExpression(exp_str)

        exp.prepare(exp_context)
        if exp.hasEvalError():
            raise QgsProcessingException(
                tr(
                    '* ERROR: Expression {} has eval error: {}'
                ).format(exp.expression(), exp.evalErrorString())
            )

        last_t_id = exp.evaluate(exp_context)
        if not last_t_id:
            last_t_id = 0

        exp_context = QgsExpressionContext()
        exp_context.appendScope(
            QgsExpressionContextUtils.globalScope()
        )
        exp_context.appendScope(
            QgsExpressionContextUtils.projectScope(context.project())
        )
        exp_context.appendScope(
            QgsExpressionContextUtils.layerScope(t_regard)
        )

        exp_str = 'maximum("id")'
        exp = QgsExpression(exp_str)

        exp.prepare(exp_context)
        if exp.hasEvalError():
            raise QgsProcessingException(
                tr(
                    '* ERROR: Expression {} has eval error: {}'
                ).format(exp.expression(), exp.evalErrorString())
            )

        last_r_id = exp.evaluate(exp_context)
        if not last_r_id:
            last_r_id = 0

        # lecture des entetes
        ENCODING = 'ISO-8859-1'
        LANG = 'fr'
        DELIMITER = ','
        DECIMAL = '.'
        QUOTECHAR = '"'
        VERSION = ''

        with open(path, 'rb') as f:
            for line in f:
                # Stop the algorithm if cancel button has been clicked
                if feedback.isCanceled():
                    return {self.SUCCESS: 0}
                try:
                    line = line.decode()
                except UnicodeDecodeError:
                    raise QgsProcessingException(
                        'Error while reading {}'.format(path)
                    )
                # remove break line
                line = line.replace('\n', '').replace('\r', '')
                if line.startswith('#'):
                    if line.startswith('#A'):
                        if line.startswith('#A1'):
                            ENCODING = line[4:]
                            if ENCODING.find(':') != -1:
                                ENCODING = ENCODING[:ENCODING.find(':')]
                        elif line.startswith('#A2'):
                            LANG = line[4:]
                        elif line.startswith('#A3'):
                            DELIMITER = line[4:]
                        elif line.startswith('#A4'):
                            DECIMAL = line[4:]
                        elif line.startswith('#A5'):
                            QUOTECHAR = line[4:]
                    else:
                        break

        # Dialect CSV pour la lecture des tableaux de valeurs du
        # fichier d'ITV
        class itvDialect(csv.Dialect):
            strict = True
            skipinitialspace = True
            quoting = csv.QUOTE_MINIMAL
            delimiter = DELIMITER
            quotechar = QUOTECHAR
            lineterminator = '\r\n'

        # Liste des troncons, observations et regards
        troncons = []
        regards = []
        observations = []

        # Lectures des donnees
        with open(path, 'rb') as f:
            # Identifiant de départ
            t_id = last_t_id
            r_id = last_r_id
            # Entête
            header = []
            # Nom du tableau
            array = ''
            # Observations de troncons ?
            obs_for_troncon = False
            # initialisation du Dialect CSV pour ITV
            dia = itvDialect()
            # Lecture ligne à ligne du fichier
            for line in f:
                # Stop the algorithm if cancel button has been clicked
                if feedback.isCanceled():
                    return {self.SUCCESS: 0}
                # Decoding line en utilisant l'encoding du fichier
                line = line.decode(ENCODING)
                # remove break line
                line = line.replace('\n', '').replace('\r', '')
                # Ligne commençant par un # est une ligne d'entête
                if line.startswith('#'):
                    # Entête de troncon ou regard
                    if line.startswith('#B'):
                        l_b = io.StringIO(line[5:])
                        for l_r in csv.reader(l_b, dia):
                            header = l_r
                            break
                        array = line[1:4]
                        continue
                    # Entête d'observation
                    elif line.startswith('#C'):
                        if header[0].startswith('A'):
                            obs_for_troncon = True
                        else:
                            obs_for_troncon = False
                        l_b = io.StringIO(line[3:])
                        for l_r in csv.reader(l_b, dia):
                            header = l_r
                            break
                        array = line[1:2]
                        continue
                    # Fin d'observation
                    elif line.startswith('#Z'):
                        header = []
                        array = ''
                        obs_for_troncon = False
                        continue
                # La ligne contient des donnees
                else:
                    if not header:  # an error in the file structure
                        continue
                    l_b = io.StringIO(line)
                    for l_r in csv.reader(l_b, dia):
                        data = l_r
                        row = list(
                            zip(
                                [h.lower() for h in header],
                                [t for t in data]
                            )
                        )
                        # observation
                        if array == 'C':
                            if obs_for_troncon:
                                observations.append(
                                    row + [('id_troncon', t_id)]
                                )
                        # Premiere ligne de description d'un troncon ou regard
                        elif array == 'B01':
                            if header[0].startswith('A'):
                                t_id += 1
                                troncons.append([('id', t_id)] + row)
                            elif header[0].startswith('C'):
                                r_id += 1
                                regards.append([('id', r_id)] + row)
                        # Ligne complémentaire de description
                        else:
                            if header[0].startswith('A'):
                                troncons[-1] += row
                            elif header[0].startswith('C'):
                                regards[-1] += row

        # Recuperation des references de noeuds et dates
        itv_dates = []
        regard_node_refs = []
        regard_ref_id = {}
        max_r_id = last_r_id
        for reg in regards:
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SUCCESS: 0}

            d_rg = dict(reg)
            if d_rg['caa'] and d_rg['caa'] not in regard_node_refs:
                regard_node_refs.append(d_rg['caa'])
                regard_ref_id[d_rg['caa']] = d_rg['id']
            if d_rg['id'] and d_rg['id'] > max_r_id:
                max_r_id = d_rg['id']
            if 'cbf' in d_rg and d_rg['cbf'] not in itv_dates:
                itv_dates.append(d_rg['cbf'])

        node_refs = []
        for tro in troncons:
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SUCCESS: 0}

            d_tr = dict(tro)
            # The nodes ref are stored in AAB, AAD, AAF and AAT
            if 'aab' in d_tr and \
                    d_tr['aab'] and \
                    d_tr['aab'] not in regard_node_refs and \
                    d_tr['aab'] not in node_refs:
                node_refs.append(d_tr['aab'])
            if 'aad' in d_tr and \
                    d_tr['aad'] and \
                    d_tr['aad'] not in regard_node_refs and \
                    d_tr['aad'] not in node_refs:
                node_refs.append(d_tr['aad'])
            if 'aaf' in d_tr and \
                    d_tr['aaf'] and \
                    d_tr['aaf'] not in regard_node_refs and \
                    d_tr['aaf'] not in node_refs:
                node_refs.append(d_tr['aaf'])
            if 'aat' in d_tr and \
                    d_tr['aat'] and \
                    d_tr['aat'] not in regard_node_refs and \
                    d_tr['aat'] not in node_refs:
                node_refs.append(d_tr['aat'])
            if 'abf' in d_tr and d_tr['abf'] not in itv_dates:
                itv_dates.append(d_tr['abf'])

        # Ajout des regards manquant
        for n_ref in node_refs:
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SUCCESS: 0}

            max_r_id += 1
            regards.append([('id', max_r_id), ('caa', n_ref)])
            regard_ref_id[n_ref] = max_r_id

        # Ajout des identifiants de regards aux tronçons
        regard_refs = regard_ref_id.keys()
        for tro in troncons:
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SUCCESS: 0}

            d_tr = dict(tro)
            # If AAD is not defined then it is equal to AAB
            if 'aad' not in d:
                d['aad'] = d['aab']
            if d_tr['aad'] and \
                    d_tr['aad'] in regard_refs:
                tro += [('id_regard1', regard_ref_id[d_tr['aad']])]
            if d_tr['aaf'] and \
                    d_tr['aaf'] in regard_refs:
                tro += [('id_regard2', regard_ref_id[d_tr['aaf']])]
            if 'aat' in d_tr.keys() and \
                    d_tr['aat'] and \
                    d_tr['aat'] in regard_refs:
                tro += [('id_regard3', regard_ref_id[d_tr['aat']])]

        # Verification des champs
        fields = provider_fields(t_troncon.fields())
        for tro in troncons:
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SUCCESS: 0}

            for key, val in tro:
                # Stop the algorithm if cancel button has been clicked
                if feedback.isCanceled():
                    return {self.SUCCESS: 0}

                if fields.indexOf(key) == -1:
                    raise QgsProcessingException(
                        tr(
                            '* ERREUR dans le fichier : '
                            'le champs de tronçon "{}" est inconnue'
                        ).format(key)
                    )
                field = fields.field(key)
                if isinstance(val, str) and field.isNumeric():
                    if val:
                        try:
                            float(val.replace(DECIMAL, '.'))
                        except BaseException:
                            raise QgsProcessingException(
                                tr(
                                    '* ERREUR dans le fichier : '
                                    'le champs de tronçon "{}" est '
                                    'numérique mais pas la valeur "{}"'
                                ).format(key, val)
                            )

        fields = provider_fields(t_obs.fields())
        for obs in observations:
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SUCCESS: 0}

            for key, val in obs:
                # Stop the algorithm if cancel button has been clicked
                if feedback.isCanceled():
                    return {self.SUCCESS: 0}

                if fields.indexOf(key) == -1:
                    raise QgsProcessingException(
                        tr(
                            '* ERREUR dans le fichier : '
                            'le champs d\'observation "{}" est '
                            'inconnue'
                        ).format(key)
                    )
                field = fields.field(key)
                if isinstance(val, str) and field.isNumeric():
                    if val:
                        try:
                            float(val.replace(DECIMAL, '.'))
                        except BaseException:
                            raise QgsProcessingException(
                                tr(
                                    '* ERREUR dans le fichier : '
                                    'le champs d\'observation "{}" est '
                                    'numérique mais pas la valeur "{}"'
                                ).format(key, val)
                            )

        fields = provider_fields(t_regard.fields())
        for reg in regards:
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SUCCESS: 0}

            for key, val in reg:
                # Stop the algorithm if cancel button has been clicked
                if feedback.isCanceled():
                    return {self.SUCCESS: 0}

                if fields.indexOf(key) == -1:
                    raise QgsProcessingException(
                        tr(
                            '* ERREUR dans le fichier : '
                            'le champs de regard "{}" est inconnue'
                        ).format(key)
                    )
                field = fields.field(key)
                if isinstance(val, str) and field.isNumeric():
                    if val:
                        try:
                            float(val.replace(DECIMAL, '.'))
                        except BaseException:
                            raise QgsProcessingException(
                                tr(
                                    '* ERREUR dans le fichier : '
                                    'le champs de regard "{}" est '
                                    'numérique mais pas la valeur "{}"'
                                ).format(key, val)
                            )

        # Finalisation objet fichier
        feat_file.setAttribute('encoding', ENCODING)
        feat_file.setAttribute('lang', LANG)
        if VERSION:
            feat_file.setAttribute('version', VERSION)
        if itv_dates:
            feat_file.setAttribute('date_debut', min(itv_dates))
            feat_file.setAttribute('date_fin', max(itv_dates))

        # Stop the algorithm if cancel button has been clicked
        if feedback.isCanceled():
            return {self.SUCCESS: 0}

        # Ajout de l'objet fichier
        t_file.startEditing()
        (res, outFeats) = t_file.dataProvider().addFeatures([feat_file])
        if not res or not outFeats:
            raise QgsProcessingException(
                tr(
                    '* ERREUR: lors de l\'enregistrement du fichier {}'
                ).format(', '.join(t_file.dataProvider().errors()))
            )
        if not t_file.commitChanges():
            raise QgsProcessingException(
                tr('* ERROR: Commit {}.').format(t_file.commitErrors())
            )

        # Mise a jour de l'identifiant de l'objet fichier
        feat_file.setAttribute('id', outFeats[0]['id'])

        # Creation des objets troncons
        features = []
        fields = provider_fields(t_troncon.fields())
        for tro in troncons:
            feat_t = QgsVectorLayerUtils.createFeature(t_troncon)
            feat_t.setAttribute('id_file', feat_file['id'])
            for key, val in tro:
                field = fields.field(key)
                if isinstance(val, str) and field.isNumeric():
                    if val:
                        feat_t.setAttribute(
                            key, float(val.replace(DECIMAL, '.'))
                        )
                else:
                    feat_t.setAttribute(key, val)
            features.append(feat_t)

        # Ajout des objets troncons
        if features:
            t_troncon.startEditing()
            (res, outFeats) = t_troncon.dataProvider().addFeatures(features)
            if not res or not outFeats:
                raise QgsProcessingException(
                    tr(
                        '* ERREUR: lors de l\'enregistrement '
                        'des troncon {}'
                    ).format(
                        ', '.join(t_troncon.dataProvider().errors())
                    )
                )
            if not t_troncon.commitChanges():
                raise QgsProcessingException(
                    tr('* ERROR: Commit {}.').format(
                        t_troncon.commitErrors()
                    )
                )

        # Creation des objets observations
        features = []
        fields = provider_fields(t_obs.fields())
        for obs in observations:
            feat_o = QgsVectorLayerUtils.createFeature(t_obs)
            feat_o.setAttribute('id_file', feat_file['id'])
            for key, val in obs:
                field = fields.field(key)
                if isinstance(val, str) and field.isNumeric():
                    if val:
                        feat_o.setAttribute(
                            key, float(val.replace(DECIMAL, '.'))
                        )
                else:
                    feat_o.setAttribute(key, val)
            features.append(feat_o)

        # Ajout des objets observations
        if features:
            t_obs.startEditing()
            (res, outFeats) = t_obs.dataProvider().addFeatures(features)
            if not res or not outFeats:
                raise QgsProcessingException(
                    tr(
                        '* ERREUR: lors de l\'enregistrement '
                        'des observations {}'
                    ).format(
                        ', '.join(t_obs.dataProvider().errors())
                    )
                )
            if not t_obs.commitChanges():
                raise QgsProcessingException(
                    tr('* ERROR: Commit {}.').format(
                        t_obs.commitErrors()
                    )
                )

        # Creation des objets regards
        features = []
        fields = provider_fields(t_regard.fields())
        for reg in regards:
            feat_r = QgsVectorLayerUtils.createFeature(t_regard)
            feat_r.setAttribute('id_file', feat_file['id'])
            for key, val in reg:
                field = fields.field(key)
                if isinstance(val, str) and field.isNumeric():
                    if val:
                        feat_r.setAttribute(
                            key, float(val.replace(DECIMAL, '.'))
                        )
                else:
                    feat_r.setAttribute(key, val)
            features.append(feat_r)

        # Ajout des objets regards
        if features:
            t_regard.startEditing()
            (res, outFeats) = t_regard.dataProvider().addFeatures(
                features
            )
            if not res or not outFeats:
                raise QgsProcessingException(
                    tr(
                        '* ERREUR: lors de l\'enregistrement '
                        'des regards {}'
                    ).format(
                        ', '.join(t_regard.dataProvider().errors())
                    )
                )
            if not t_regard.commitChanges():
                raise QgsProcessingException(
                    tr('* ERROR: Commit %s.').format(
                        t_regard.commitErrors()
                    )
                )

        # Returns empty dict if no outputs
        return {self.SUCCESS: 1}