Beispiel #1
0
    def processAlgorithm(self, progress):
        ns = {}
        ns["progress"] = progress
        ns["scriptDescriptionFile"] = self.descriptionFile

        for param in self.parameters:
            ns[param.name] = param.value

        for out in self.outputs:
            ns[out.name] = out.value

        variables = re.findall("@[a-zA-Z0-9_]*", self.script)
        script = "import processing\n"
        script += self.script

        context = QgsExpressionContext()
        context.appendScope(QgsExpressionContextUtils.globalScope())
        context.appendScope(QgsExpressionContextUtils.projectScope())
        for var in variables:
            varname = var[1:]
            if context.hasVariable(varname):
                script = script.replace(var, context.variable(varname))
            else:
                ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, "Cannot find variable: %s" % varname)

        exec((script), ns)
        for out in self.outputs:
            out.setValue(ns[out.name])
Beispiel #2
0
def inasafe_sub_analysis_summary_field_value(
        exposure_key, field, feature, parent):
    """Retrieve a value from field in the specified exposure analysis layer.

    """
    _ = feature, parent  # NOQA
    project_context_scope = QgsExpressionContextUtils.projectScope(
        QgsProject.instance())
    project = QgsProject.instance()

    key = ('{provenance}__{exposure}').format(
        provenance=provenance_multi_exposure_analysis_summary_layers_id[
            'provenance_key'],
        exposure=exposure_key)
    if not project_context_scope.hasVariable(key):
        return None

    analysis_summary_layer = project.mapLayer(
        project_context_scope.variable(key))
    if not analysis_summary_layer:
        return None

    index = analysis_summary_layer.fields().lookupField(field)
    if index < 0:
        return None

    feature = next(analysis_summary_layer.getFeatures())
    return feature[index]
    def processAlgorithm(self, progress):
        layer = layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT))

        expression = self.getParameterValue(self.EXPRESSION)
        qExp = QgsExpression(expression)
        if qExp.hasParserError():
            raise GeoAlgorithmExecutionException(qExp.parserErrorString())

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            layer.fields(), layer.wkbType(), layer.crs())

        context = QgsExpressionContext()
        context.appendScope(QgsExpressionContextUtils.globalScope())
        context.appendScope(QgsExpressionContextUtils.projectScope())
        context.appendScope(QgsExpressionContextUtils.layerScope(layer))

        count = layer.featureCount()
        step = 100.0 / count if count else 1

        request = QgsFeatureRequest(qExp, context)

        for current, f in enumerate(layer.getFeatures(request)):
            writer.addFeature(f)
            progress.setPercentage(int(current * step))

        del writer
Beispiel #4
0
    def processAlgorithm(self, feedback):
        ns = {}
        ns['feedback'] = feedback
        ns['scriptDescriptionFile'] = self.descriptionFile

        for param in self.parameters:
            ns[param.name] = param.value

        for out in self.outputs:
            ns[out.name] = out.value

        variables = re.findall('@[a-zA-Z0-9_]*', self.script)
        script = 'import processing\n'
        script += self.script

        context = QgsExpressionContext()
        context.appendScope(QgsExpressionContextUtils.globalScope())
        context.appendScope(QgsExpressionContextUtils.projectScope(QgsProject.instance()))
        for var in variables:
            varname = var[1:]
            if context.hasVariable(varname):
                script = script.replace(var, context.variable(varname))
            else:
                ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, 'Cannot find variable: %s' % varname)

        exec((script), ns)
        for out in self.outputs:
            out.setValue(ns[out.name])
Beispiel #5
0
    def processAlgorithm(self, parameters, context, feedback):
        ns = {}
        ns['feedback'] = feedback
        ns['scriptDescriptionFile'] = self.descriptionFile
        ns['context'] = context

        for param in self.parameterDefinitions():
            ns[param.name] = parameters[param.name()]

        for out in self.outputs:
            ns[out.name] = out.value

        variables = re.findall('@[a-zA-Z0-9_]*', self.script)
        script = 'import processing\n'
        script += self.script

        context = QgsExpressionContext()
        context.appendScope(QgsExpressionContextUtils.globalScope())
        context.appendScope(QgsExpressionContextUtils.projectScope(QgsProject.instance()))
        for var in variables:
            varname = var[1:]
            if context.hasVariable(varname):
                script = script.replace(var, context.variable(varname))
            else:
                QgsMessageLog.logMessage(self.tr('Cannot find variable: {0}').format(varname), self.tr('Processing'), QgsMessageLog.WARNING)

        exec((script), ns)
        for out in self.outputs:
            out.setValue(ns[out.name])
Beispiel #6
0
    def processAlgorithm(self, progress):
        ns = {}
        ns['progress'] = progress
        ns['scriptDescriptionFile'] = self.descriptionFile

        for param in self.parameters:
            ns[param.name] = param.value

        for out in self.outputs:
            ns[out.name] = out.value

        variables = re.findall("@[a-zA-Z0-9_]*", self.script)
        print variables
        script = 'import processing\n'
        script += self.script

        scope = QgsExpressionContextUtils.projectScope()
        for var in variables:
            varname = var[1:]
            if not scope.hasVariable(varname):
                raise GeoAlgorithmExecutionException("Wrong variable: %s" % varname)
            script = script.replace(var, scope.variable(varname))

        exec((script), ns)
        for out in self.outputs:
            out.setValue(ns[out.name])
Beispiel #7
0
def inasafe_analysis_summary_field_value(field, feature, parent):
    """Retrieve a value from a field in the analysis summary layer.

    e.g. inasafe_analysis_summary_field_value('total_not_exposed') -> 3
    """
    _ = feature, parent  # NOQA
    project_context_scope = QgsExpressionContextUtils.projectScope(
        QgsProject.instance())
    registry = QgsProject.instance()

    key = provenance_layer_analysis_impacted_id['provenance_key']
    if not project_context_scope.hasVariable(key):
        return None

    layer = registry.mapLayer(project_context_scope.variable(key))

    if not layer:
        return None

    index = layer.fields().lookupField(field)
    if index < 0:
        return None

    feature = next(layer.getFeatures())
    return feature[index]
Beispiel #8
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_LAYER))

        geometry_type = self.getParameterValue(self.OUTPUT_GEOMETRY)
        wkb_type = None
        if geometry_type == 0:
            wkb_type = QgsWkbTypes.Polygon
        elif geometry_type == 1:
            wkb_type = QgsWkbTypes.LineString
        else:
            wkb_type = QgsWkbTypes.Point
        if self.getParameterValue(self.WITH_Z):
            wkb_type = QgsWkbTypes.addZ(wkb_type)
        if self.getParameterValue(self.WITH_M):
            wkb_type = QgsWkbTypes.addM(wkb_type)

        writer = self.getOutputFromName(
            self.OUTPUT_LAYER).getVectorWriter(
                layer.fields(),
                wkb_type,
                layer.crs())

        expression = QgsExpression(self.getParameterValue(self.EXPRESSION))
        if expression.hasParserError():
            raise GeoAlgorithmExecutionException(expression.parserErrorString())

        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(QgsExpressionContextUtils.projectScope())
        exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer))

        if not expression.prepare(exp_context):
            raise GeoAlgorithmExecutionException(
                self.tr('Evaluation error: %s' % expression.evalErrorString()))

        features = vector.features(layer)
        total = 100.0 / len(features)
        for current, input_feature in enumerate(features):
            output_feature = input_feature

            exp_context.setFeature(input_feature)
            value = expression.evaluate(exp_context)
            if expression.hasEvalError():
                raise GeoAlgorithmExecutionException(
                    self.tr('Evaluation error: %s' % expression.evalErrorString()))

            if not value:
                output_feature.setGeometry(QgsGeometry())
            else:
                if not isinstance(value, QgsGeometry):
                    raise GeoAlgorithmExecutionException(
                        self.tr('{} is not a geometry').format(value))
                output_feature.setGeometry(value)

            writer.addFeature(output_feature)
            progress.setPercentage(int(current * total))

        del writer
 def initContext(self):
     exp_context = self.builder.expressionContext()
     exp_context.appendScope(QgsExpressionContextUtils.globalScope())
     exp_context.appendScope(QgsExpressionContextUtils.projectScope())
     exp_context.appendScope(QgsExpressionContextUtils.layerScope(self.layer))
     exp_context.lastScope().setVariable("row_number", 1)
     exp_context.setHighlightedVariables(["row_number"])
     self.builder.setExpressionContext(exp_context)
Beispiel #10
0
 def expressionContext(self):
     context = QgsExpressionContext()
     context.appendScope(QgsExpressionContextUtils.globalScope())
     context.appendScope(QgsExpressionContextUtils.projectScope())
     processingScope = QgsExpressionContextScope()
     for param in self.alg.parameters:
         processingScope.setVariable("%s_value" % param.name, "")
     context.appendScope(processingScope)
     return context
Beispiel #11
0
def _expressionContext(alg):
    context = QgsExpressionContext()
    context.appendScope(QgsExpressionContextUtils.globalScope())
    context.appendScope(QgsExpressionContextUtils.projectScope())
    processingScope = QgsExpressionContextScope()
    for param in alg.parameters:
        processingScope.setVariable('%s_value' % param.name, '')
    context.appendScope(processingScope)
    return context
Beispiel #12
0
 def evaluateExpression(self, text):
     context = QgsExpressionContext()
     context.appendScope(QgsExpressionContextUtils.globalScope())
     context.appendScope(QgsExpressionContextUtils.projectScope())
     exp = QgsExpression(text)
     if exp.hasParserError():
         raise Exception(exp.parserErrorString())
     result = exp.evaluate(context)
     if exp.hasEvalError():
         raise ValueError(exp.evalErrorString())
     return result
Beispiel #13
0
def analysis_summary_report(feature, parent):
    """Retrieve an HTML table report of current selected analysis.
    """
    _ = feature, parent  # NOQA
    project_context_scope = QgsExpressionContextUtils.projectScope(
        QgsProject.instance())
    key = provenance_layer_analysis_impacted['provenance_key']
    if not project_context_scope.hasVariable(key):
        return None

    analysis_dir = dirname(project_context_scope.variable(key))
    return get_impact_report_as_string(analysis_dir)
Beispiel #14
0
def exposure_summary_layer():
    """Helper method for retrieving exposure summary layer.

    If the analysis is multi-exposure, then it will return the exposure
    summary layer from place exposure analysis.
    """
    project_context_scope = QgsExpressionContextUtils.projectScope(
        QgsProject.instance())
    project = QgsProject.instance()

    key = provenance_layer_analysis_impacted_id['provenance_key']
    analysis_summary_layer = project.mapLayer(
        project_context_scope.variable(key))
    if not analysis_summary_layer:
        key = provenance_layer_analysis_impacted['provenance_key']
        if project_context_scope.hasVariable(key):
            analysis_summary_layer = load_layer(
                project_context_scope.variable(key))[0]

    if not analysis_summary_layer:
        return None

    keywords = KeywordIO.read_keywords(analysis_summary_layer)
    extra_keywords = keywords.get(property_extra_keywords['key'], {})
    is_multi_exposure = extra_keywords.get(extra_keyword_analysis_type['key'])

    key = provenance_layer_exposure_summary_id['provenance_key']
    if is_multi_exposure:
        key = ('{provenance}__{exposure}').format(
            provenance=provenance_multi_exposure_summary_layers_id[
                'provenance_key'],
            exposure=exposure_place['key'])
    if not project_context_scope.hasVariable(key):
        return None

    exposure_summary_layer = project.mapLayer(
        project_context_scope.variable(key))
    if not exposure_summary_layer:
        key = provenance_layer_exposure_summary['provenance_key']
        if is_multi_exposure:
            key = ('{provenance}__{exposure}').format(
                provenance=provenance_multi_exposure_summary_layers[
                    'provenance_key'],
                exposure=exposure_place['key'])
        if project_context_scope.hasVariable(key):
            exposure_summary_layer = load_layer(
                project_context_scope.variable(key))[0]
        else:
            return None

    return exposure_summary_layer
    def calculate( self, layer, fieldName, expression ):
        if ( layer.featureCount() == 0 ):
            self.msg.show( "[Info] * No existing features on layer " + layer.name() + " to calculate expression.", 'info', True )
            return

        expression = QgsExpression( expression )
        if expression.hasParserError():
            self.msg.show( QApplication.translate( "AutoFields-FieldCalculator", "[Error] (Parsing) " ) + \
                expression.parserErrorString(), 'critical' )
            return
        
        context = QgsExpressionContext()
        context.appendScope( QgsExpressionContextUtils.globalScope() )
        context.appendScope( QgsExpressionContextUtils.projectScope() )
        context.appendScope( QgsExpressionContextUtils.layerScope( layer ) )
        context.setFields( layer.fields() )

        if expression.needsGeometry():
            if self.iface:
                # This block was borrowed from QGIS/python/plugins/processing/algs/qgis/FieldsCalculator.py 
                da = QgsDistanceArea()
                da.setSourceCrs( layer.crs().srsid() )
                da.setEllipsoidalMode( self.iface.mapCanvas().mapSettings().hasCrsTransformEnabled() )
                da.setEllipsoid( QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE )[0] )
                expression.setGeomCalculator( da )
                if QGis.QGIS_VERSION_INT >= 21400: # Methods added in QGIS 2.14
                    expression.setDistanceUnits( QgsProject.instance().distanceUnits() ) 
                    expression.setAreaUnits( QgsProject.instance().areaUnits() )
        
        expression.prepare( context )

        fieldIndex = layer.fieldNameIndex( fieldName )
        if fieldIndex == -1:
            return           
        field = layer.fields()[fieldIndex]
        
        dictResults = {}
        for feature in layer.getFeatures():
            context.setFeature( feature )
            result = expression.evaluate( context )
            if expression.hasEvalError():
                self.msg.show( QApplication.translate( "AutoFields-FieldCalculator", "[Error] (Evaluating) " ) + \
                    expression.evalErrorString(), 'critical' )
                return
                
            dictResults[feature.id()] = { fieldIndex: field.convertCompatible( result ) }
            

        layer.dataProvider().changeAttributeValues( dictResults )
        
        self.msg.show( "[Info] * An expression was calculated on existing features of layer " + layer.name() + ", field " + fieldName + ".", 'info', True )
Beispiel #16
0
    def __init__(self, provider):
        super(PyFeatureSource, self).__init__()
        self._provider = provider
        self._features = provider._features

        self._expression_context = QgsExpressionContext()
        self._expression_context.appendScope(QgsExpressionContextUtils.globalScope())
        self._expression_context.appendScope(QgsExpressionContextUtils.projectScope(QgsProject.instance()))
        self._expression_context.setFields(self._provider.fields())
        if self._provider.subsetString():
            self._subset_expression = QgsExpression(self._provider.subsetString())
            self._subset_expression.prepare(self._expression_context)
        else:
            self._subset_expression = None
Beispiel #17
0
    def doAction(self, layer, uid, feature):
        if layer.actions().action(uid).name() == 'openFeatureForm':
            self.plugin.iface.openFeatureForm(layer, feature)
        else :
            ctxt = QgsExpressionContext()
            ctxt.appendScope(QgsExpressionContextUtils.globalScope())
            ctxt.appendScope(QgsExpressionContextUtils.projectScope(QgsProject.instance()))
            ctxt.appendScope(QgsExpressionContextUtils.mapSettingsScope(self.canvas.mapSettings()))

            # Add click_x and click_y to context
            p = self.toLayerCoordinates(layer, self.pos())            
            QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(), 'click_x', p.x())
            QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(), 'click_y', p.y())

            layer.actions().doAction(uid, feature, ctxt)
    def updateLayer(self):
        self.layer = dataobjects.getObject(self.cmbInputLayer.currentText())

        self.builder.setLayer(self.layer)
        self.builder.loadFieldNames()

        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(QgsExpressionContextUtils.projectScope())
        exp_context.appendScope(QgsExpressionContextUtils.layerScope(self.layer))
        exp_context.lastScope().setVariable("row_number", 1)
        exp_context.setHighlightedVariables(["row_number"])
        self.builder.setExpressionContext(exp_context)

        self.populateFields()
Beispiel #19
0
def aggregation_result_report(feature, parent):
    """Retrieve the aggregation result section from InaSAFE report.
    """
    _ = feature, parent  # NOQA
    project_context_scope = QgsExpressionContextUtils.projectScope()
    key = provenance_layer_analysis_impacted['provenance_key']
    if not project_context_scope.hasVariable(key):
        return None

    analysis_dir = dirname(project_context_scope.variable(key))
    complete_html_report = get_impact_report_as_string(analysis_dir)

    requested_html_report = get_report_section(
        complete_html_report, component_id=aggregation_result_component['key'])

    return requested_html_report
Beispiel #20
0
def createExpressionContext():
    context = QgsExpressionContext()
    context.appendScope(QgsExpressionContextUtils.globalScope())
    context.appendScope(QgsExpressionContextUtils.projectScope(QgsProject.instance()))

    if iface.mapCanvas():
        context.appendScope(QgsExpressionContextUtils.mapSettingsScope(iface.mapCanvas().mapSettings()))

    processingScope = QgsExpressionContextScope()

    extent = iface.mapCanvas().fullExtent()
    processingScope.setVariable('fullextent_minx', extent.xMinimum())
    processingScope.setVariable('fullextent_miny', extent.yMinimum())
    processingScope.setVariable('fullextent_maxx', extent.xMaximum())
    processingScope.setVariable('fullextent_maxy', extent.yMaximum())
    context.appendScope(processingScope)
    return context
    def test_length_expression(self):
        # compare length using the ellipsoid in kms and the planimetric distance in meters
        self.lyr.fieldName = "round($length,5) || ' - ' || round(length($geometry),2)"
        self.lyr.isExpression = True

        QgsProject.instance().setCrs(QgsCoordinateReferenceSystem("EPSG:32613"))
        QgsProject.instance().setEllipsoid("WGS84")
        QgsProject.instance().setDistanceUnits(QgsUnitTypes.DistanceKilometers)

        ctxt = QgsExpressionContext()
        ctxt.appendScope(QgsExpressionContextUtils.projectScope(QgsProject.instance()))
        ctxt.appendScope(QgsExpressionContextUtils.layerScope(self.layer))
        self._TestMapSettings.setExpressionContext(ctxt)

        self.lyr.placement = QgsPalLayerSettings.Curved
        self.lyr.placementFlags = QgsPalLayerSettings.AboveLine | QgsPalLayerSettings.MapOrientation
        self.checkTest()
Beispiel #22
0
def default_inasafe_html_resources(feature, parent):
    """Retrieve default InaSAFE HTML resources (style and script).
    """
    _ = feature, parent  # NOQA
    project_context_scope = QgsExpressionContextUtils.projectScope()
    key = provenance_layer_analysis_impacted['provenance_key']
    if not project_context_scope.hasVariable(key):
        return None

    analysis_dir = dirname(project_context_scope.variable(key))
    complete_html_report = get_impact_report_as_string(analysis_dir)

    requested_html_report = get_report_section(
        complete_html_report,
        component_id='inasafe-html-resources',
        container_wrapper_format=u'{section_content}')

    return requested_html_report
Beispiel #23
0
 def _layer_tooltip(self, layer, feat):
     try:
         df = layer.displayField()
         if df:
             return str(feat.attribute(df))
         else:
             context = QgsExpressionContext()
             context.appendScope(QgsExpressionContextUtils.globalScope())
             context.appendScope(QgsExpressionContextUtils.projectScope(QgsProject.instance()))
             context.appendScope(QgsExpressionContextUtils.layerScope(layer))
             context.appendScope(QgsExpressionContextUtils.mapSettingsScope( self.canvas.mapSettings() ) )
             context.setFeature( feat )
             
             x = QgsExpression(layer.displayExpression())
             x.prepare(context)
             return x.evaluate(context).replace('\n', "<br/>")
     except:
         return ""
Beispiel #24
0
    def pointPicked(self, event):
        for b in self.rubberBands:
            del b
        self.rubberBands[:] = []

        fieldX = self.cmbXField.currentField()
        fieldY = self.cmbYField.currentField()

        artist = event.artist
        indices = event.ind
        for i in indices:
            x = self.xData[artist.name][i]
            y = self.yData[artist.name][i]

            if isinstance(x, int):
                expr = '"{}" = {} AND '.format(fieldX, x)
            elif isinstance(x, float):
                expr = 'abs("{}" - {}) <= 0.0000001 AND '.format(fieldX, x)
            elif isinstance(x, (str, unicode)):
                expr = """"{}" = '{}' AND """.format(fieldX, x)
            else:
                expr = """"{}" = '{}' AND """.format(fieldX, x.toString('yyyy-MM-dd'))

            if isinstance(y, float):
                expr += 'abs("{}" - {}) <= 0.0000001'.format(fieldY, y)
            elif isinstance(y, (str, unicode)):
                expr += """"{}" = '{}'""".format(fieldY, y)
            else:
                expr += '"{}" = {}'.format(fieldY, y)

            layer = self.cmbLayer.currentLayer()
            expression = QgsExpression(expr)
            context = QgsExpressionContext()
            context.appendScope(QgsExpressionContextUtils.globalScope())
            context.appendScope(QgsExpressionContextUtils.projectScope())
            context.appendScope(QgsExpressionContextUtils.mapSettingsScope(self.canvas.mapSettings()))
            context.appendScope(QgsExpressionContextUtils.layerScope(layer))

            request = QgsFeatureRequest(expression, context)
            for f in layer.getFeatures(request):
                hl = QgsHighlight(self.canvas, f.geometry(), layer)
                hl.setColor(QColor(255, 0, 0))
                hl.setWidth(2)
                self.rubberBands.append(hl)
Beispiel #25
0
    def expressionContext(self):
        context = QgsExpressionContext()
        context.appendScope(QgsExpressionContextUtils.globalScope())
        context.appendScope(QgsExpressionContextUtils.projectScope())
        processingScope = QgsExpressionContextScope()
        layers = dataobjects.getAllLayers()
        for layer in layers:
            name = layer.name()
            processingScope.setVariable('%s_minx' % name, layer.extent().xMinimum())
            processingScope.setVariable('%s_miny' % name, layer.extent().yMinimum())
            processingScope.setVariable('%s_maxx' % name, layer.extent().xMaximum())
            processingScope.setVariable('%s_maxy' % name, layer.extent().yMaximum())
            if isinstance(layer, QgsRasterLayer):
                cellsize = (layer.extent().xMaximum()
                            - layer.extent().xMinimum()) / layer.width()
                processingScope.setVariable('%s_cellsize' % name, cellsize)

        layers = dataobjects.getRasterLayers()
        for layer in layers:
            for i in range(layer.bandCount()):
                stats = layer.dataProvider().bandStatistics(i + 1)
                processingScope.setVariable('%s_band%i_avg' % (name, i + 1), stats.mean)
                processingScope.setVariable('%s_band%i_stddev' % (name, i + 1), stats.stdDev)
                processingScope.setVariable('%s_band%i_min' % (name, i + 1), stats.minimumValue)
                processingScope.setVariable('%s_band%i_max' % (name, i + 1), stats.maximumValue)

        extent = iface.mapCanvas().extent()
        processingScope.setVariable('canvasextent_minx', extent.xMinimum())
        processingScope.setVariable('canvasextent_miny', extent.yMinimum())
        processingScope.setVariable('canvasextent_maxx', extent.xMaximum())
        processingScope.setVariable('canvasextent_maxy', extent.yMaximum())

        extent = iface.mapCanvas().fullExtent()
        processingScope.setVariable('fullextent_minx', extent.xMinimum())
        processingScope.setVariable('fullextent_miny', extent.yMinimum())
        processingScope.setVariable('fullextent_maxx', extent.xMaximum())
        processingScope.setVariable('fullextent_maxy', extent.yMaximum())
        context.appendScope(processingScope)
        return context
Beispiel #26
0
def createExpressionContext():
    context = QgsExpressionContext()
    context.appendScope(QgsExpressionContextUtils.globalScope())
    context.appendScope(
        QgsExpressionContextUtils.projectScope(QgsProject.instance()))

    if iface and iface.mapCanvas():
        context.appendScope(
            QgsExpressionContextUtils.mapSettingsScope(
                iface.mapCanvas().mapSettings()))

    processingScope = QgsExpressionContextScope()

    if iface and iface.mapCanvas():
        extent = iface.mapCanvas().fullExtent()
        processingScope.setVariable('fullextent_minx', extent.xMinimum())
        processingScope.setVariable('fullextent_miny', extent.yMinimum())
        processingScope.setVariable('fullextent_maxx', extent.xMaximum())
        processingScope.setVariable('fullextent_maxy', extent.yMaximum())

    context.appendScope(processingScope)
    return context
Beispiel #27
0
    def processAlgorithm(self, parameters, context, feedback):
        # Database connection parameters
        connection_name = QgsExpressionContextUtils.projectScope(
            context.project()).variable('gobs_connection_name')

        msg = ''
        status = 1

        # Set SQL
        self.setSql(parameters, context, feedback)
        # Set output layer name
        self.setLayerName(parameters, context, feedback)

        # Buid QGIS uri to load layer
        id_field = 'id'
        uri = getPostgisConnectionUriFromName(connection_name)
        uri.setDataSource("", "(" + self.SQL + ")", self.GEOM_FIELD, "",
                          id_field)
        vlayer = QgsVectorLayer(uri.uri(), "layername", "postgres")
        if not vlayer.isValid():
            feedback.reportError('SQL = \n' + self.SQL)
            raise QgsProcessingException(
                tr("""This layer is invalid!
                Please check the PostGIS log for error messages."""))

        # Load layer
        context.temporaryLayerStore().addMapLayer(vlayer)
        context.addLayerToLoadOnCompletion(
            vlayer.id(),
            QgsProcessingContext.LayerDetails(self.LAYER_NAME,
                                              context.project(),
                                              self.OUTPUT_LAYER))

        return {
            self.OUTPUT_STATUS: status,
            self.OUTPUT_STRING: msg,
            self.OUTPUT_LAYER: vlayer.id(),
            self.OUTPUT_LAYER_RESULT_NAME: self.LAYER_NAME
        }
def get_project_setting(key: str,
                        default: Optional[any] = None,
                        typehint: type = None,
                        internal: bool = True) -> Union[QVariant, str, None]:
    """
    Get QGIS project setting value

    :param key: Key for the setting
    :param default: Optional default value
    :param typehint: Type hint
    :param internal: Whether to search from only plugin settings or all
    :return: Value if conversion is successful, else None
    """
    proj = QgsProject.instance()

    if not internal:
        value = QgsExpressionContextUtils.projectScope(proj).variable(key)
        return value if value is not None else default

    args = [plugin_name(), key]
    if default is not None:
        args.append(default)

    value = None
    conversion_ok = False
    if typehint is not None and typehint is not str:
        try:
            if typehint is int:
                value, conversion_ok = proj.readNumEntry(*args)
            elif typehint is bool:
                value, conversion_ok = proj.readBoolEntry(*args)
            elif typehint is list:
                value, conversion_ok = proj.readListEntry(*args)
        except TypeError as e:
            raise QgsPluginInvalidProjectSetting(str(e))
    else:
        value, conversion_ok = proj.readEntry(*args)
    return value if conversion_ok else default
    def initAlgorithm(self, config):
        # INPUTS
        project = QgsProject.instance()
        connection_name = QgsExpressionContextUtils.projectScope(
            project).variable('gobs_connection_name')
        db_param = QgsProcessingParameterString(
            self.CONNECTION_NAME,
            tr('PostgreSQL connection to G-Obs database'),
            defaultValue=connection_name,
            optional=False)
        db_param.setMetadata({
            'widget_wrapper': {
                'class':
                'processing.gui.wrappers_postgis.ConnectionWidgetWrapper'
            }
        })
        self.addParameter(db_param)

        self.addParameter(
            QgsProcessingParameterBoolean(
                self.OVERRIDE,
                tr('Overwrite schema gobs and all data ? ** CAUTION ** It will remove all existing data !'
                   ),
                defaultValue=False,
            ))
        self.addParameter(
            QgsProcessingParameterBoolean(
                self.ADD_TEST_DATA,
                tr('Add test data ?'),
                defaultValue=False,
            ))
        # OUTPUTS
        # Add output for status (integer) and message (string)
        self.addOutput(
            QgsProcessingOutputNumber(self.OUTPUT_STATUS, tr('Output status')))
        self.addOutput(
            QgsProcessingOutputString(self.OUTPUT_STRING,
                                      tr('Output message')))
Beispiel #30
0
    def _layer_tooltip(self, layer, feat):
        try:
            df = layer.displayField()
            if df:
                return str(feat.attribute(df))
            else:
                context = QgsExpressionContext()
                context.appendScope(QgsExpressionContextUtils.globalScope())
                context.appendScope(
                    QgsExpressionContextUtils.projectScope(
                        QgsProject.instance()))
                context.appendScope(
                    QgsExpressionContextUtils.layerScope(layer))
                context.appendScope(
                    QgsExpressionContextUtils.mapSettingsScope(
                        self.canvas.mapSettings()))
                context.setFeature(feat)

                x = QgsExpression(layer.displayExpression())
                x.prepare(context)
                return x.evaluate(context).replace("\n", "<br/>")
        except:
            return ""
    def setCustomExpression( self ):
        """ Initialize and show the expression builder dialog """
        layer = None
        if len( self.tblLayers.selectedItems() ) / 3 == 1: # Single layer selected?
            for item in self.tblLayers.selectedItems():
                if item.column() == 1: # It's the layer name item
                    layer = QgsMapLayerRegistry.instance().mapLayer( item.data( Qt.UserRole ) )

        if not self.expressionDlg:
            self.expressionDlg = ExpressionBuilderDialog( self.iface.mainWindow() )
            context = QgsExpressionContext()
            context.appendScope( QgsExpressionContextUtils.globalScope() )
            context.appendScope( QgsExpressionContextUtils.projectScope() )

            # Initialize dialog with layer-based names and variables if single layer selected
            if len( self.tblLayers.selectedItems() ) / 3 == 1:
                context.appendScope( QgsExpressionContextUtils.layerScope( layer ) )
                self.expressionDlg.expressionBuilderWidget.setLayer( layer )
                self.expressionDlg.expressionBuilderWidget.loadFieldNames()

                # This block was borrowed from QGIS/python/plugins/processing/algs/qgis/FieldsCalculator.py
                da = QgsDistanceArea()
                da.setSourceCrs( layer.crs().srsid() )
                da.setEllipsoidalMode( self.iface.mapCanvas().mapSettings().hasCrsTransformEnabled() )
                da.setEllipsoid( QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE )[0] )
                self.expressionDlg.expressionBuilderWidget.setGeomCalculator( da )

                # If this layer-field is an AutoField, get its expression
                if self.optExistingField.isChecked():
                    fieldName = self.cboField.currentText()
                    expression = self.autoFieldManager.getFieldExpression( layer, fieldName )
                    self.expressionDlg.expressionBuilderWidget.setExpressionText( expression )
                    self.expressionDlg.expression = expression # To remember it when closing/opening

            self.expressionDlg.expressionBuilderWidget.setExpressionContext( context )

        self.expressionDlg.show()
Beispiel #32
0
def inasafe_impact_analysis_field_value(field, feature, parent):
    """Retrieve a value from a field in the impact analysis layer.

    e.g. inasafe_impact_analysis_field_value('total_not_exposed') -> 3
    """
    _ = feature, parent  # NOQA
    project_context_scope = QgsExpressionContextUtils.projectScope()
    registry = QgsMapLayerRegistry.instance()

    key = provenance_layer_analysis_impacted_id['provenance_key']
    if not project_context_scope.hasVariable(key):
        return None

    layer = registry.mapLayer(project_context_scope.variable(key))

    if not layer:
        return None

    index = layer.fieldNameIndex(field)
    if index < 0:
        return None

    feature = layer.getFeatures().next()
    return feature[index]
Beispiel #33
0
 def loadState(self, state=None):
     """
     Loads all loaded workflows from current QgsProject instance.
     :param state: (str) this should be a strigfied map to QA's state
                   variables. If none is given, state is retrieved from the
                   project.
     """
     state = json.loads(
         state or\
         QgsExpressionContextUtils.projectScope(QgsProject.instance())\
                 .variable("dsgtools_qatoolbox_state") or\
         "{}"
     )
     workflows = state["workflows"] if "workflows" in state else {}
     self.resetComboBox()
     for idx, (name, workflowMap) in enumerate(workflows.items()):
         self.workflows[name] = QualityAssuranceWorkflow(workflowMap)
         self.comboBox.addItem(name)
         self.setWorkflowTooltip(idx + 1, self.workflows[name].metadata())
     currentIdx = state["current_workflow"] if "current_workflow" in state \
                     else 0
     self.comboBox.setCurrentIndex(currentIdx)
     showButtons = state["show_buttons"] if "show_buttons" in state else True
     self.showEditionButton(showButtons)
    def checkParameterValues(self, parameters, context):

        # Check that the connection name has been configured
        connection_name = QgsExpressionContextUtils.projectScope(
            context.project()).variable('gobs_connection_name')
        if not connection_name:
            return False, tr(
                'You must use the "Configure G-obs plugin" alg to set the database connection name'
            )

        # Check that it corresponds to an existing connection
        if connection_name not in getPostgisConnectionList():
            return False, tr(
                'The configured connection name does not exists in QGIS')

        serie_id = self.parameterAsInt(parameters, self.SERIE_ID, context)

        # Check series id is in the list of existing series
        if serie_id and serie_id > 0:
            if serie_id not in self.SERIES_DICT.values():
                return False, tr('Series ID does not exists in the database')

        return super(GetSeriesData,
                     self).checkParameterValues(parameters, context)
Beispiel #35
0
def hazard_extra_keyword(keyword, feature, parent):
    """Given a keyword, it will return the value of the keyword
    from the hazard layer's extra keywords.

    For instance:
    *   hazard_extra_keyword( 'depth' ) -> will return the value of 'depth'
        in current hazard layer's extra keywords.
    """
    _ = feature, parent  # NOQA
    hazard_layer_path = QgsExpressionContextUtils.projectScope().variable(
        'hazard_layer')
    hazard_layer = load_layer(hazard_layer_path)[0]
    keywords = KeywordIO.read_keywords(hazard_layer)
    extra_keywords = keywords.get('extra_keywords')
    if extra_keywords:
        value = extra_keywords.get(keyword)
        if value:
            value_definition = definition(value)
            if value_definition:
                return value_definition['name']
            return value
        else:
            return tr('Keyword %s is not found' % keyword)
    return tr('No extra keywords found')
    def evaluate(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 = find_vector_layer(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
        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
        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
        add_form_scope = 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 add_form_scope:
                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 add_form_scope:
                    # need to prepare the expression because the context has 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
    def initAlgorithm(self, config):
        # INPUTS
        project = QgsProject.instance()
        connection_name = QgsExpressionContextUtils.projectScope(
            project).variable('gobs_connection_name')
        if not connection_name:
            connection_name = os.environ.get("GOBS_CONNECTION_NAME")
        get_data = QgsExpressionContextUtils.globalScope().variable(
            'gobs_get_database_data')

        # List of spatial_layer
        sql = '''
            SELECT id, sl_label
            FROM gobs.spatial_layer
            ORDER BY sl_label
        '''
        data = []
        if get_data == 'yes' and connection_name in getPostgisConnectionList():
            [header, data, rowCount, ok,
             error_message] = fetchDataFromSqlQuery(connection_name, sql)
        self.SPATIALLAYERS = ['%s - %s' % (a[1], a[0]) for a in data]
        self.addParameter(
            QgsProcessingParameterEnum(self.SPATIALLAYER,
                                       tr('Target spatial layer'),
                                       options=self.SPATIALLAYERS,
                                       optional=False))
        self.addParameter(
            QgsProcessingParameterVectorLayer(self.SOURCELAYER,
                                              tr('Source data layer'),
                                              optional=False))
        self.addParameter(
            QgsProcessingParameterField(
                self.UNIQUEID,
                tr('Unique identifier'),
                parentLayerParameterName=self.SOURCELAYER))
        self.addParameter(
            QgsProcessingParameterField(
                self.UNIQUELABEL,
                tr('Unique label'),
                parentLayerParameterName=self.SOURCELAYER,
                type=QgsProcessingParameterField.String))
        # Min validity field
        self.addParameter(
            QgsProcessingParameterField(
                self.DATE_VALIDITY_MIN,
                tr('Start timestamp of validity. Field in ISO Format'),
                optional=True,
                parentLayerParameterName=self.SOURCELAYER))
        # Manual min validity
        self.addParameter(
            QgsProcessingParameterString(
                self.MANUAL_DATE_VALIDITY_MIN,
                tr('Manual start timestamp of validity (2019-01-06 or 2019-01-06 22:59:50)'
                   ),
                optional=True))
        # Max validity field
        self.addParameter(
            QgsProcessingParameterField(
                self.DATE_VALIDITY_MAX,
                tr('End timestamp of validity. Field in ISO Format'),
                optional=True,
                parentLayerParameterName=self.SOURCELAYER))
        # Manual max validity
        self.addParameter(
            QgsProcessingParameterString(
                self.MANUAL_DATE_VALIDITY_MAX,
                tr('Manual end timestamp of validity (2019-01-31 or 2019-01-31 23:59:59)'
                   ),
                optional=True))

        # OUTPUTS
        # Add output for message
        self.addOutput(
            QgsProcessingOutputString(self.OUTPUT_STRING,
                                      tr('Output message')))
Beispiel #38
0
def print_atlas(project, layout_name, feature_filter, scales=None, scale=None):
    """Generate an atlas.

    :param project: The project to render as atlas.
    :type project: QgsProject

    :param layout_name: Name of the layout.
    :type layout_name: basestring

    :param feature_filter: QGIS Expression to use to select the feature.
    It can return many features, a multiple pages PDF will be returned.
    :type feature_filter: basestring

    :param scale: A scale to force in the atlas context. Default to None.
    :type scale: int

    :param scales: A list of predefined list of scales to force in the atlas context.
    Default to None.
    :type scales: list

    :return: Path to the PDF.
    :rtype: basestring
    """
    canvas = QgsMapCanvas()
    bridge = QgsLayerTreeMapCanvasBridge(project.layerTreeRoot(), canvas)
    bridge.setCanvasLayers()
    manager = project.layoutManager()
    master_layout = manager.layoutByName(layout_name)

    if not master_layout:
        raise AtlasPrintException('Layout not found')

    if master_layout.layoutType() != QgsMasterLayoutInterface.PrintLayout:
        raise AtlasPrintException('The layout is not a print layout')

    for l in manager.printLayouts():
        if l.name() == layout_name:
            layout = l
            break
    else:
        raise AtlasPrintException('The layout is not found')

    atlas = layout.atlas()

    if not atlas.enabled():
        raise AtlasPrintException('The layout is not enabled for an atlas')

    settings = QgsLayoutExporter.PdfExportSettings()

    if scale:
        layout.referenceMap().setAtlasScalingMode(QgsLayoutItemMap.Fixed)
        layout.referenceMap().setScale(scale)

    if scales:
        layout.referenceMap().setAtlasScalingMode(QgsLayoutItemMap.Predefined)
        if Qgis.QGIS_VERSION_INT >= 30900:
            settings.predefinedMapScales = scales
        else:
            layout.reportContext().setPredefinedScales(scales)

    layer = atlas.coverageLayer()
    feature_filter = optimize_expression(layer, feature_filter)

    expression = QgsExpression(feature_filter)
    if expression.hasParserError():
        raise AtlasPrintException(
            'Expression is invalid, parser error: {}'.format(
                expression.parserErrorString()))

    context = QgsExpressionContext()
    context.appendScope(QgsExpressionContextUtils.globalScope())
    context.appendScope(QgsExpressionContextUtils.projectScope(project))
    context.appendScope(QgsExpressionContextUtils.layoutScope(layout))
    context.appendScope(QgsExpressionContextUtils.atlasScope(atlas))
    context.appendScope(QgsExpressionContextUtils.layerScope(layer))

    expression.prepare(context)
    if expression.hasEvalError():
        raise AtlasPrintException(
            'Expression is invalid, eval error: {}'.format(
                expression.evalErrorString()))

    atlas.setFilterFeatures(True)
    atlas.setFilterExpression(feature_filter)

    if not scales and layout.referenceMap().atlasScalingMode(
    ) == QgsLayoutItemMap.Predefined:
        if Qgis.QGIS_VERSION_INT >= 30900:
            use_project = project.useProjectScales()
            map_scales = project.mapScales()
        else:
            map_scales = project_scales(project)
            use_project = len(map_scales) == 0

        if not use_project or len(map_scales) == 0:
            QgsMessageLog.logMessage(
                'Map scales not found in project, fetching predefined map scales in global config',
                'atlasprint', Qgis.Info)
            map_scales = global_scales()

        if Qgis.QGIS_VERSION_INT >= 30900:
            settings.predefinedMapScales = map_scales
        else:
            layout.reportContext().setPredefinedScales(map_scales)

    export_path = os.path.join(tempfile.gettempdir(),
                               '{}_{}.pdf'.format(layout_name, uuid4()))
    exporter = QgsLayoutExporter(layout)
    result = exporter.exportToPdf(atlas, export_path, settings)

    if result[0] != QgsLayoutExporter.Success and not os.path.isfile(
            export_path):
        raise Exception('export not generated {}'.format(export_path))

    return export_path
Beispiel #39
0
def print_layout(project,
                 layout_name,
                 feature_filter: str = None,
                 scales=None,
                 scale=None,
                 **kwargs):
    """Generate a PDF for an atlas or a report.

    :param project: The QGIS project.
    :type project: QgsProject

    :param layout_name: Name of the layout of the atlas or report.
    :type layout_name: basestring

    :param feature_filter: QGIS Expression to use to select the feature.
    It can return many features, a multiple pages PDF will be returned.
    This is required to print atlas, not report
    :type feature_filter: basestring

    :param scale: A scale to force in the atlas context. Default to None.
    :type scale: int

    :param scales: A list of predefined list of scales to force in the atlas context.
    Default to None.
    :type scales: list

    :return: Path to the PDF.
    :rtype: basestring
    """
    canvas = QgsMapCanvas()
    bridge = QgsLayerTreeMapCanvasBridge(project.layerTreeRoot(), canvas)
    bridge.setCanvasLayers()
    manager = project.layoutManager()
    master_layout = manager.layoutByName(layout_name)
    settings = QgsLayoutExporter.PdfExportSettings()

    atlas = None
    atlas_layout = None
    report_layout = None

    logger = Logger()

    if not master_layout:
        raise AtlasPrintException('Layout `{}` not found'.format(layout_name))

    if master_layout.layoutType() == QgsMasterLayoutInterface.PrintLayout:
        for _print_layout in manager.printLayouts():
            if _print_layout.name() == layout_name:
                atlas_layout = _print_layout
                break

        atlas = atlas_layout.atlas()
        if not atlas.enabled():
            raise AtlasPrintException('The layout is not enabled for an atlas')

        layer = atlas.coverageLayer()

        if feature_filter is None:
            raise AtlasPrintException(
                'EXP_FILTER is mandatory to print an atlas layout')

        feature_filter = optimize_expression(layer, feature_filter)

        expression = QgsExpression(feature_filter)
        if expression.hasParserError():
            raise AtlasPrintException(
                'Expression is invalid, parser error: {}'.format(
                    expression.parserErrorString()))

        context = QgsExpressionContext()
        context.appendScope(QgsExpressionContextUtils.globalScope())
        context.appendScope(QgsExpressionContextUtils.projectScope(project))
        context.appendScope(
            QgsExpressionContextUtils.layoutScope(atlas_layout))
        context.appendScope(QgsExpressionContextUtils.atlasScope(atlas))
        context.appendScope(QgsExpressionContextUtils.layerScope(layer))
        expression.prepare(context)
        if expression.hasEvalError():
            raise AtlasPrintException(
                'Expression is invalid, eval error: {}'.format(
                    expression.evalErrorString()))

        atlas.setFilterFeatures(True)
        atlas.setFilterExpression(feature_filter)

        if scale:
            atlas_layout.referenceMap().setAtlasScalingMode(
                QgsLayoutItemMap.Fixed)
            atlas_layout.referenceMap().setScale(scale)

        if scales:
            atlas_layout.referenceMap().setAtlasScalingMode(
                QgsLayoutItemMap.Predefined)
            if Qgis.QGIS_VERSION_INT >= 30900:
                settings.predefinedMapScales = scales
            else:
                atlas_layout.reportContext().setPredefinedScales(scales)

        if not scales and atlas_layout.referenceMap().atlasScalingMode(
        ) == QgsLayoutItemMap.Predefined:
            if Qgis.QGIS_VERSION_INT >= 30900:
                use_project = project.useProjectScales()
                map_scales = project.mapScales()
            else:
                map_scales = project_scales(project)
                use_project = len(map_scales) == 0

            if not use_project or len(map_scales) == 0:
                logger.info(
                    'Map scales not found in project, fetching predefined map scales in global config'
                )
                map_scales = global_scales()

            if Qgis.QGIS_VERSION_INT >= 30900:
                settings.predefinedMapScales = map_scales
            else:
                atlas_layout.reportContext().setPredefinedScales(map_scales)

    elif master_layout.layoutType() == QgsMasterLayoutInterface.Report:
        report_layout = master_layout

    else:
        raise AtlasPrintException('The layout is not supported by the plugin')

    for key, value in kwargs.items():
        found = False
        if atlas_layout:
            item = atlas_layout.itemById(key.lower())
            if isinstance(item, QgsLayoutItemLabel):
                item.setText(value)
                found = True
        logger.info(
            'Additional parameters: {} found in layout {}, value {}'.format(
                key, found, value))

    export_path = os.path.join(tempfile.gettempdir(),
                               '{}_{}.pdf'.format(layout_name, uuid4()))
    result, error = QgsLayoutExporter.exportToPdf(atlas or report_layout,
                                                  export_path, settings)

    if result != QgsLayoutExporter.Success and not os.path.isfile(export_path):
        raise Exception('export not generated {} ({})'.format(
            export_path, error))

    return export_path
Beispiel #40
0
    def fetchResults(self, search, context, feedback):

        self.info('search {}'.format(search))

        if len(search) < 3:
            return

        if search in 'tomtom ':
            return

        project = QgsProject.instance()
        try:
            key = QgsExpressionContextUtils.projectScope(project).variable(
                'tomtom_api_key').strip()
        except:
            #QgsExpressionContextUtils.setProjectVariable(project, 'tomtom_api_key', '')
            self.info('Add tomtom_api_key variable to your project')
            key = ''
            return

        # End with a space to trigger a search:
        #if search[-1] != ' ':
        #    return

        url = '{}{}'.format(self.SEARCH_URL, search.strip())
        url = url + '.json?'
        url = url + '&key=' + key
        url = url + '&idxSet=POI,Geo,Addr,PAD,Str,Xstr'
        self.info('Search url {}'.format(url))
        nam = NetworkAccessManager()
        try:
            # use BLOCKING request, as fetchResults already has it's own thread!
            (response, content) = nam.request(url, blocking=True)
            #self.info(response)
            #self.info(response.status_code)
            if response.status_code == 200:  # other codes are handled by NetworkAccessManager
                content_string = content.decode('utf-8')
                locations = json.loads(content_string)
                for loc in locations['results']:
                    result = QgsLocatorResult()
                    result.filter = self
                    if loc['type'] == 'Geography':
                        loc_type = loc['entityType']
                    else:
                        loc_type = loc['type']

                    if loc['type'] == 'Geography':
                        loc_display = loc['address'][
                            'freeformAddress'] + ', ' + loc['address'][
                                'country']
                    elif loc['type'] == 'Street' or loc[
                            'type'] == 'Cross Street':
                        loc_display = loc['address']['streetName'] + ', ' + loc[
                            'address']['municipality'] + ', ' + loc['address'][
                                'country']
                    elif loc['type'] == 'POI':
                        if loc['poi'].get('brands'):
                            loc_display = loc['poi']['brands'][0][
                                'name'] + ' ' + loc['poi'][
                                    'name'] + ' - ' + loc['address'][
                                        'municipality'] + ', ' + loc[
                                            'address']['country']
                        else:
                            loc_display = loc['poi']['name'] + ' - ' + loc[
                                'address']['municipality'] + ', ' + loc[
                                    'address']['country']
                    else:
                        loc_display = loc['address'][
                            'freeformAddress'] + ', ' + loc['address'][
                                'country']

                    result.displayString = '{} ({})'.format(
                        loc_display, loc_type)
                    # use the json full item as userData, so all info is in it:
                    result.userData = loc
                    self.resultFetched.emit(result)

        except RequestsException as err:
            # Handle exception..
            # only this one seems to work
            self.info(err)
            # THIS: results in a floating window with a warning in it, wrong thread/parent?
            #self.iface.messageBar().pushWarning("TomTomLocatorFilter Error", '{}'.format(err))
            # THIS: emitting the signal here does not work either?
            self.resultProblem.emit('{}'.format(err))
    def processAlgorithm(self, parameters, context, feedback):
        # parameters
        # Database connection parameters
        connection_name = QgsExpressionContextUtils.projectScope(
            context.project()).variable('gobs_connection_name')
        if not connection_name:
            connection_name = os.environ.get("GOBS_CONNECTION_NAME")

        spatiallayer = self.SPATIALLAYERS[parameters[self.SPATIALLAYER]]
        sourcelayer = self.parameterAsVectorLayer(parameters, self.SOURCELAYER,
                                                  context)
        uniqueid = self.parameterAsString(parameters, self.UNIQUEID, context)
        uniquelabel = self.parameterAsString(parameters, self.UNIQUELABEL,
                                             context)
        date_validity_min = self.parameterAsString(parameters,
                                                   self.DATE_VALIDITY_MIN,
                                                   context)
        manual_date_validity_min = self.parameterAsString(
            parameters, self.MANUAL_DATE_VALIDITY_MIN, context)
        date_validity_max = self.parameterAsString(parameters,
                                                   self.DATE_VALIDITY_MAX,
                                                   context)
        manual_date_validity_max = self.parameterAsString(
            parameters, self.MANUAL_DATE_VALIDITY_MAX, context)

        msg = ''
        status = 1

        # Get chosen spatial layer id
        id_spatial_layer = spatiallayer.split('-')[-1].strip()
        feedback.pushInfo(
            tr('CHECK COMPATIBILITY BETWEEN SOURCE AND TARGET GEOMETRY TYPES'))
        # Get spatial layer geometry type
        sql = '''
        SELECT sl_geometry_type
        FROM gobs.spatial_layer
        WHERE id = {0}
        LIMIT 1
        '''.format(id_spatial_layer)
        target_type = None
        [header, data, rowCount, ok,
         error_message] = fetchDataFromSqlQuery(connection_name, sql)
        if not ok:
            status = 0
            msg = tr('* The following error has been raised'
                     ) + '  %s' % error_message
            feedback.reportError(msg)
            raise QgsProcessingException(msg)
        else:
            for line in data:
                target_type = line[0].lower()

        # Check multi type
        target_is_multi = target_type.startswith('multi')

        # Get vector layer geometry type
        # And compare it with the spatial_layer type
        source_type = QgsWkbTypes.geometryDisplayString(
            int(sourcelayer.geometryType())).lower()
        source_wtype = QgsWkbTypes.displayString(int(
            sourcelayer.wkbType())).lower()
        ok = True
        if not target_type.endswith(source_type):
            ok = False
            msg = tr(
                'Source vector layer and target spatial layer do not have compatible geometry types'
            )
            msg += ' - SOURCE: {}, TARGET: {}'.format(source_type, target_type)
            feedback.pushInfo(msg)
            raise QgsProcessingException(msg)

        source_is_multi = source_wtype.startswith('multi')

        # Cannot import multi type into single type target spatial layer
        if source_is_multi and not target_is_multi:
            ok = False
            msg = tr(
                'Cannot import a vector layer with multi geometries into a target spatial layer with a simple geometry type defined'
            )
            msg += ' - SOURCE: {}, TARGET: {}'.format(source_wtype,
                                                      target_type)
            feedback.pushInfo(msg)
            raise QgsProcessingException(msg)

        # Import data to temporary table
        feedback.pushInfo(tr('IMPORT SOURCE LAYER INTO TEMPORARY TABLE'))
        temp_schema = 'public'
        temp_table = 'temp_' + str(time.time()).replace('.', '')
        processing.run("qgis:importintopostgis", {
            'INPUT': parameters[self.SOURCELAYER],
            'DATABASE': connection_name,
            'SCHEMA': temp_schema,
            'TABLENAME': temp_table,
            'PRIMARY_KEY': 'gobs_id',
            'GEOMETRY_COLUMN': 'geom',
            'ENCODING': 'UTF-8',
            'OVERWRITE': True,
            'CREATEINDEX': False,
            'LOWERCASE_NAMES': False,
            'DROP_STRING_LENGTH': True,
            'FORCE_SINGLEPART': False
        },
                       context=context,
                       feedback=feedback)
        feedback.pushInfo(
            tr('* Source layer has been imported into temporary table'))
        # Add ST_Multi if needed
        st_multi_left = ''
        st_multi_right = ''
        if target_is_multi:
            st_multi_left = 'ST_Multi('
            st_multi_right = ')'

        # Get target geometry type in integer
        geometry_type_integer = 1
        if target_type.replace('multi', '') == 'linestring':
            geometry_type_integer = 2
        if target_type.replace('multi', '') == 'polygon':
            geometry_type_integer = 3

        # Format validity timestamp fields
        if manual_date_validity_min.strip():
            manualdate = manual_date_validity_min.strip().replace('/', '-')
            casted_timestamp_min = '''
                '{0}'::timestamp
            '''.format(manualdate)
        else:
            casted_timestamp_min = '''
                s."{0}"::timestamp
            '''.format(date_validity_min)

        has_max_validity = False
        if manual_date_validity_max.strip() or date_validity_max:
            has_max_validity = True
            if manual_date_validity_max.strip():
                manualdate = manual_date_validity_max.strip().replace('/', '-')
                casted_timestamp_max = '''
                    '{0}'::timestamp
                '''.format(manualdate)
            else:
                casted_timestamp_max = '''
                    s."{0}"::timestamp
                '''.format(date_validity_max)

        # Copy data to spatial_object
        feedback.pushInfo(tr('COPY IMPORTED DATA TO spatial_object'))
        sql = '''
            INSERT INTO gobs.spatial_object (
                so_unique_id, so_unique_label,
                geom, fk_id_spatial_layer,
                so_valid_from
            '''
        if has_max_validity:
            sql += ', so_valid_to'
        sql += '''
            )
            SELECT "{so_unique_id}", "{so_unique_label}", {st_multi_left}ST_Transform(ST_CollectionExtract(ST_MakeValid(geom),{geometry_type_integer}), 4326){st_multi_right} AS geom, {id_spatial_layer},
            {casted_timestamp_min}
        '''.format(so_unique_id=uniqueid,
                   so_unique_label=uniquelabel,
                   st_multi_left=st_multi_left,
                   geometry_type_integer=geometry_type_integer,
                   st_multi_right=st_multi_right,
                   id_spatial_layer=id_spatial_layer,
                   casted_timestamp_min=casted_timestamp_min)
        if has_max_validity:
            sql += ', {casted_timestamp_max}'.format(
                casted_timestamp_max=casted_timestamp_max)
        sql += '''
            FROM "{temp_schema}"."{temp_table}" AS s

            -- Update line if data already exists
            -- i.e. Same external ids for the same layer and the same start validity date
            -- so_unique_id, fk_id_spatial_layer AND so_valid_from are the same
            -- This is considered as the same object as the one already in database
            -- We update the geometry, label, and end date of validity
            ON CONFLICT
                ON CONSTRAINT spatial_object_unique_key
            DO UPDATE
            SET (geom, so_unique_label, so_valid_to) = (EXCLUDED.geom, EXCLUDED.so_unique_label, EXCLUDED.so_valid_to)
            WHERE True
            ;

        '''.format(temp_schema=temp_schema, temp_table=temp_table)

        try:
            [header, data, rowCount, ok,
             error_message] = fetchDataFromSqlQuery(connection_name, sql)
            if not ok:
                status = 0
                msg = tr('* The following error has been raised'
                         ) + '  %s' % error_message
                feedback.reportError(msg)
                feedback.pushInfo(sql)
            else:
                status = 1
                msg = tr('* Source data has been successfully imported !')
                feedback.pushInfo(msg)
        except Exception as e:
            status = 0
            msg = tr(
                '* An unknown error occured while adding features to spatial_object table'
            )
            msg += ' ' + str(e)

        # Check there is no issues with related observation data
        # For each series related to the chosen spatial layer
        # SELECT gobs.find_observation_with_wrong_spatial_object({fk_id_series})
        # v1/ Only check and display warning
        # v2/ Check and try to update with gobs.update_observations_with_wrong_spatial_objects
        # v3/ Find orphans

        # Remove temporary table
        feedback.pushInfo(tr('DROP TEMPORARY DATA'))
        sql = '''
            DROP TABLE IF EXISTS "%s"."%s"
        ;
        ''' % (temp_schema, temp_table)
        [header, data, rowCount, ok,
         error_message] = fetchDataFromSqlQuery(connection_name, sql)
        if ok:
            feedback.pushInfo(tr('* Temporary data has been deleted.'))
        else:
            feedback.reportError(
                tr('* An error occured while droping temporary table') +
                ' "%s"."%s"' % (temp_schema, temp_table))

        msg = tr('SPATIAL LAYER HAS BEEN SUCCESSFULLY IMPORTED !')

        return {self.OUTPUT_STATUS: status, self.OUTPUT_STRING: msg}
    def virtualFields(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
        """
        layer_name = params.get('LAYER', '')
        if not layer_name:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'VirtualFields' REQUEST: LAYER parameter is mandatory",
                400)

        # get layer
        layer = find_vector_layer(layer_name, project)
        # layer not found
        if not layer:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid LAYER parameter for 'VirtualFields': {} provided".format(layer_name),
                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
        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
        with_geom = params.get('WITH_GEOMETRY', '').lower() in ['true', '1', 't']
        if not with_geom:
            req.setFlags(QgsFeatureRequest.NoGeometry)

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

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

        json_exporter = QgsJsonExporter(layer)
        if attribute_list:
            json_exporter.setAttributes(attribute_list)

        separator = ''
        for feat in layer.getFeatures(req):
            fid = layer_name + '.' + get_server_fid(feat, pk_attributes)

            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 + json_exporter.exportFeature(feat, extra, fid))
            response.flush()
            separator = ',\n'
        response.write(']}')
        return
Beispiel #43
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)
        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 = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(QgsExpressionContextUtils.projectScope())
        exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer))

        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())

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

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

        # Create output vector layer with new attributes
        error = ''
        calculationSuccess = True
        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():
                    calculationSuccess = False
                    error = expression.evalErrorString()
                    break

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

            writer.addFeature(outFeat)

            progress.setPercentage(int(current * total))

        del writer

        if not calculationSuccess:
            raise GeoAlgorithmExecutionException(
                self.tr('An error occurred while evaluating the calculation'
                        ' string:\n') + error)
Beispiel #44
0
def getProjectVariable(project, variable):
    if (project is not None):
        scope = QgsExpressionContextUtils.projectScope(project)
        return scope.variable(variable)
    else:
        return None
Beispiel #45
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)
        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 = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(QgsExpressionContextUtils.projectScope())
        exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer))

        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())

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

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

        # Create output vector layer with new attributes
        error = ''
        calculationSuccess = True
        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():
                    calculationSuccess = False
                    error = expression.evalErrorString()
                    break

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

            writer.addFeature(outFeat)

            progress.setPercentage(int(current * total))

        del writer

        if not calculationSuccess:
            raise GeoAlgorithmExecutionException(
                self.tr('An error occurred while evaluating the calculation'
                        ' string:\n') + error)
Beispiel #46
0
    def testHomePath(self):
        p = QgsProject()
        path_changed_spy = QSignalSpy(p.homePathChanged)
        self.assertFalse(p.homePath())
        self.assertFalse(p.presetHomePath())

        # simulate save file
        tmp_dir = QTemporaryDir()
        tmp_file = "{}/project.qgs".format(tmp_dir.path())
        with open(tmp_file, 'w') as f:
            pass
        p.setFileName(tmp_file)

        # home path should be file path
        self.assertEqual(p.homePath(), tmp_dir.path())
        self.assertFalse(p.presetHomePath())
        self.assertEqual(len(path_changed_spy), 1)

        # manually override home path
        p.setPresetHomePath('/tmp/my_path')
        self.assertEqual(p.homePath(), '/tmp/my_path')
        self.assertEqual(p.presetHomePath(), '/tmp/my_path')
        self.assertEqual(len(path_changed_spy), 2)
        # check project scope
        scope = QgsExpressionContextUtils.projectScope(p)
        self.assertEqual(scope.variable('project_home'), '/tmp/my_path')

        # no extra signal if path is unchanged
        p.setPresetHomePath('/tmp/my_path')
        self.assertEqual(p.homePath(), '/tmp/my_path')
        self.assertEqual(p.presetHomePath(), '/tmp/my_path')
        self.assertEqual(len(path_changed_spy), 2)

        # setting file name should not affect home path is manually set
        tmp_file_2 = "{}/project/project2.qgs".format(tmp_dir.path())
        os.mkdir(tmp_dir.path() + '/project')
        with open(tmp_file_2, 'w') as f:
            pass
        p.setFileName(tmp_file_2)
        self.assertEqual(p.homePath(), '/tmp/my_path')
        self.assertEqual(p.presetHomePath(), '/tmp/my_path')
        self.assertEqual(len(path_changed_spy), 2)

        scope = QgsExpressionContextUtils.projectScope(p)
        self.assertEqual(scope.variable('project_home'), '/tmp/my_path')

        # clear manual path
        p.setPresetHomePath('')
        self.assertEqual(p.homePath(), tmp_dir.path() + '/project')
        self.assertFalse(p.presetHomePath())
        self.assertEqual(len(path_changed_spy), 3)

        scope = QgsExpressionContextUtils.projectScope(p)
        self.assertEqual(scope.variable('project_home'), tmp_dir.path() + '/project')

        # relative path
        p.setPresetHomePath('../home')
        self.assertEqual(p.homePath(), tmp_dir.path() + '/home')
        self.assertEqual(p.presetHomePath(), '../home')
        self.assertEqual(len(path_changed_spy), 4)

        scope = QgsExpressionContextUtils.projectScope(p)
        self.assertEqual(scope.variable('project_home'), tmp_dir.path() + '/home')

        # relative path, no filename
        p.setFileName('')
        self.assertEqual(p.homePath(), '../home')
        self.assertEqual(p.presetHomePath(), '../home')

        scope = QgsExpressionContextUtils.projectScope(p)
        self.assertEqual(scope.variable('project_home'), '../home')
    def checkParameterValues(self, parameters, context):

        # Check that the connection name has been configured
        connection_name = QgsExpressionContextUtils.projectScope(
            context.project()).variable('gobs_connection_name')
        connection_name_env = os.environ.get("GOBS_CONNECTION_NAME")
        if not connection_name and not connection_name_env:
            return False, tr(
                'You must use the "Configure G-obs plugin" alg to set the database connection name'
            )

        # Check that it corresponds to an existing connection
        if connection_name and connection_name not in getPostgisConnectionList(
        ):
            return False, tr(
                'The configured connection name does not exists in QGIS')

        # replace connection_name by env variable
        if not connection_name:
            connection_name = connection_name_env

        # Check correct validity timestamps have been given
        date_fields = {
            'Start of validity': {
                'field': self.DATE_VALIDITY_MIN,
                'manual': self.MANUAL_DATE_VALIDITY_MIN,
                'optional': False
            },
            'End of validity': {
                'field': self.DATE_VALIDITY_MAX,
                'manual': self.MANUAL_DATE_VALIDITY_MAX,
                'optional': True
            }
        }
        for key in date_fields:
            ok = True
            item = date_fields[key]
            field_timestamp = self.parameterAsString(parameters, item['field'],
                                                     context)
            manualdate = (self.parameterAsString(parameters, item['manual'],
                                                 context)).strip().replace(
                                                     '/', '-')
            if not field_timestamp and not manualdate and not item['optional']:
                ok = False
                msg = tr(key) + ' - '
                msg += tr(
                    'You need to enter either a timestamp field or a manual timestamp'
                )

            # check validity of given manual date
            if manualdate:
                ok, msg = validateTimestamp(manualdate)
                if not ok:
                    return False, tr(key) + ' - ' + msg
                ok = True

            if not ok:
                return False, msg

        return super(ImportSpatialLayerData,
                     self).checkParameterValues(parameters, context)
    def replace_expression_text(params: Dict[str, str], response: QgsServerResponse, project: QgsProject) -> None:
        """ Replace expression texts against layer or features
        In parameters:
            LAYER=wms-layer-name
            STRING=A string with expression between [% and %]
            or
            STRINGS=["first string with expression", "second string with expression"]
            or
            STRINGS={"key1": "first string with expression", "key2": "second string with 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 'ReplaceExpressionText' REQUEST: LAYER parameter is mandatory",
                400)

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

        # get strings
        strings = params.get('STRINGS', '')
        if not strings:
            the_string = params.get('STRING', '')
            if not the_string:
                raise ExpressionServiceError(
                    "Bad request error",
                    "Invalid 'ReplaceExpressionText' REQUEST: STRING or STRINGS parameter is mandatory",
                    400)
            strings = '["{}"]'.format(the_string)

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

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

        # 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())

        # organized strings
        str_map = {}
        str_items = []
        if isinstance(str_json, list):
            str_items = enumerate(str_json)
        elif isinstance(str_json, dict):
            str_items = str_json.items()
        for k, s in str_items:
            str_map[k] = s

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

        # without features just replace expression string with layer context
        if not features:
            result = {}
            for k, s in str_map.items():
                value = QgsExpression.replaceExpressionText(s, exp_context, da)
                result[k] = json.loads(QgsJsonUtils.encodeValue(value))
            body['results'].append(result)
            write_json_response(body, response)
            return

        # Check features
        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 'ReplaceExpressionText': 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
        add_form_scope = params.get('FORM_SCOPE', '').lower() in ['true', '1', 't']

        # loop through provided features to replace expression strings
        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():
                field_name = field.name()
                if feat_fields.indexOf(field_name) != -1:
                    feat.setAttribute(field_name, f[field_name])

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

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

            # replace expression strings with the new feature
            result = {}
            for k, s in str_map.items():
                value = QgsExpression.replaceExpressionText(s, exp_context, da)
                result[k] = json.loads(QgsJsonUtils.encodeValue(value))
            body['results'].append(result)

        write_json_response(body, response)
        return
    def get_feature_with_form_scope(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
        """
        layer_name = params.get('LAYER', '')
        if not layer_name:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'GetFeatureWithFormScope' REQUEST: LAYER parameter is mandatory",
                400)

        # get layer
        layer = find_vector_layer(layer_name, project)
        # layer not found
        if not layer:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid LAYER parameter for 'VirtualField': {} provided".format(layer_name),
                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
        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
        with_geom = params.get('WITH_GEOMETRY', '').lower() in ['true', '1', 't']
        if not with_geom:
            req.setFlags(QgsFeatureRequest.NoGeometry)

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

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

        json_exporter = QgsJsonExporter(layer)
        if attribute_list:
            json_exporter.setAttributes(attribute_list)

        separator = ''
        for feat in layer.getFeatures(req):
            fid = layer_name + '.' + get_server_fid(feat, pk_attributes)
            response.write(separator + json_exporter.exportFeature(feat, {}, fid))
            response.flush()
            separator = ',\n'
        response.write(']}')
        return
Beispiel #50
0
    def photoDetails_field(self, restrictionDialog, currRestrictionLayer,
                           currRestriction):

        # Function to deal with photo fields

        self.demandDialog = restrictionDialog
        self.currDemandLayer = currRestrictionLayer
        self.currFeature = currRestriction

        TOMsMessageLog.logMessage("gnns: In photoDetails", level=Qgis.Info)

        photoPath = QgsExpressionContextUtils.projectScope(
            QgsProject.instance()).variable('PhotoPath')
        #path_absolute = photoPath

        projectFolder = QgsExpressionContextUtils.projectScope(
            QgsProject.instance()).variable('project_home')

        path_absolute = os.path.join(projectFolder, photoPath)

        if path_absolute == None:
            reply = QMessageBox.information(None, "Information",
                                            "Please set value for PhotoPath.",
                                            QMessageBox.Ok)
            return

        # Check path exists ...
        if os.path.isdir(path_absolute) == False:
            reply = QMessageBox.information(
                None, "Information", "PhotoPath folder " + str(path_absolute) +
                " does not exist. Please check value.", QMessageBox.Ok)
            return

        # if cv2 is available, check camera nr
        try:
            cameraNr = int(self.params.setParam("CameraNr"))
        except Exception as e:
            TOMsMessageLog.logMessage(
                "In photoDetails_field: cameraNr issue: {}".format(e),
                level=Qgis.Info)
            if cv2_available:
                cameraNr = QMessageBox.information(
                    None, "Information", "Please set value for CameraNr.",
                    QMessageBox.Ok)
            cameraNr = None

        TOMsMessageLog.logMessage(
            "In photoDetails_field: cameraNr is: {}".format(cameraNr),
            level=Qgis.Info)

        # get image resolution

        frameWidth, frameHeight = self.getCameraResolution()
        TOMsMessageLog.logMessage(
            "In gnns: In photoDetails: ... resolution: {}*{} ".format(
                frameWidth, frameHeight),
            level=Qgis.Warning)

        layerName = self.currDemandLayer.name()

        # Generate the full path to the file

        fileName1 = "Photos_01"
        fileName2 = "Photos_02"
        fileName3 = "Photos_03"

        idx1 = self.currDemandLayer.fields().indexFromName(fileName1)
        idx2 = self.currDemandLayer.fields().indexFromName(fileName2)
        idx3 = self.currDemandLayer.fields().indexFromName(fileName3)

        TOMsMessageLog.logMessage("In photoDetails. idx1: " + str(idx1) +
                                  "; " + str(idx2) + "; " + str(idx3),
                                  level=Qgis.Info)

        if cameraNr is not None:
            TOMsMessageLog.logMessage("Camera TRUE", level=Qgis.Info)
            takePhoto = True
        else:
            TOMsMessageLog.logMessage("Camera FALSE", level=Qgis.Info)
            takePhoto = False

        FIELD1 = self.demandDialog.findChild(QLabel, "Photo_Widget_01")
        FIELD2 = self.demandDialog.findChild(QLabel, "Photo_Widget_02")
        FIELD3 = self.demandDialog.findChild(QLabel, "Photo_Widget_03")

        if FIELD1:

            TOMsMessageLog.logMessage("In photoDetails. FIELD 1 exists",
                                      level=Qgis.Info)
            if self.currFeature[idx1]:
                newPhotoFileName1 = os.path.join(path_absolute,
                                                 self.currFeature[idx1])
                TOMsMessageLog.logMessage(
                    "In photoDetails. photo1: {}".format(newPhotoFileName1),
                    level=Qgis.Info)
            else:
                newPhotoFileName1 = None

            pixmap1 = QPixmap(newPhotoFileName1)

            tab = FIELD1.parentWidget()
            grid = FIELD1.parentWidget().layout()

            photo_Widget1 = imageLabel(tab)
            TOMsMessageLog.logMessage(
                "In photoDetails. FIELD 1 w: {}; h: {}".format(
                    FIELD1.width(), FIELD1.height()),
                level=Qgis.Info)
            photo_Widget1.setObjectName("Photo_Widget_01")
            photo_Widget1.setText("No photo is here")
            #photo_Widget1 = imageLabel(tab)
            grid.addWidget(photo_Widget1, 0, 0, 1, 1)

            FIELD1.hide()
            FIELD1.setParent(None)
            FIELD1 = photo_Widget1
            FIELD1.set_Pixmap(pixmap1)

            TOMsMessageLog.logMessage("In photoDetails. FIELD 1 Photo1: " +
                                      str(newPhotoFileName1),
                                      level=Qgis.Info)
            TOMsMessageLog.logMessage(
                "In photoDetails.pixmap1 size: {}".format(pixmap1.size()),
                level=Qgis.Info)

            FIELD1.pixmapUpdated.connect(
                functools.partial(self.displayPixmapUpdated, FIELD1))

            if takePhoto:
                START_CAMERA_1 = self.demandDialog.findChild(
                    QPushButton, "startCamera1")
                TAKE_PHOTO_1 = self.demandDialog.findChild(
                    QPushButton, "getPhoto1")
                TAKE_PHOTO_1.setEnabled(False)

                self.camera1 = formCamera(path_absolute, newPhotoFileName1,
                                          cameraNr, frameWidth, frameHeight)
                START_CAMERA_1.clicked.connect(
                    functools.partial(self.camera1.useCamera, START_CAMERA_1,
                                      TAKE_PHOTO_1, FIELD1))
                self.camera1.notifyPhotoTaken.connect(
                    functools.partial(self.savePhotoTaken, idx1))
                self.camera1.pixmapUpdated.connect(
                    functools.partial(self.displayImage, FIELD1))

        if FIELD2:
            TOMsMessageLog.logMessage("In photoDetails. FIELD 2 exisits",
                                      level=Qgis.Info)
            if self.currFeature[idx2]:
                newPhotoFileName2 = os.path.join(path_absolute,
                                                 self.currFeature[idx2])
                TOMsMessageLog.logMessage("In photoDetails. Photo1: " +
                                          str(newPhotoFileName2),
                                          level=Qgis.Info)
            else:
                newPhotoFileName2 = None

            pixmap2 = QPixmap(newPhotoFileName2)

            tab = FIELD2.parentWidget()
            grid = FIELD2.parentWidget().layout()

            photo_Widget2 = imageLabel(tab)
            TOMsMessageLog.logMessage(
                "In photoDetails. FIELD 2 w: {}; h: {}".format(
                    FIELD2.width(), FIELD2.height()),
                level=Qgis.Info)
            photo_Widget2.setObjectName("Photo_Widget_02")
            photo_Widget2.setText("No photo is here")
            #photo_Widget2 = imageLabel(tab)
            grid.addWidget(photo_Widget2, 0, 0, 1, 1)

            FIELD2.hide()
            FIELD2.setParent(None)
            FIELD2 = photo_Widget2
            FIELD2.set_Pixmap(pixmap2)

            TOMsMessageLog.logMessage("In photoDetails. FIELD 2 Photo2: " +
                                      str(newPhotoFileName2),
                                      level=Qgis.Info)
            TOMsMessageLog.logMessage(
                "In photoDetails.pixmap2 size: {}".format(pixmap2.size()),
                level=Qgis.Info)

            FIELD2.pixmapUpdated.connect(
                functools.partial(self.displayPixmapUpdated, FIELD2))

            if takePhoto:
                START_CAMERA_2 = self.demandDialog.findChild(
                    QPushButton, "startCamera2")
                TAKE_PHOTO_2 = self.demandDialog.findChild(
                    QPushButton, "getPhoto2")
                TAKE_PHOTO_2.setEnabled(False)

                self.camera2 = formCamera(path_absolute, newPhotoFileName2,
                                          cameraNr, frameWidth, frameHeight)
                START_CAMERA_2.clicked.connect(
                    functools.partial(self.camera2.useCamera, START_CAMERA_2,
                                      TAKE_PHOTO_2, FIELD2))
                self.camera2.notifyPhotoTaken.connect(
                    functools.partial(self.savePhotoTaken, idx2))
                self.camera2.pixmapUpdated.connect(
                    functools.partial(self.displayImage, FIELD2))

        if FIELD3:
            TOMsMessageLog.logMessage("In photoDetails. FIELD 3 exisits",
                                      level=Qgis.Info)

            if self.currFeature[idx3]:
                newPhotoFileName3 = os.path.join(path_absolute,
                                                 self.currFeature[idx3])
                TOMsMessageLog.logMessage("In photoDetails. Photo1: " +
                                          str(newPhotoFileName3),
                                          level=Qgis.Info)
            else:
                newPhotoFileName3 = None

            pixmap3 = QPixmap(newPhotoFileName3)

            tab = FIELD3.parentWidget()
            grid = FIELD3.parentWidget().layout()

            photo_Widget3 = imageLabel(tab)
            TOMsMessageLog.logMessage(
                "In photoDetails. FIELD 3 w: {}; h: {}".format(
                    FIELD3.width(), FIELD3.height()),
                level=Qgis.Info)
            photo_Widget3.setObjectName("Photo_Widget_03")
            photo_Widget3.setText("No photo is here")
            #photo_Widget3 = imageLabel(tab)
            grid.addWidget(photo_Widget3, 0, 0, 1, 1)

            FIELD3.hide()
            FIELD3.setParent(None)
            FIELD3 = photo_Widget3
            FIELD3.set_Pixmap(pixmap3)

            TOMsMessageLog.logMessage("In photoDetails. FIELD 3 Photo3: " +
                                      str(newPhotoFileName3),
                                      level=Qgis.Info)
            TOMsMessageLog.logMessage(
                "In photoDetails.pixmap3 size: {}".format(pixmap3.size()),
                level=Qgis.Info)

            FIELD3.pixmapUpdated.connect(
                functools.partial(self.displayPixmapUpdated, FIELD3))

            if takePhoto:
                START_CAMERA_3 = self.demandDialog.findChild(
                    QPushButton, "startCamera3")
                TAKE_PHOTO_3 = self.demandDialog.findChild(
                    QPushButton, "getPhoto3")
                TAKE_PHOTO_3.setEnabled(False)

                self.camera3 = formCamera(path_absolute, newPhotoFileName3,
                                          cameraNr, frameWidth, frameHeight)
                START_CAMERA_3.clicked.connect(
                    functools.partial(self.camera3.useCamera, START_CAMERA_3,
                                      TAKE_PHOTO_3, FIELD3))
                self.camera3.notifyPhotoTaken.connect(
                    functools.partial(self.savePhotoTaken, idx3))
                self.camera3.pixmapUpdated.connect(
                    functools.partial(self.displayImage, FIELD3))

        pass
Beispiel #51
0
    def __init__(self, path: str):
        super(UiBuilder, self).__init__()
        if not path:
            raise ValueError("path is None")

        self.prefix = "ve"
        self.var_format = "{0}_{1}"
        self.project = QgsProject.instance()
        self.user_ui = createClass(path)
        proj_variables = QgsExpressionContextUtils.projectScope(self.project)
        # signals and init variables
        ui_objs = self.user_ui.findChildren(QObject)
        for obj in ui_objs:
            name = obj.objectName()
            if name:
                var_name = self.var_format.format(self.prefix, name)
                if isinstance(obj, QCheckBox):
                    if var_name in proj_variables.variableNames():
                        try:
                            value = int(proj_variables.variable(var_name))
                        except ValueError:
                            value = 0
                        finally:
                            obj.setCheckState(value)
                    else:
                        self.store_variable(name, obj.checkState())

                    obj.stateChanged.connect(self.widget_connector)
                elif isinstance(obj, QComboBox):
                    if var_name in proj_variables.variableNames():
                        value = proj_variables.variable(var_name)
                        obj.setCurrentText(value)
                    else:
                        self.store_variable(name, obj.currentText())

                    obj.currentIndexChanged.connect(self.widget_connector)
                elif isinstance(obj, QAbstractSpinBox):
                    if var_name in proj_variables.variableNames():
                        value = proj_variables.variable(var_name)
                        obj.lineEdit().setText(value)
                    else:
                        self.store_variable(name, obj.text())

                    obj.editingFinished.connect(self.widget_connector)
                elif isinstance(obj, QLineEdit):
                    if var_name in proj_variables.variableNames():
                        value = proj_variables.variable(var_name)
                        obj.setText(value)
                    else:
                        self.store_variable(name, obj.text())

                    obj.editingFinished.connect(self.widget_connector)
                elif isinstance(obj, QAbstractSlider):
                    if var_name in proj_variables.variableNames():
                        try:
                            value = int(proj_variables.variable(var_name))
                        except ValueError:
                            value = 0
                        finally:
                            obj.setValue(value)
                    else:
                        self.store_variable(name, obj.value())

                    obj.valueChanged.connect(self.widget_connector)

        self.user_ui.show()
Beispiel #52
0
    def testHomePath(self):
        p = QgsProject()
        path_changed_spy = QSignalSpy(p.homePathChanged)
        self.assertFalse(p.homePath())
        self.assertFalse(p.presetHomePath())

        # simulate save file
        tmp_dir = QTemporaryDir()
        tmp_file = "{}/project.qgs".format(tmp_dir.path())
        with open(tmp_file, 'w') as f:
            pass
        p.setFileName(tmp_file)

        # home path should be file path
        self.assertEqual(p.homePath(), tmp_dir.path())
        self.assertFalse(p.presetHomePath())
        self.assertEqual(len(path_changed_spy), 1)

        # manually override home path
        p.setPresetHomePath('/tmp/my_path')
        self.assertEqual(p.homePath(), '/tmp/my_path')
        self.assertEqual(p.presetHomePath(), '/tmp/my_path')
        self.assertEqual(len(path_changed_spy), 2)
        # check project scope
        scope = QgsExpressionContextUtils.projectScope(p)
        self.assertEqual(scope.variable('project_home'), '/tmp/my_path')

        # no extra signal if path is unchanged
        p.setPresetHomePath('/tmp/my_path')
        self.assertEqual(p.homePath(), '/tmp/my_path')
        self.assertEqual(p.presetHomePath(), '/tmp/my_path')
        self.assertEqual(len(path_changed_spy), 2)

        # setting file name should not affect home path is manually set
        tmp_file_2 = "{}/project/project2.qgs".format(tmp_dir.path())
        os.mkdir(tmp_dir.path() + '/project')
        with open(tmp_file_2, 'w') as f:
            pass
        p.setFileName(tmp_file_2)
        self.assertEqual(p.homePath(), '/tmp/my_path')
        self.assertEqual(p.presetHomePath(), '/tmp/my_path')
        self.assertEqual(len(path_changed_spy), 2)

        scope = QgsExpressionContextUtils.projectScope(p)
        self.assertEqual(scope.variable('project_home'), '/tmp/my_path')

        # clear manual path
        p.setPresetHomePath('')
        self.assertEqual(p.homePath(), tmp_dir.path() + '/project')
        self.assertFalse(p.presetHomePath())
        self.assertEqual(len(path_changed_spy), 3)

        scope = QgsExpressionContextUtils.projectScope(p)
        self.assertEqual(scope.variable('project_home'), tmp_dir.path() + '/project')

        # relative path
        p.setPresetHomePath('../home')
        self.assertEqual(p.homePath(), tmp_dir.path() + '/home')
        self.assertEqual(p.presetHomePath(), '../home')
        self.assertEqual(len(path_changed_spy), 4)

        scope = QgsExpressionContextUtils.projectScope(p)
        self.assertEqual(scope.variable('project_home'), tmp_dir.path() + '/home')

        # relative path, no filename
        p.setFileName('')
        self.assertEqual(p.homePath(), '../home')
        self.assertEqual(p.presetHomePath(), '../home')

        scope = QgsExpressionContextUtils.projectScope(p)
        self.assertEqual(scope.variable('project_home'), '../home')
Beispiel #53
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)

        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().srsid())
        da.setEllipsoidalMode(
            iface.mapCanvas().mapSettings().hasCrsTransformEnabled())
        da.setEllipsoid(QgsProject.instance().readEntry(
            'Measure', '/Ellipsoid', GEO_NONE)[0])
        exp.setGeomCalculator(da)
        exp.setDistanceUnits(QgsProject.instance().distanceUnits())
        exp.setAreaUnits(QgsProject.instance().areaUnits())

        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(QgsExpressionContextUtils.projectScope())
        exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer))

        if not exp.prepare(exp_context):
            raise GeoAlgorithmExecutionException(
                self.tr('Evaluation error: %s' % 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)

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

        if not calculationSuccess:
            raise GeoAlgorithmExecutionException(
                self.tr('An error occurred while evaluating the calculation '
                        'string:\n%s' % error))
Beispiel #54
0
    def populateMetadataItems(self, m, layout):
        """Get the current value of metadata items from the project or layout variable, and populate the Edit Metadata dialog
        See *updateVars* to populate variable values from th Edit Metadata UI
        """
        currProject = QgsProject.instance()
        # Check that all the variables exist, and if they don't, create them and give them a default value where appropriate
        with open(os.path.join(self.plugin_dir, "input/metadata_items.csv"),
                  'r') as metadata_file:
            reader = csv.reader(metadata_file, delimiter=',')
            metadata_list = list(reader)
        for x in metadata_list:
            ma_variable = str(x[0])
            elem_name = str(x[1])
            elem_name = elem_name.strip()
            ma_level = str(x[2])
            default_value = str(x[3])
            ma_level = ma_level.strip()
            # If project level variables don't exist, create them and populate with the default value
            if (ma_level == 'project'):
                if str(
                        QgsExpressionContextUtils.projectScope(
                            currProject).variable(ma_variable)) == 'None':
                    QgsExpressionContextUtils.setProjectVariable(
                        currProject, ma_variable, default_value)

        # Populate comboboxes
        # Populate values of Status combobox
        self.dlg.maStatus.addItem('New')
        self.dlg.maStatus.addItem('Correction')
        self.dlg.maStatus.addItem('Update')

        # Populate values of Access combobox
        self.dlg.maAccess.addItem('Public')
        self.dlg.maAccess.addItem('MapAction')
        self.dlg.maAccess.addItem('Selected partners')

        # Populate values of Language combobox
        self.dlg.maLanguage.addItem('English')
        self.dlg.maLanguage.addItem('French')
        self.dlg.maLanguage.addItem('Spanish')

        # Populate the Edit Metadata dialog with current values from variables
        for x in m:
            ma_variable = str(x[0])
            elem_name = str(x[1])
            elem_name = elem_name.strip()
            ma_level = str(x[2])
            ma_level = ma_level.strip()
            default_value = str(x[3])
            proj_crs = QgsProject.instance().crs()
            if (ma_level == 'project'):
                # Project: get current value for each variable from project and populate field
                if ma_variable == 'ma_country':
                    self.dlg.maCountry.setText(
                        str(
                            QgsExpressionContextUtils.projectScope(
                                currProject).variable(ma_variable)))
                elif ma_variable == 'ma_crs':
                    self.dlg.maCrs.setText(
                        str(
                            QgsCoordinateReferenceSystem(
                                proj_crs).description()))
                elif ma_variable == 'ma_glide_number':
                    self.dlg.maGlide.setText(
                        str(
                            QgsExpressionContextUtils.projectScope(
                                currProject).variable(ma_variable)))
                elif ma_variable == 'ma_organisation':
                    self.dlg.maOrganisation.setText(
                        str(
                            QgsExpressionContextUtils.projectScope(
                                currProject).variable(ma_variable)))
                elif ma_variable == 'ma_opid':
                    self.dlg.maOperationID.setText(
                        str(
                            QgsExpressionContextUtils.projectScope(
                                currProject).variable(ma_variable)))
                elif ma_variable == 'ma_sourceorg':
                    self.dlg.maSourceOrg.setText(
                        str(
                            QgsExpressionContextUtils.projectScope(
                                currProject).variable(ma_variable)))
                elif ma_variable == 'ma_acknowledgements':
                    self.dlg.maAcknowledgements.setText(
                        str(
                            QgsExpressionContextUtils.projectScope(
                                currProject).variable(ma_variable)))
                elif ma_variable == 'ma_disclaimer':
                    self.dlg.maDisclaimer.setText(
                        str(
                            QgsExpressionContextUtils.projectScope(
                                currProject).variable(ma_variable)))

            # Layout: Get the current value of the variable if it exists and populate the field
            elif (ma_level == 'layout'):
                for layout in QgsProject.instance().layoutManager(
                ).printLayouts():
                    # If the variable doesn't exist, create it
                    if layout.name() == self.dlg.layoutSelect.currentText():
                        if str(
                                QgsExpressionContextUtils.layoutScope(
                                    layout).variable(ma_variable)) == 'None':
                            QgsExpressionContextUtils.setLayoutVariable(
                                layout, ma_variable, default_value)
                        elif ma_variable == 'ma_map_number':
                            self.dlg.maMapNumber.setText(
                                str(
                                    QgsExpressionContextUtils.layoutScope(
                                        layout).variable(ma_variable)))
                        elif ma_variable == 'ma_summary':
                            self.dlg.maSummary.setText(
                                str(
                                    QgsExpressionContextUtils.layoutScope(
                                        layout).variable(ma_variable)))
                        elif ma_variable == 'ma_datasource':
                            self.dlg.maDatasource.setText(
                                str(
                                    QgsExpressionContextUtils.layoutScope(
                                        layout).variable(ma_variable)))
                        elif ma_variable == 'ma_title':
                            self.dlg.maTitle.setText(
                                str(
                                    QgsExpressionContextUtils.layoutScope(
                                        layout).variable(ma_variable)))
                        elif ma_variable == 'ma_version':
                            self.dlg.maVersion.setValue(
                                int(
                                    QgsExpressionContextUtils.layoutScope(
                                        layout).variable(ma_variable)))
                        elif ma_variable == 'ma_status':
                            self.dlg.maStatus.setCurrentText(
                                str(
                                    QgsExpressionContextUtils.layoutScope(
                                        layout).variable(ma_variable)))
                        elif ma_variable == 'ma_access':
                            self.dlg.maAccess.setCurrentText(
                                str(
                                    QgsExpressionContextUtils.layoutScope(
                                        layout).variable(ma_variable)))
                        elif ma_variable == 'ma_language':
                            self.dlg.maLanguage.setCurrentText(
                                str(
                                    QgsExpressionContextUtils.layoutScope(
                                        layout).variable(ma_variable)))
            else:
                # ACTION: update or remove this message
                QgsMessageLog.logMessage('Warning: level ' + str(ma_level),
                                         'MapExport')
Beispiel #55
0
    def exportLayout(self, cView, folder, title):
        """Function that sets how to export files."""
        currProject = QgsProject.instance()
        printer = QPrinter()
        painter = QPainter()
        exporter = QgsLayoutExporter(cView)
        # Set page progressbar maximum value
        self.dlg.pageBar.setValue(0)
        self.dlg.pageBar.setMaximum(11)
        # Do the export process
        if not os.path.exists(os.path.join(folder, title)):
            os.makedirs(os.path.join(folder, title))
        exporter.exportToPdf(os.path.join(folder, title, title + '.pdf'),
                             QgsLayoutExporter.PdfExportSettings())
        exporter.exportToImage(os.path.join(folder, title, title + '.jpg'),
                               QgsLayoutExporter.ImageExportSettings())

        # read CSV file & load into list
        with open(os.path.join(self.plugin_dir, "input/metadata_items.csv"),
                  'r') as metadata_file:
            reader = csv.reader(metadata_file, delimiter=',')
            metadata_list = list(reader)

        settings = ET.Element("mapdoc")
        mapdata = ET.SubElement(settings, "mapdata")

        # output fixed QGIS variables to XML
        """ACTION?"""

        # output project variables listed in CSV to XML
        for x in metadata_list:
            ma_variable = str(x[0])
            elem_name = str(x[1])
            elem_name = elem_name.strip()
            ma_level = str(x[2])
            ma_level = ma_level.strip()
            if (ma_level == 'project') and (elem_name != 'no_xml'):
                elem_value = str(
                    QgsExpressionContextUtils.projectScope(
                        currProject).variable(ma_variable))
                ET.SubElement(mapdata, elem_name).text = elem_value
                if elem_value.strip():
                    QgsMessageLog.logMessage(
                        ma_variable + ' exported as ' + elem_value,
                        'MapExport', Qgis.Info)
                else:
                    msgBar.pushMessage(
                        'Warning: missing value for ' + ma_variable, 5)
                    QgsMessageLog.logMessage(
                        'Warning: missing value for ' + ma_variable,
                        'MapExport')

        themes = ET.SubElement(mapdata, "themes")
        for theme in self.dlg.themeBox.findChildren(QCheckBox):
            if theme.isChecked():
                ET.SubElement(themes, 'theme').text = theme.text()

        for layout in QgsProject.instance().layoutManager().printLayouts():
            # Set values of internal variables

            if layout.name() == self.dlg.layoutSelect.currentText():
                date_now = datetime.date.today().strftime("%B %d, %Y")
                ET.SubElement(mapdata, 'lastUpdated').text = date_now
                title = layout.name()
                ET.SubElement(mapdata,
                              'jpgfilename').text = layout.name() + '.jpg'
                ET.SubElement(mapdata,
                              'pdffilename').text = layout.name() + '.pdf'
                # Action: Which map is selected by this?
                item = layout.referenceMap()
                #                item = layout.itemById('main')

                # Get the attr by name and call
                map_scale = getattr(item, 'scale')()

                ET.SubElement(mapdata, 'scale').text = str(round(map_scale))
                map_extent = item.extent()
                map_xmin = map_extent.xMinimum()
                map_xmax = map_extent.xMaximum()
                map_ymin = map_extent.yMinimum()
                map_ymax = map_extent.yMaximum()
                QgsMessageLog.logMessage('Scale ' + str(map_xmin), 'MapExport',
                                         Qgis.Info)

                ET.SubElement(mapdata, 'xmin').text = str(round(map_xmin))
                ET.SubElement(mapdata, 'xmax').text = str(round(map_xmax))
                ET.SubElement(mapdata, 'ymin').text = str(round(map_ymin))
                ET.SubElement(mapdata, 'ymax').text = str(round(map_ymax))

                for x in metadata_list:
                    ma_variable = str(x[0])
                    elem_name = str(x[1])
                    elem_name = elem_name.strip()
                    ma_level = str(x[2])
                    ma_level = ma_level.strip()
                    if ma_level == 'layout':
                        elem_value = str(
                            QgsExpressionContextUtils.layoutScope(
                                layout).variable(ma_variable))
                        ET.SubElement(mapdata, elem_name).text = elem_value
                        if elem_value.strip():
                            QgsMessageLog.logMessage(
                                ma_variable + ' exported as ' + elem_value,
                                'MapExport', Qgis.Info)
                        else:
                            msgBar.pushMessage(
                                'Warning: missing value for ' + ma_variable, 5)
                            QgsMessageLog.logMessage(
                                'Warning: missing value for ' + ma_variable,
                                'MapExport')
                tree = ET.ElementTree(settings)
                tree.write(os.path.join(folder, title, title + '.xml'))

        # Set the location and the file name of the zip
        zippath = os.path.join(folder, title)
        zf = zipfile.ZipFile(
            os.path.abspath(folder) + os.sep + title + ".zip", "w")
        for dirnames, folders, files in os.walk(os.path.join(folder, title)):
            #  for root, dirs, files in os.walk(folder):
            for file in files:
                zf.write(os.path.join(os.path.join(folder, title), file), file)
        zf.close()
        self.pageProcessed()
Beispiel #56
0
    def processAlgorithm(self, parameters, context, feedback):

        t_regard = self.parameterAsSource(parameters, self.MANHOLES_TABLE,
                                          context)
        g_regard = self.parameterAsSource(parameters, self.GEOM_MANHOLES,
                                          context)
        t_troncon = self.parameterAsVectorLayer(parameters,
                                                self.SEGMENTS_TABLE, context)
        g_troncon = self.parameterAsVectorLayer(parameters, self.GEOM_SEGMENTS,
                                                context)

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

        exp_str = '"id_geom_troncon" IS NULL'
        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)
        r_ids = []  # identifiant des regards
        l_t_f = {}  # lien troncon fichier
        l_f_t = {}  # lien fichier troncons
        troncons = {}
        sorties = {}
        entrees = {}
        for tro in t_troncon.getFeatures(request):
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SEGMENT_CREATED: None}

            segment_number = tro['id']
            r1 = tro['id_regard1']
            r2 = tro['id_regard2']

            if r1 not in r_ids:
                r_ids.append(r1)
            if r2 not in r_ids:
                r_ids.append(r2)

            fid = tro['id_file']
            l_t_f[segment_number] = fid
            if fid in l_f_t:
                l_f_t[fid] = l_f_t[fid] + [segment_number]
            else:
                l_f_t[fid] = [segment_number]

            troncons[segment_number] = (r1, r2)
            if r1 in sorties:
                sorties[r1] = sorties[r1] + [segment_number]
            else:
                sorties[r1] = [segment_number]
            if r2 in entrees:
                entrees[r2] = entrees[r2] + [segment_number]
            else:
                entrees[r2] = [segment_number]

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

        exp_str = ('"id_geom_regard" IS NOT NULL '
                   'AND '
                   '"id" IN ({})').format(','.join([str(i)
                                                    for i in r_ids] + ['-1']))
        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)
        g_ids = []  # identifiants des géométrie de regards
        l_r_g = {}  # lien regard geometrie
        l_g_r = {}  # lien geometrie regards
        for reg in t_regard.getFeatures(request):
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SEGMENT_CREATED: None}

            segment_number = reg['id']
            fid = reg['id_file']

            if segment_number in sorties:
                sorties[segment_number] = [
                    trid for trid in sorties[segment_number]
                    if l_t_f[trid] == fid
                ]
            if segment_number in entrees:
                entrees[segment_number] = [
                    trid for trid in entrees[segment_number]
                    if l_t_f[trid] == fid
                ]

            gid = reg['id_geom_regard']
            l_r_g[segment_number] = gid
            if gid not in g_ids:
                g_ids.append(gid)
            if gid in l_g_r:
                l_g_r[gid] = l_g_r[gid] + [segment_number]
            else:
                l_g_r[gid] = [segment_number]

        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(
            QgsExpressionContextUtils.projectScope(context.project()))
        exp_context.appendScope(g_regard.createExpressionContextScope())

        exp_str = '"id" IN ({})'.format(','.join([str(i)
                                                  for i in g_ids] + ['-1']))
        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)
        points = {}
        pt_labels = {}
        for reg in g_regard.getFeatures(request):
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SEGMENT_CREATED: None}

            segment_number = reg['id']
            points[segment_number] = reg.geometry().asPoint()
            pt_labels[segment_number] = reg['label']

        lines = {}
        for gid in points:
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SEGMENT_CREATED: None}

            if gid not in l_g_r:
                continue

            for rid in l_g_r[gid]:
                # Stop the algorithm if cancel button has been clicked
                if feedback.isCanceled():
                    return {self.SEGMENT_CREATED: None}

                if rid in sorties:
                    for tid in sorties[rid]:
                        # Stop the algorithm if cancel button has been clicked
                        if feedback.isCanceled():
                            return {self.SEGMENT_CREATED: None}

                        if tid in lines:
                            continue
                        if tid not in troncons:
                            continue
                        r2 = troncons[tid][1]
                        if r2 not in l_r_g:
                            continue
                        g2 = l_r_g[r2]
                        if g2 not in points:
                            continue
                        lines[tid] = (gid, g2)

                if rid in entrees:
                    for tid in entrees[rid]:
                        # Stop the algorithm if cancel button has been clicked
                        if feedback.isCanceled():
                            return {self.SEGMENT_CREATED: None}

                        if tid in lines:
                            continue
                        if tid not in troncons:
                            continue
                        r1 = troncons[tid][0]
                        if r1 not in l_r_g:
                            continue
                        g1 = l_r_g[r1]
                        if g1 not in points:
                            continue
                        lines[tid] = (g1, gid)

        # Creation des troncons
        l_t_g = {}  # lien troncon et geometrie troncon
        l_pts_t = {}  # lien points troncons
        features = []  # les objets de geometrie de troncon
        geom_point_keys = []  # liste des clés des points troncons
        for tid, pts in lines.items():
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SEGMENT_CREATED: None}

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

            exp_str = ('"id_geom_regard_amont" = {} AND '
                       '"id_geom_regard_aval" = {}').format(pts[0], pts[1])
            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 tro in g_troncon.getFeatures(request):
                l_t_g[tid] = tro['id']
                continue

            if (pts[0], pts[1]) in geom_point_keys:
                l_pts_t[(pts[0], pts[1])].append(tid)
                continue
            else:
                l_pts_t[(pts[0], pts[1])] = [tid]
                geom_point_keys.append((pts[0], pts[1]))

            feat_t = QgsVectorLayerUtils.createFeature(g_troncon)
            feat_t.setAttribute(
                'label', '{}-{}'.format(pt_labels[pts[0]], pt_labels[pts[1]]))
            feat_t.setAttribute('id_geom_regard_amont', pts[0])
            feat_t.setAttribute('id_geom_regard_aval', pts[1])
            feat_t.setGeometry(
                QgsGeometry.fromPolylineXY([points[pts[0]], points[pts[1]]]))
            features.append(feat_t)

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

            for tro in outFeats:
                # Stop the algorithm if cancel button has been clicked
                if feedback.isCanceled():
                    return {self.SEGMENT_CREATED: None}

                if not tro['id']:
                    continue
                key = (tro['id_geom_regard_amont'], tro['id_geom_regard_aval'])
                if key not in geom_point_keys:
                    continue
                for tid in l_pts_t[(pts[0], pts[1])]:
                    l_t_g[tid] = tro['id']
                    # Stop the algorithm if cancel button has been clicked
                    if feedback.isCanceled():
                        return {self.SEGMENT_CREATED: None}

        for tid, pts in lines.items():
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SEGMENT_CREATED: None}

            if tid in l_t_g:
                continue
            exp_context = QgsExpressionContext()
            exp_context.appendScope(QgsExpressionContextUtils.globalScope())
            exp_context.appendScope(
                QgsExpressionContextUtils.projectScope(context.project()))
            exp_context.appendScope(
                QgsExpressionContextUtils.layerScope(g_troncon))

            exp_str = ('"id_geom_regard_amont" = {} AND '
                       '"id_geom_regard_aval" = {}').format(pts[0], pts[1])
            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 tro in g_troncon.getFeatures(request):
                l_t_g[tid] = tro['id']
                # Stop the algorithm if cancel button has been clicked
                if feedback.isCanceled():
                    return {self.SEGMENT_CREATED: None}

        if not l_t_g.keys():
            raise QgsProcessingException(
                tr('* ERREUR: Aucune géométrie de tronçon'))

        # Mise a jour de la table troncon
        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(
            QgsExpressionContextUtils.projectScope(context.project()))
        exp_context.appendScope(
            QgsExpressionContextUtils.layerScope(t_troncon))

        exp_str = ('"id_geom_troncon" IS NULL AND '
                   'id IN ({})').format(','.join(
                       [str(i) for i in l_t_g.keys()]))
        exp = QgsExpression(exp_str)

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

        # Mise a jour de la table de tronçon
        request = QgsFeatureRequest(exp, exp_context)
        t_troncon.startEditing()
        segment_number = 0
        for tro in t_troncon.getFeatures(request):
            tro.setAttribute('id_geom_troncon', l_t_g[tro['id']])
            t_troncon.updateFeature(tro)
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SEGMENT_CREATED: None}
            segment_number += 1

        if not t_troncon.commitChanges():
            raise QgsProcessingException(
                tr('* ERROR: Commit %s.') % t_troncon.commitErrors())

        # Returns empty dict if no outputs
        return {self.SEGMENT_CREATED: segment_number}
Beispiel #57
0
    def expressionBasedUpdate( self, layer, dictProperties, featureId, index=None, value=None ):
        """ Defines the logic of the expression-based update to be applied.
            This SLOT listens to featureAdded, geometryChanged, and attributeValueChanged SIGNALS.
        """
        # Check if AutoField is there, otherwise return
        fieldIndex = layer.fieldNameIndex( dictProperties['field'] )
        if fieldIndex == -1:
            self.msg.show(
                QApplication.translate( "EventManager", "[Error] Updating AutoField " ) + \
                dictProperties['field'] + \
                QApplication.translate( "EventManager", " in layer " ) + \
                layer.name() + QApplication.translate( "EventManager", " was NOT possible." ) + \
                QApplication.translate( "EventManager", " Perhaps you just removed it but haven't saved the changes yet?" ),
                'warning' )
            return

        event = ""
        result = None

        expression = QgsExpression( dictProperties['expression'] )
        if expression.hasParserError():
            self.msg.show( QApplication.translate( "EventManager", "[Error] (Parsing) " ) + \
                expression.parserErrorString(), 'critical' )
            result = NULL

        # Avoid infinite recursion (changing the same attribute value infinitely).
        if not index is None: # Filters out the featureAdded SIGNAL       
            if type( index ) == int: # Filters out the geometryChanged SIGNAL
                
                if index == fieldIndex: # This call comes from the same AutoField, so return
                    return
                
                if self.afm.isFieldAnAutoField( layer, layer.fields()[index].name() ): # Call from AutoField, don't listen
                    # This is to prevent corrupting the layerEditBuffer and being bitten by:
                    #   Fatal: ASSERT: "mChangedAttributeValues.isEmpty()" in file /tmp/buildd/qgis-2.14.2+20trusty/src/core/qgsvectorlayereditbuffer.cpp, line 585
                    return 
                
                #if type(value)==QPyNullVariant: 
                    # Vector layers with numeric field whose value for 1st feature is NULL
                    #   trigger an attributeValueChanged SIGNAL when start editing from the
                    #   attribute table window. We use this conditional to avoid such SIGNAL.
                    #   The ideal case is that such NULL valued SIGNAL shouldn't be emitted by QGIS.
                #    return  
                # While the previous block reduces the number of times attributeValueChanged
                #   is called from the attribute table, it leads to a QGIS bug:
                #   Fatal: ASSERT: "mChangedAttributeValues.isEmpty()" in file /tmp/buildd/qgis-2.14.2+20trusty/src/core/qgsvectorlayereditbuffer.cpp, line 585
                #   I prefer the attributeValueChanged to be called multiple 
                #   times (inefficient) than to open the possibility to a bug. 
                # As soon as QGIS bug #15272 is solved, the number of calls will be reduced!
                
                event = "attributeValueChanged"
            else:
                event = "geometryChanged"
        else:
            event = "featureAdded"
            
        feature = layer.getFeatures( QgsFeatureRequest( featureId ) ).next()
        
        if result is None:
            context = QgsExpressionContext()
            context.appendScope( QgsExpressionContextUtils.globalScope() )
            context.appendScope( QgsExpressionContextUtils.projectScope() )
            context.appendScope( QgsExpressionContextUtils.layerScope( layer ) )
            context.setFields( feature.fields() )
            context.setFeature( feature )

            if expression.needsGeometry():
                if self.iface:
                    # This block was borrowed from QGIS/python/plugins/processing/algs/qgis/FieldsCalculator.py 
                    da = QgsDistanceArea()
                    da.setSourceCrs( layer.crs().srsid() )
                    da.setEllipsoidalMode( self.iface.mapCanvas().mapSettings().hasCrsTransformEnabled() )
                    da.setEllipsoid( QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE )[0] )
                    expression.setGeomCalculator( da )
                    if QGis.QGIS_VERSION_INT >= 21400: # Methods added in QGIS 2.14
                        expression.setDistanceUnits( QgsProject.instance().distanceUnits() ) 
                        expression.setAreaUnits( QgsProject.instance().areaUnits() )
            
            expression.prepare( context )
            result = expression.evaluate( context )
            
            if expression.hasEvalError():
                self.msg.show( QApplication.translate( "EventManager", "[Error] (Evaluating) " ) + \
                    expression.evalErrorString(), 'critical' )
                result = NULL
        
        field = layer.fields()[fieldIndex]
        res = field.convertCompatible( result )
        # If result is None, res will be None, but even in that case, QGIS knows
        #   what to do with it while saving, it seems it's treated as NULL.
        

        # TODO when bug #15311 is fixed, this block should work better
        #if dictProperties['expression'] in self.listProviderExpressions: 
        #    # Save directly to provider
        #    layer.dataProvider().changeAttributeValues( { featureId : { fieldIndex : res } } )
        #else: # Save to layer
        #    layer.changeAttributeValue( featureId, fieldIndex, res )
         
        # Workaround 
        if event == 'featureAdded': # Save directly to the provider
            layer.dataProvider().changeAttributeValues( { featureId : { fieldIndex : res } } )
        else: # Save to layer
            layer.changeAttributeValue( featureId, fieldIndex, res )
        
        self.msg.show( "[Info] * AutoField's value updated to " + unicode(res) + \
            ", (" + layer.name() + "." + dictProperties['field'] + ") by " + event +".", 'info', True )
Beispiel #58
0
    def photoDetails(self):

        # Function to deal with photo fields

        TOMsMessageLog.logMessage("In photoDetails", level=Qgis.Info)

        FIELD1 = self.ui.findChild(QLabel, "Photo_Widget_01")
        FIELD2 = self.ui.findChild(QLabel, "Photo_Widget_02")
        FIELD3 = self.ui.findChild(QLabel, "Photo_Widget_03")

        path_absolute = QgsExpressionContextUtils.projectScope(
            QgsProject.instance()).variable('PhotoPath')
        if path_absolute == None:
            reply = QMessageBox.information(None, "Information",
                                            "Please set value for PhotoPath.",
                                            QMessageBox.Ok)
            return

        layerName = self.currRestrictionLayer.name()

        # Generate the full path to the file

        fileName1 = "Photos_01"
        fileName2 = "Photos_02"
        fileName3 = "Photos_03"

        idx1 = self.currRestrictionLayer.fields().indexFromName(fileName1)
        idx2 = self.currRestrictionLayer.fields().indexFromName(fileName2)
        idx3 = self.currRestrictionLayer.fields().indexFromName(fileName3)

        TOMsMessageLog.logMessage("In photoDetails. idx1: " + str(idx1) +
                                  "; " + str(idx2) + "; " + str(idx3),
                                  level=Qgis.Info)
        #if currRestrictionFeature[idx1]:
        #TOMsMessageLog.logMessage("In photoDetails. photo1: " + str(currRestrictionFeature[idx1]), level=Qgis.Info)
        #TOMsMessageLog.logMessage("In photoDetails. photo2: " + str(currRestrictionFeature.attribute(idx2)), level=Qgis.Info)
        #TOMsMessageLog.logMessage("In photoDetails. photo3: " + str(currRestrictionFeature.attribute(idx3)), level=Qgis.Info)

        if FIELD1:
            TOMsMessageLog.logMessage("In photoDetails. FIELD 1 exisits",
                                      level=Qgis.Info)
            if self.currRestriction[idx1]:
                newPhotoFileName1 = os.path.join(path_absolute,
                                                 self.currRestriction[idx1])
            else:
                newPhotoFileName1 = None

            TOMsMessageLog.logMessage("In photoDetails. A. Photo1: " +
                                      str(newPhotoFileName1),
                                      level=Qgis.Info)
            pixmap1 = QPixmap(newPhotoFileName1)
            if pixmap1.isNull():
                pass
                # FIELD1.setText('Picture could not be opened ({path})'.format(path=newPhotoFileName1))
            else:
                FIELD1.setPixmap(pixmap1)
                FIELD1.setScaledContents(True)
                TOMsMessageLog.logMessage("In photoDetails. Photo1: " +
                                          str(newPhotoFileName1),
                                          level=Qgis.Info)

        if FIELD2:
            TOMsMessageLog.logMessage("In photoDetails. FIELD 2 exisits",
                                      level=Qgis.Info)
            if self.currRestriction[idx2]:
                newPhotoFileName2 = os.path.join(path_absolute,
                                                 self.currRestriction[idx2])
            else:
                newPhotoFileName2 = None

            #newPhotoFileName2 = os.path.join(path_absolute, str(currRestrictionFeature[idx2]))
            #newPhotoFileName2 = os.path.join(path_absolute, str(currRestrictionFeature.attribute(fileName2)))
            TOMsMessageLog.logMessage("In photoDetails. A. Photo2: " +
                                      str(newPhotoFileName2),
                                      level=Qgis.Info)
            pixmap2 = QPixmap(newPhotoFileName2)
            if pixmap2.isNull():
                pass
                # FIELD1.setText('Picture could not be opened ({path})'.format(path=newPhotoFileName1))
            else:
                FIELD1.setPixmap(pixmap2)
                FIELD1.setScaledContents(True)
                TOMsMessageLog.logMessage("In photoDetails. Photo2: " +
                                          str(newPhotoFileName2),
                                          level=Qgis.Info)

        if FIELD3:
            TOMsMessageLog.logMessage("In photoDetails. FIELD 3 exisits",
                                      level=Qgis.Info)
            if self.currRestriction[idx3]:
                newPhotoFileName3 = os.path.join(path_absolute,
                                                 self.currRestriction[idx3])
            else:
                newPhotoFileName3 = None

            #newPhotoFileName3 = os.path.join(path_absolute, str(currRestrictionFeature[idx3]))
            #newPhotoFileName3 = os.path.join(path_absolute,
            #                                 str(currRestrictionFeature.attribute(fileName3)))
            #newPhotoFileName3 = os.path.join(path_absolute, str(layerName + "_Photos_03"))
            pixmap3 = QPixmap(newPhotoFileName3)
            if pixmap3.isNull():
                pass
                # FIELD1.setText('Picture could not be opened ({path})'.format(path=newPhotoFileName1))
            else:
                FIELD1.setPixmap(pixmap3)
                FIELD1.setScaledContents(True)
                TOMsMessageLog.logMessage("In photoDetails. Photo3: " +
                                          str(newPhotoFileName3),
                                          level=Qgis.Info)

        pass
Beispiel #59
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)

        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().srsid())
        da.setEllipsoidalMode(
            iface.mapCanvas().mapSettings().hasCrsTransformEnabled())
        da.setEllipsoid(QgsProject.instance().readEntry(
            'Measure', '/Ellipsoid', GEO_NONE)[0])
        exp.setGeomCalculator(da)
        exp.setDistanceUnits(QgsProject.instance().distanceUnits())
        exp.setAreaUnits(QgsProject.instance().areaUnits())

        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(QgsExpressionContextUtils.projectScope())
        exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer))

        if not exp.prepare(exp_context):
            raise GeoAlgorithmExecutionException(
                self.tr('Evaluation error: %s' % 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)

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

        if not calculationSuccess:
            raise GeoAlgorithmExecutionException(
                self.tr('An error occurred while evaluating the calculation '
                        'string:\n%s' % error))
Beispiel #60
0
def expression_eval(expression_text,
                    project_id=None,
                    qgs_layer_id=None,
                    form_data=None,
                    formatter=0):
    """Evaluates a QgsExpression and returns the result

    :param expression_text: The QgsExpression text
    :type expression_text: str
    :param project_id: ID of the qdjango project, defaults to None
    :type project_id: int, optional
    :param qgs_layer_id: ID of the QGIS Layer, defaults to None
    :type qgslayer_id: str, optional
    :param form_data: A dictionary that maps to a GeoJSON representation of the feature currently edited in the form
    :type form_data: dict, optional
    :param formatter: Indicate if form_data values contains formatter values or original features value.
    :type formatter: int, optional
    """

    expression = QgsExpression(expression_text)
    expression_context = QgsExpressionContext()

    layer = None

    for func_name in expression.referencedFunctions():
        if func_name in FORBIDDEN_FUNCTIONS:
            raise ExpressionForbiddenError(
                _('Function "{}" is not allowed for security reasons!').format(
                    func_name))

    for var_name in expression.referencedVariables():
        if var_name in FORBIDDEN_VARIABLES:
            raise ExpressionForbiddenError(
                _('Variable "{}" is not allowed for security reasons!').format(
                    var_name))

    if project_id is not None:

        try:
            project = Project.objects.get(pk=project_id)

            if qgs_layer_id is not None:
                try:
                    layer = project.layer_set.get(qgs_layer_id=qgs_layer_id)
                except Layer.DoesNotExist:
                    raise ExpressionLayerError(
                        _('QGIS layer with id "{}" could not be found!').
                        format(qgs_layer_id))

                expression_contex = QgsExpressionContextUtils.globalProjectLayerScopes(
                    layer.qgis_layer)

            else:
                expression_contex = QgsExpressionContextUtils.globalScope()
                expression_context.appendScope(
                    QgsExpressionContextUtils.projectScope(
                        project.qgis_project))

        except Project.DoesNotExist:
            raise ExpressionProjectError(
                _('QDjango project with id "{}" could not be found!').format(
                    project_id))

    else:
        expression_contex = QgsExpressionContextUtils.globalScope()

    if form_data is not None:

        if layer is None:
            raise ExpressionLayerError(
                _('A valid QGIS layer is required to process form data!'))

        try:
            # Case by formatter
            # formatter == 1 : get featureid from layer, usually must be used with formatter form_data
            # formatter == 0 : default behavior
            if formatter == 0:
                fields = layer.qgis_layer.fields()
                form_feature = QgsJsonUtils.stringToFeatureList(
                    json.dumps(form_data), fields, None)[0]

                # Set attributes manually because QgsJsonUtils does not respect order
                for k, v in form_data['properties'].items():
                    form_feature.setAttribute(k, v)
            else:
                qgis_feature_request = QgsFeatureRequest()
                exp = expression_from_server_fids(
                    [form_data['id']], layer.qgis_layer.dataProvider())
                qgis_feature_request.combineFilterExpression(exp)
                form_feature = get_qgis_features(layer.qgis_layer,
                                                 qgis_feature_request)[0]

            expression_context.appendScope(
                QgsExpressionContextUtils.formScope(form_feature))
            expression_context.setFeature(form_feature)
        except:
            raise ExpressionFormDataError()

    valid, errors = expression.checkExpression(expression_text,
                                               expression_context)

    if not valid:
        raise ExpressionParseError(errors)

    result = expression.evaluate(expression_context)

    if expression.hasEvalError():
        raise ExpressionEvalError(expression.evalErrorString())

    return result