Пример #1
0
 def mg_flow_trace_select_features(self, layer, elem_type):
     
     sql = "SELECT * FROM "+self.schema_name+".temp_mincut_"+elem_type+" ORDER BY "+elem_type+"_id"  
     rows = self.dao.get_rows(sql)
     self.dao.commit()
     
     # Build an expression to select them
     aux = "\""+elem_type+"_id\" IN ("
     for elem in rows:
         aux+= elem[0]+", "
     aux = aux[:-2]+")"
     
     # Get a featureIterator from this expression:
     expr = QgsExpression(aux)
     if expr.hasParserError():
         self.showWarning("Expression Error: "+str(expr.parserErrorString()))
         return        
     it = layer.getFeatures(QgsFeatureRequest(expr))
     
     # Build a list of feature id's from the previous result
     id_list = [i.id() for i in it]
     
     # Select features with these id's 
     layer.setSelectedFeatures(id_list)       
         
         
Пример #2
0
    def get_feature_value(self, model=None):
        self.layer.startEditing()
        feature = None

        request = QgsFeatureRequest()
        if model is None:
            model = self.host.model()
        request.setFilterFid(model.id)
        feature_itr = self.layer.getFeatures(request)
        for feat in feature_itr:
            feature = feat
            break

        exp = QgsExpression(self.column.expression)

        if exp.hasParserError():
            raise Exception(exp.parserErrorString())

        exp.prepare(self.layer.pendingFields())
        if feature is not None:
            value = exp.evaluate(feature)

            return value
        else:
            return None
Пример #3
0
    def getValue(self):
        fileName = unicode(self.leText.text())
        context = self.expressionContext()
        exp = QgsExpression(fileName)
        if not exp.hasParserError():
            result = exp.evaluate(context)
            if not exp.hasEvalError():
                fileName = result
                if fileName.startswith("[") and fileName.endswith("]"):
                    fileName = fileName[1:-1]
        if fileName.strip() in ['', self.SAVE_TO_TEMP_FILE]:
            value = None
        elif fileName.startswith('memory:'):
            value = fileName
        elif fileName.startswith('postgis:'):
            value = fileName
        elif fileName.startswith('spatialite:'):
            value = fileName
        elif not os.path.isabs(fileName):
            value = ProcessingConfig.getSetting(
                ProcessingConfig.OUTPUT_FOLDER) + os.sep + fileName
        else:
            value = fileName

        return value
Пример #4
0
    def getValue(self):
        fileName = unicode(self.leText.text())
        context = self.expressionContext()
        exp = QgsExpression(fileName)
        if not exp.hasParserError():
            result = exp.evaluate(context)
            if not exp.hasEvalError():
                fileName = result
                if fileName.startswith("[") and fileName.endswith("]"):
                    fileName = fileName[1:-1]
        if fileName.strip() in ["", self.SAVE_TO_TEMP_FILE, self.SAVE_TO_TEMP_LAYER]:
            if isinstance(self.output, OutputVector) and self.alg.provider.supportsNonFileBasedOutput():
                # use memory layers for temporary files if supported
                value = "memory:"
            else:
                value = None
        elif fileName.startswith("memory:"):
            value = fileName
        elif fileName.startswith("postgis:"):
            value = fileName
        elif fileName.startswith("spatialite:"):
            value = fileName
        elif not os.path.isabs(fileName):
            value = ProcessingConfig.getSetting(ProcessingConfig.OUTPUT_FOLDER) + os.sep + fileName
        else:
            value = fileName

        return value
    def setSearchAndReplaceDictionaryFromLayer(self, layer, expression):
        '''
        Set the search and replace dictionary
        from a given layer
        and an expression.
        The first found features is the data source
        '''
        searchAndReplaceDictionary = {}

        # Get and validate expression
        qExp = QgsExpression( expression )
        if not qExp.hasParserError():
            qReq = QgsFeatureRequest( qExp )
            features = layer.getFeatures( qReq )
        else:
            QgsMessageLog.logMessage( 'An error occured while parsing the given expression: %s' % qExp.parserErrorString() )
            features = layer.getFeatures()

        # Get layer fields name
        fields = layer.pendingFields()
        field_names = [ field.name() for field in fields ]

        # Take only first feature
        for feat in features:
            # Build dictionnary
            searchAndReplaceDictionary = dict(zip(field_names, feat.attributes()))
            break

        self.searchAndReplaceDictionary = searchAndReplaceDictionary
Пример #6
0
 def generic_zoom(self, fieldname, combo, field_index=0):  
     ''' Get selected element from the combo, and returns a feature request expression '''
     
     # Get selected element from combo    
     element = combo.currentText()
     if element.strip() == '':
         print "Any record selected"
         return None
             
     elem = combo.itemData(combo.currentIndex())
     if not elem:
         # that means that user has edited manually the combo but the element
         # does not correspond to any combo element
         message = 'Element {} does not exist'.format(element)
         self.controller.show_warning(message) 
         return None
     
     # Select this feature in order to copy to memory layer   
     aux = fieldname+" = '"+str(elem[field_index])+"'"
     expr = QgsExpression(aux)    
     if expr.hasParserError():   
         message = expr.parserErrorString() + ": " + aux
         self.controller.show_warning(message)        
         return     
     
     return expr
Пример #7
0
    def resolveValue(self, alg):
        if self.hidden:
            return
        if not bool(self.value):
            self.value = self._resolveTemporary(alg)
        else:
            exp = QgsExpression(self.value)
            if not exp.hasParserError():
                value = exp.evaluate(_expressionContext(alg))
                if not exp.hasEvalError():
                    self.value = value

        if ":" not in self.value:
            if not os.path.isabs(self.value):
                self.value = os.path.join(ProcessingConfig.getSetting(ProcessingConfig.OUTPUT_FOLDER),
                                          self.value)
            supported = self._supportedExtensions()
            if supported:
                idx = self.value.rfind('.')
                if idx == -1:
                    self.value = self.value + '.' + self.getDefaultFileExtension()
                else:
                    ext = self.value[idx + 1:]
                    if ext not in supported:
                        self.value = self.value + '.' + self.getDefaultFileExtension()
    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
    def mg_flow_trace_select_features(self, layer, elem_type):

        if self.index_action == '56':
            sql = "SELECT * FROM "+self.schema_name+".anl_flow_trace_"+elem_type+" ORDER BY "+elem_type+"_id"
        else:
            sql = "SELECT * FROM "+self.schema_name+".anl_flow_exit_"+elem_type+" ORDER BY "+elem_type+"_id"

        rows = self.controller.get_rows(sql)
        if rows:
    
            # Build an expression to select them
            aux = "\""+elem_type+"_id\" IN ("
            for elem in rows:
                aux += elem[0] + ", "
            aux = aux[:-2] + ")"
    
            # Get a featureIterator from this expression:
            expr = QgsExpression(aux)
            if expr.hasParserError():
                message = "Expression Error: " + str(expr.parserErrorString())
                self.controller.show_warning(message, context_name='ui_message')
                return
            it = layer.getFeatures(QgsFeatureRequest(expr))
    
            # Build a list of feature id's from the previous result
            id_list = [i.id() for i in it]
    
            # Select features with these id's
            layer.setSelectedFeatures(id_list)
Пример #10
0
    def prepareAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, 'INPUT', context)
        mapping = self.parameterAsFieldsMapping(parameters, self.FIELDS_MAPPING, context)

        self.fields = QgsFields()
        self.expressions = []

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

        # create an expression context using thread safe processing context
        self.expr_context = self.createExpressionContext(parameters, context, source)

        for field_def in mapping:
            self.fields.append(QgsField(name=field_def['name'],
                                        type=field_def['type'],
                                        typeName="",
                                        len=field_def.get('length', 0),
                                        prec=field_def.get('precision', 0)))
            expression = QgsExpression(field_def['expression'])
            expression.setGeomCalculator(da)
            expression.setDistanceUnits(context.project().distanceUnits())
            expression.setAreaUnits(context.project().areaUnits())
            if expression.hasParserError():
                raise QgsProcessingException(
                    self.tr(u'Parser error in expression "{}": {}')
                    .format(str(expression.expression()),
                            str(expression.parserErrorString())))
            self.expressions.append(expression)
        return True
Пример #11
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
Пример #12
0
 def showExpressionsBuilder(self):
     context = self.param.expressionContext()
     dlg = QgsExpressionBuilderDialog(None, self.leText.text(), self, 'generic', context)
     dlg.setWindowTitle(self.tr('Expression based input'))
     if dlg.exec_() == QDialog.Accepted:
         exp = QgsExpression(dlg.expressionText())
         if not exp.hasParserError():
             self.setValue(dlg.expressionText())
Пример #13
0
 def address_get_numbers(self):
     ''' Populate civic numbers depending on selected street. 
         Available civic numbers are linked with self.street_field_code column code in self.portal_layer and self.street_layer
     '''   
                        
     # get selected street
     selected = self.dlg.adress_street.currentText()
     if selected == '':
         print "Any record selected"            
         return
     
     # get street code
     elem = self.dlg.adress_street.itemData(self.dlg.adress_street.currentIndex())
     code = elem[0] # to know the index see the query that populate the combo
     records = [[-1, '']]
     
     # Set filter expression
     layer = self.layers['portal_layer'] 
     idx_field_code = layer.fieldNameIndex(self.params['portal_field_code'])            
     idx_field_number = layer.fieldNameIndex(self.params['portal_field_number'])   
     aux = self.params['portal_field_code']+" = '"+str(code)+"'" 
     
     # Check filter and existence of fields
     expr = QgsExpression(aux)     
     if expr.hasParserError():    
         message = expr.parserErrorString() + ": " + aux
         self.controller.show_warning(message)    
         return               
     if idx_field_code == -1:    
         message = "Field '{}' not found in layer '{}'. Open '{}' and check parameter '{}'" \
             .format(self.params['portal_field_code'], layer.name(), self.setting_file, 'portal_field_code')            
         self.controller.show_warning(message)         
         return      
     if idx_field_number == -1:    
         message = "Field '{}' not found in layer '{}'. Open '{}' and check parameter '{}'" \
             .format(self.params['portal_field_number'], layer.name(), self.setting_file, 'portal_field_number')            
         self.controller.show_warning(message)         
         return      
         
     # Get a featureIterator from an expression:
     # Get features from the iterator and do something
     it = layer.getFeatures(QgsFeatureRequest(expr))
     for feature in it: 
         attrs = feature.attributes() 
         field_number = attrs[idx_field_number]    
         if not type(field_number) is QPyNullVariant:
             elem = [code, field_number]
             records.append(elem)
               
     # Fill numbers combo
     records_sorted = sorted(records, key = operator.itemgetter(1))           
     self.dlg.adress_number.blockSignals(True)
     self.dlg.adress_number.clear()
     for record in records_sorted:
         self.dlg.adress_number.addItem(str(record[1]), record)
     self.dlg.adress_number.blockSignals(False)  
Пример #14
0
    def urban_zoom(self):
        ''' Zoom to layer 'urban' filtering values of all combos '''  

        # Build expresion search
        aux = ""
        layer = self.layers['urban_propierties_layer']      
        fieldname = self.params['urban_propierties_field_pzone']
        combo =  self.dlg.urban_properties_zone
        text = utils_giswater.getSelectedItem(combo)
        if text != "null":
            if aux != "":
                aux+= " AND "
            aux+= fieldname+" = '"+str(text)+"'"
            
        fieldname = self.params['urban_propierties_field_block']
        combo =  self.dlg.urban_properties_block
        text = utils_giswater.getSelectedItem(combo)
        if text != "null":
            if aux != "":
                aux+= " AND "
            aux+= fieldname+" = '"+str(text)+"'"
            
        fieldname = self.params['urban_propierties_field_number']
        combo =  self.dlg.urban_properties_number
        text = utils_giswater.getSelectedItem(combo)
        if text != "null":
            if aux != "":
                aux+= " AND "
            aux+= fieldname+" = '"+str(text)+"'"
         
        # Build a list of feature id's from the expression and select them       
        if aux != '':
            expr = QgsExpression(aux)    
            if expr.hasParserError():   
                message = expr.parserErrorString() + ": " + aux
                self.controller.show_warning(message)        
                return              
            it = layer.getFeatures(QgsFeatureRequest(expr))
            ids = [i.id() for i in it]
            layer.setSelectedFeatures(ids)
        # Select all features
        else:
            layer.selectAll()       
        
        # Copy selected features to memory layer     
        self.urbanMemLayer = self.copy_selected(layer, self.urbanMemLayer, "Polygon")       

        # Zoom to generated memory layer
        self.zoom_to_scale()
        
        # Load style
        if self.QML_URBAN is not None:
            self.load_style(self.urbanMemLayer, self.QML_URBAN) 
              
        # Toggles 'Show feature count'
        self.show_feature_count()                             
Пример #15
0
 def createExpression(self, text, da, context):
     expr = QgsExpression(text)
     expr.setGeomCalculator(da)
     expr.setDistanceUnits(context.project().distanceUnits())
     expr.setAreaUnits(context.project().areaUnits())
     if expr.hasParserError():
         raise QgsProcessingException(
             self.tr(u'Parser error in expression "{}": {}')
             .format(text, expr.parserErrorString()))
     return expr
Пример #16
0
 def getStreetNumbers(self):
     ''' Populate civic numbers depending on selected street. 
         Available civic numbers are linked with self.STREET_FIELD_CODE column code in self.PORTAL_LAYER
         and self.STREET_LAYER
     '''       
     # get selected street
     selected = self.dlg.cboStreet.currentText()
     if selected == '':
         return
     
     # get street code
     sel_street = self.dlg.cboStreet.itemData(self.dlg.cboStreet.currentIndex())
     code = sel_street[2] # to know the index see the query that populate the combo
     records = [[-1, '']]
     
     # Set filter expression
     layer = self.portalLayer       
     idx_field_code = layer.fieldNameIndex(self.PORTAL_FIELD_CODE)            
     idx_field_number = layer.fieldNameIndex(self.PORTAL_FIELD_NUMBER)   
     aux = self.PORTAL_FIELD_CODE+"='"+str(code)+"'" 
     
     # Check filter and existence of fields
     expr = QgsExpression(aux)     
     if expr.hasParserError():   
         self.iface.messageBar().pushMessage(expr.parserErrorString() + ": " + aux, self.app_name, QgsMessageBar.WARNING, 10)        
         return               
     if idx_field_code == -1:    
         message = self.tr("Field '{}' not found in layer '{}'. Open '{}' and check parameter '{}'".
             format(self.PORTAL_FIELD_CODE, layer.name(), self.setting_file, 'PORTAL_FIELD_CODE'))            
         self.iface.messageBar().pushMessage(message, '', QgsMessageBar.WARNING)        
         return      
     if idx_field_number == -1:    
         message = self.tr("Field '{}' not found in layer '{}'. Open '{}' and check parameter '{}'".
             format(self.PORTAL_FIELD_NUMBER, layer.name(), self.setting_file, 'PORTAL_FIELD_NUMBER'))            
         self.iface.messageBar().pushMessage(message, '', QgsMessageBar.WARNING)        
         return      
         
     # Get a featureIterator from an expression:
     # Get features from the iterator and do something
     it = layer.getFeatures(QgsFeatureRequest(expr))
     for feature in it: 
         attrs = feature.attributes() 
         field_number = attrs[idx_field_number]    
         if not type(field_number) is QPyNullVariant:
             elem = [code, field_number]
             records.append(elem)
               
     # Fill numbers combo
     records_sorted = sorted(records, key = operator.itemgetter(1))           
     self.dlg.cboNumber.blockSignals(True)
     self.dlg.cboNumber.clear()
     for record in records_sorted:
         self.dlg.cboNumber.addItem(record[1], record)
     self.dlg.cboNumber.blockSignals(False) 
Пример #17
0
def where(layer, exp):
      exp = QgsExpression(exp)
      if exp.hasParserError():
         raise Exception(exp.parserErrorString())
      exp.prepare(layer.pendingFields())
      for feature in layer.getFeatures():
         value = exp.evaluate(feature)
         if exp.hasEvalError():
            raise ValueError(exp.evalErrorString())
         if bool(value):
            yield feature
Пример #18
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
Пример #19
0
def layer_value(feature, layer, defaultconfig):
    if not canvas:
        roam.utils.warning("No canvas set for using layer_values default function")
        return None
    layers = []
    # layer name can also be a list of layers to search
    layername = defaultconfig['layer']
    if isinstance(layername, basestring):
        layers.append(layername)
    else:
        layers = layername

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

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

            rect.scale(20)

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

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

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

    raise DefaultError('No features found')
Пример #20
0
 def where(self, exp):
     '''Request feature by QgsExpression
     Usage :
     for feat in layer.where("myfield" = 2):
         ...
     '''
     exp = QgsExpression(exp)
     if exp.hasParserError():
         raise Exception(exp.parserErrorString())
     if exp.hasEvalError():
         raise ValueError(exp.evalErrorString())
     return self.getFeatures(QgsFeatureRequest(exp))
Пример #21
0
    def _buildfromlayer(self, widget, layerconfig):
        layername = layerconfig['layer']
        keyfield = layerconfig['key']
        valuefield = layerconfig['value']
        filterexp = layerconfig.get('filter', None)

        try:
            layer = QgsMapLayerRegistry.instance().mapLayersByName(layername)[0]
        except IndexError:
            roam.utils.warning("Can't find layer {} in project".format(layername))
            return

        keyfieldindex = layer.fieldNameIndex(keyfield)
        valuefieldindex = layer.fieldNameIndex(valuefield)
        if keyfieldindex == -1 or valuefieldindex == -1:
            roam.utils.warning("Can't find key or value column")
            return

        if not filterexp and valuefieldindex == keyfieldindex:
            values = layer.uniqueValues(keyfieldindex)
            for value in values:
                widget.addItem(value, value)
            return

        attributes = {keyfieldindex, valuefieldindex}
        flags = QgsFeatureRequest.NoGeometry

        expression = None
        if filterexp:
            expression = QgsExpression(filterexp)
            expression.prepare(layer.pendingFields())
            if expression.hasParserError():
                roam.utils.warning("Expression has parser error: {}".format(expression.parserErrorString()))
                return

            if expression.needsGeometry():
                flags = QgsFeatureRequest.NoFlags

            for field in expression.referencedColumns():
                index = layer.fieldNameIndex(field)
                attributes.add(index)

        values = set()
        request = QgsFeatureRequest().setFlags(flags).setSubsetOfAttributes(list(attributes))
        for feature in layer.getFeatures(request):
            if expression and not expression.evaluate(feature):
                continue

            widget.addItem(feature[keyfieldindex], feature[valuefield])

        if self.allownulls:
            widget.insertItem(0, '(no selection)', None)
Пример #22
0
 def getPlots(self):
     # get selected urban core
     selected = self.dlg.cboUrbanCore.currentText()
     if selected == '':
         return
     
     # get urban core code
     sel_core = self.dlg.cboUrbanCore.itemData(self.dlg.cboUrbanCore.currentIndex())
     code = sel_core[2] # to know the index see the query that populate the combo
     records = [[-1, '']]
     
     # Set filter expression
     layer = self.plotLayer       
     idx_field_code = layer.fieldNameIndex(self.PLOT_FIELD_CODE)            
     idx_field_number = layer.fieldNameIndex(self.PLOT_FIELD_ADDRESS)   
     idx_field_id = layer.fieldNameIndex('id')
     aux = self.PLOT_FIELD_CODE+"='"+str(code)+"'" 
     
     # Check filter and existence of fields
     expr = QgsExpression(aux)     
     if expr.hasParserError():   
         self.iface.messageBar().pushMessage(expr.parserErrorString() + ": " + aux, self.app_name, QgsMessageBar.WARNING, 10)        
         return               
     if idx_field_code == -1:    
         message = self.tr("Field '{}' not found in layer '{}'. Open '{}' and check parameter '{}'".
             format(self.PLOT_FIELD_CODE, layer.name(), self.setting_file, 'PLOT_FIELD_CODE'))            
         self.iface.messageBar().pushMessage(message, '', QgsMessageBar.WARNING)        
         return      
     if idx_field_number == -1:    
         message = self.tr("Field '{}' not found in layer '{}'. Open '{}' and check parameter '{}'".
             format(self.PLOT_FIELD_ADDRESS, layer.name(), self.setting_file, 'PLOT_FIELD_ADDRESS'))            
         self.iface.messageBar().pushMessage(message, '', QgsMessageBar.WARNING)        
         return      
         
     # Get a featureIterator from an expression:
     # Get features from the iterator and do something
     it = layer.getFeatures(QgsFeatureRequest(expr))
     for feature in it: 
         attrs = feature.attributes() 
         plot_id = attrs[idx_field_id]
         field_number = attrs[idx_field_number]    
         if not type(field_number) is QPyNullVariant:
             elem = [plot_id, field_number]
             records.append(elem)
               
     # Fill numbers combo
     records_sorted = sorted(records, key = operator.itemgetter(1))           
     self.dlg.cboPlot.blockSignals(True)
     self.dlg.cboPlot.clear()
     for record in records_sorted:
         self.dlg.cboPlot.addItem(record[1], record)
     self.dlg.cboPlot.blockSignals(False) 
Пример #23
0
    def processAlgorithm(self, parameters, context, feedback):
        layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)

        fieldName = self.parameterAsString(parameters, self.FIELD, context)
        operator = self.OPERATORS[self.parameterAsEnum(parameters, self.OPERATOR, context)]
        value = self.parameterAsString(parameters, self.VALUE, context)

        fields = layer.fields()

        idx = layer.fields().lookupField(fieldName)
        if idx < 0:
            raise QgsProcessingException(self.tr("Field '{}' was not found in layer").format(fieldName))

        fieldType = fields[idx].type()

        if fieldType != QVariant.String and operator in self.STRING_OPERATORS:
            op = ''.join(['"%s", ' % o for o in self.STRING_OPERATORS])
            raise QgsProcessingException(
                self.tr('Operators {0} can be used only with string fields.').format(op))

        field_ref = QgsExpression.quotedColumnRef(fieldName)
        quoted_val = QgsExpression.quotedValue(value)
        if operator == 'is null':
            expression_string = '{} IS NULL'.format(field_ref)
        elif operator == 'is not null':
            expression_string = '{} IS NOT NULL'.format(field_ref)
        elif operator == 'begins with':
            expression_string = "{} LIKE '{}%'".format(field_ref, value)
        elif operator == 'contains':
            expression_string = "{} LIKE '%{}%'".format(field_ref, value)
        elif operator == 'does not contain':
            expression_string = "{} NOT LIKE '%{}%'".format(field_ref, value)
        else:
            expression_string = '{} {} {}'.format(field_ref, operator, quoted_val)

        method = self.parameterAsEnum(parameters, self.METHOD, context)
        if method == 0:
            behavior = QgsVectorLayer.SetSelection
        elif method == 1:
            behavior = QgsVectorLayer.AddToSelection
        elif method == 2:
            behavior = QgsVectorLayer.RemoveFromSelection
        elif method == 3:
            behavior = QgsVectorLayer.IntersectSelection

        expression = QgsExpression(expression_string)
        if expression.hasParserError():
            raise QgsProcessingException(expression.parserErrorString())

        layer.selectByExpression(expression_string, behavior)

        return {self.OUTPUT: parameters[self.INPUT]}
Пример #24
0
    def processAlgorithm(self, parameters, context, feedback):
        layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)

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

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

        exp_context = QgsExpressionContext(QgsExpressionContextUtils.globalProjectLayerScopes(layer))

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

        features = QgsProcessingUtils.getFeatures(layer, context)
        total = 100.0 / QgsProcessingUtils.featureCount(layer, context)
        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: {0}').format(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)
            feedback.setProgress(int(current * total))

        del writer
Пример #25
0
    def showExpressionsBuilder(self):
        context = self.param.expressionContext()
        dlg = QgsExpressionBuilderDialog(None, str(self.spnValue.value()), self, 'generic', context)

        dlg.setWindowTitle(self.tr('Expression based input'))
        if dlg.exec_() == QDialog.Accepted:
            exp = QgsExpression(dlg.expressionText())
            if not exp.hasParserError():
                try:
                    val = float(exp.evaluate(context))
                    self.setValue(val)
                except:
                    return
Пример #26
0
 def showExpressionsBuilder(self):
     context = self.expressionContext()
     dlg = QgsExpressionBuilderDialog(None, self.spnValue.text(), self, 'generic', context)
     dlg.setWindowTitle(self.tr('Expression based input'))
     if dlg.exec_() == QDialog.Accepted:
         exp = QgsExpression(dlg.expressionText())
         if not exp.hasParserError():
             result = exp.evaluate(context)
             if not exp.hasEvalError():
                 try:
                     self.spnValue.setValue(float(result))
                 except:
                     pass
Пример #27
0
    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 )
Пример #28
0
    def showExpressionsBuilder(self):
        context = createExpressionContext()
        dlg = QgsExpressionBuilderDialog(None, str(self.leText.text()), self, 'generic', context)

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

        dlg.setWindowTitle(self.tr('Expression based input'))
        if dlg.exec_() == QDialog.Accepted:
            exp = QgsExpression(dlg.expressionText())
            if not exp.hasParserError():
                self.setValue(dlg.expressionText())
Пример #29
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT))
        fieldName = self.getParameterValue(self.FIELD)
        operator = self.OPERATORS[self.getParameterValue(self.OPERATOR)]
        value = self.getParameterValue(self.VALUE)

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

        idx = layer.fieldNameIndex(fieldName)
        fieldType = fields[idx].type()

        if fieldType != QVariant.String and operator in self.OPERATORS[-2:]:
            op = ''.join(['"%s", ' % o for o in self.OPERATORS[-2:]])
            raise GeoAlgorithmExecutionException(
                self.tr('Operators %s can be used only with string fields.' % op))

        if fieldType in [QVariant.Int, QVariant.Double]:
            progress.setInfo(self.tr('Numeric field'))
            expr = '"%s" %s %s' % (fieldName, operator, value)
            progress.setInfo(expr)
        elif fieldType == QVariant.String:
            progress.setInfo(self.tr('String field'))
            if operator not in self.OPERATORS[-2:]:
                expr = """"%s" %s '%s'""" % (fieldName, operator, value)
            elif operator == 'begins with':
                expr = """"%s" LIKE '%s%%'""" % (fieldName, value)
            elif operator == 'contains':
                expr = """"%s" LIKE '%%%s%%'""" % (fieldName, value)
            progress.setInfo(expr)
        elif fieldType in [QVariant.Date, QVariant.DateTime]:
            progress.setInfo(self.tr('Date field'))
            expr = """"%s" %s '%s'""" % (fieldName, operator, value)
            progress.setInfo(expr)
        else:
            raise GeoAlgorithmExecutionException(
                self.tr('Unsupported field type "%s"' % fields[idx].typeName()))

        expression = QgsExpression(expr)
        if not expression.hasParserError():
            req = QgsFeatureRequest(expression)
        else:
            raise GeoAlgorithmExecutionException(expression.parserErrorString())

        for f in layer.getFeatures(req):
            writer.addFeature(f)

        del writer
Пример #30
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT))
        expression_string = self.getParameterValue(self.EXPRESSION)
        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(layer.fields(), layer.wkbType(), layer.crs())

        expression = QgsExpression(expression_string)
        if not expression.hasParserError():
            req = QgsFeatureRequest().setFilterExpression(expression_string)
        else:
            raise GeoAlgorithmExecutionException(expression.parserErrorString())

        for f in layer.getFeatures(req):
            writer.addFeature(f)

        del writer
Пример #31
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 )
Пример #32
0
    def virtualFields(self, params: Dict[str,
                                         str], response: QgsServerResponse,
                      project: QgsProject) -> None:
        """ Get virtual fields for features
        In parameters:
            LAYER=wms-layer-name
            VIRTUALS={"key1": "first expression", "key2": "second expression"}
            // optionals
            FILTER=An expression to filter layer
            FIELDS=list of requested field separated by comma
            WITH_GEOMETRY=False
        """
        layername = params.get('LAYER', '')
        if not layername:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'VirtualFields' REQUEST: LAYER parameter is mandatory",
                400)

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

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

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

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

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

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

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

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

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

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

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

        req = QgsFeatureRequest()

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

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

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

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

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

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

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

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

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

            extra = {}

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

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

            response.write(separator +
                           jsonExporter.exportFeature(feat, extra, fid))
            response.flush()
            separator = ',\n'
        response.write(']}')
        return
Пример #33
0
    def evaluate(self, params: Dict[str, str], response: QgsServerResponse,
                 project: QgsProject) -> None:
        """ Evaluate expressions against layer or features
        In parameters:
            LAYER=wms-layer-name
            EXPRESSION=An expression to evaluate
            or
            EXPRESSIONS=["first expression", "second expression"]
            or
            EXPRESSIONS={"key1": "first expression", "key2": "second expression"}
            // optionals
            FEATURE={"type": "Feature", "geometry": {}, "properties": {}}
            or
            FEATURES=[{"type": "Feature", "geometry": {}, "properties": {}}, {"type": "Feature", "geometry": {}, "properties": {}}]
            FORM_SCOPE=boolean to add formScope based on provided features
        """

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        write_json_response(body, response)
        return
    def shortest_path(self, start_point, end_point):
        """ Calculating shortest path using dijkstra algorithm """

        args = []
        start_point_id = start_point
        end_point_id = end_point

        args.append(start_point_id)
        args.append(end_point_id)

        self.rnode_id = []
        self.rarc_id = []

        rstart_point = None
        sql = "SELECT rid"
        sql += " FROM " + self.schema_name + ".v_anl_pgrouting_node"
        sql += " WHERE node_id = '" + start_point + "'"
        row = self.controller.get_row(sql)
        if row:
            rstart_point = int(row[0])

        rend_point = None
        sql = "SELECT rid"
        sql += " FROM " + self.schema_name + ".v_anl_pgrouting_node"
        sql += " WHERE node_id = '" + end_point + "'"
        row = self.controller.get_row(sql)
        if row:
            rend_point = int(row[0])

        # Check starting and end points
        if rstart_point is None or rend_point is None:
            message = "Start point or end point not found"
            self.controller.show_warning(message)
            return

        # Clear list of arcs and nodes - preparing for new profile
        sql = "SELECT * FROM public.pgr_dijkstra('SELECT id::integer, source, target, cost"
        sql += " FROM " + self.schema_name + ".v_anl_pgrouting_arc', " + str(
            rstart_point) + ", " + str(rend_point) + ", false"
        if self.version == '2':
            sql += ", false"
        elif self.version == '3':
            pass
        else:
            message = "You need to upgrade your version of pg_routing!"
            self.controller.show_info(message)
            return
        sql += ")"

        rows = self.controller.get_rows(sql)
        for i in range(0, len(rows)):
            if self.version == '2':
                self.rnode_id.append(str(rows[i][1]))
                self.rarc_id.append(str(rows[i][2]))
            elif self.version == '3':
                self.rnode_id.append(str(rows[i][2]))
                self.rarc_id.append(str(rows[i][3]))

        self.rarc_id.pop()
        self.arc_id = []
        self.node_id = []

        for n in range(0, len(self.rarc_id)):
            # convert arc_ids
            sql = "SELECT arc_id"
            sql += " FROM " + self.schema_name + ".v_anl_pgrouting_arc"
            sql += " WHERE id = '" + str(self.rarc_id[n]) + "'"
            row = self.controller.get_row(sql)
            if row:
                self.arc_id.append(str(row[0]))

        for m in range(0, len(self.rnode_id)):
            # convert node_ids
            sql = "SELECT node_id"
            sql += " FROM " + self.schema_name + ".v_anl_pgrouting_node"
            sql += " WHERE rid = '" + str(self.rnode_id[m]) + "'"
            row = self.controller.get_row(sql)
            if row:
                self.node_id.append(str(row[0]))

        # Select arcs of the shortest path
        if rows:
            # Build an expression to select them
            aux = "\"arc_id\" IN ("
            for i in range(len(self.arc_id)):
                aux += "'" + str(self.arc_id[i]) + "', "
            aux = aux[:-2] + ")"
            expr = QgsExpression(aux)
            if expr.hasParserError():
                message = "Expression Error: " + str(expr.parserErrorString())
                self.controller.show_warning(message)
                return

            # Loop which is pasing trough all layer of arc_group searching for feature
            for layer_arc in self.group_pointers_arc:
                it = layer_arc.getFeatures(QgsFeatureRequest(expr))

                # Build a list of feature id's from the previous result
                id_list = [i.id() for i in it]

                # Select features with these id's
                layer_arc.selectByIds(id_list)

        # Select nodes of shortest path
        aux = "\"node_id\" IN ("
        for i in range(len(self.node_id)):
            aux += "'" + str(self.node_id[i]) + "', "
        aux = aux[:-2] + ")"
        expr = QgsExpression(aux)
        if expr.hasParserError():
            message = "Expression Error: " + str(expr.parserErrorString())
            self.controller.show_warning(message)
            return

        # Loop which is pasing trough all layers of node_group searching for feature
        for layer_node in self.group_pointers_node:

            it = layer_node.getFeatures(QgsFeatureRequest(expr))

            # Build a list of feature id's from the previous result
            self.id_list = [i.id() for i in it]

            # Select features with these id's
            layer_node.selectByIds(self.id_list)

            if self.id_list != []:
                layer = layer_node
                center_widget = self.id_list[0]

        # Center profile (first node)
        canvas = self.iface.mapCanvas()
        layer.selectByIds([center_widget])
        canvas.zoomToSelected(layer)

        self.tbl_list_arc = self.dlg.findChild(QListWidget, "tbl_list_arc")
        list_arc = []

        # Clear list
        self.tbl_list_arc.clear()

        for i in range(len(self.arc_id)):
            item_arc = QListWidgetItem(self.arc_id[i])
            self.tbl_list_arc.addItem(item_arc)
            list_arc.append(self.arc_id[i])

        self.dlg.findChild(QPushButton, "btn_draw").clicked.connect(
            partial(self.paint_event, self.arc_id, self.node_id))
        self.dlg.findChild(QPushButton, "btn_clear_profile").clicked.connect(
            self.clear_profile)
Пример #35
0
    def _buildfromlayer(self, widget, layerconfig):
        layername = layerconfig['layer']
        keyfield = layerconfig['key']
        valuefield = layerconfig['value']
        filterexp = layerconfig.get('filter', None)

        try:
            layer = QgsMapLayerRegistry.instance().mapLayersByName(layername)[0]
        except IndexError:
            roam.utils.warning("Can't find layer {} in project".format(layername))
            return

        keyfieldindex = layer.fieldNameIndex(keyfield)
        valuefieldindex = layer.fieldNameIndex(valuefield)
        if keyfieldindex == -1 or valuefieldindex == -1:
            roam.utils.warning("Can't find key or value column")
            return

        if self.allownulls:
            item = QStandardItem('(no selection)')
            item.setData(None, Qt.UserRole)
            self.listmodel.appendRow(item)

        if not filterexp and valuefieldindex == keyfieldindex:
            values = layer.uniqueValues(keyfieldindex)
            for value in values:
                value = nullconvert(value)
                item = QStandardItem(value)
                item.setData(value, Qt.UserRole)
                self.listmodel.appendRow(item)
            return

        attributes = {keyfieldindex, valuefieldindex}
        flags = QgsFeatureRequest.NoGeometry

        iconfieldindex =  layer.fieldNameIndex('icon')
        if iconfieldindex > -1:
            attributes.add(iconfieldindex)

        expression = None
        if filterexp:
            expression = QgsExpression(filterexp)
            expression.prepare(layer.pendingFields())
            if expression.hasParserError():
                roam.utils.warning("Expression has parser error: {}".format(expression.parserErrorString()))
                return

            if expression.needsGeometry():
                flags = QgsFeatureRequest.NoFlags

            for field in expression.referencedColumns():
                index = layer.fieldNameIndex(field)
                attributes.add(index)

        request = QgsFeatureRequest().setFlags(flags).setSubsetOfAttributes(list(attributes))
        for feature in layer.getFeatures(request):
            if expression and not expression.evaluate(feature):
                continue

            keyvalue = nullconvert(feature[keyfieldindex])
            valuvalue = nullconvert(feature[valuefield])
            try:
                path = feature[iconfieldindex]
                icon = QIcon(path)
            except KeyError:
                icon = QIcon()

            item = QStandardItem(unicode(keyvalue))
            item.setData(unicode(valuvalue), Qt.UserRole)
            item.setIcon(icon)
            self.listmodel.appendRow(item)
Пример #36
0
    def get_print(
        self, params: Dict[str, str], response: QgsServerResponse, project: QgsProject
    ) -> None:
        """ Get print document
        """

        template = params.get("TEMPLATE")
        feature_filter = params.get("EXP_FILTER", None)
        scale = params.get("SCALE")
        scales = params.get("SCALES")
        output_format = parse_output_format(params.get("FORMAT", params.get("format")))

        try:
            if not template:
                raise AtlasPrintException("TEMPLATE is required")

            if feature_filter:
                expression = QgsExpression(feature_filter)
                if expression.hasParserError():
                    raise AtlasPrintException(
                        "Expression is invalid: {}".format(
                            expression.parserErrorString()
                        )
                    )

            if scale and scales:
                raise AtlasPrintException("SCALE and SCALES can not be used together.")

            if scale:
                try:
                    scale = int(scale)
                except ValueError:
                    raise AtlasPrintException("Invalid number in SCALE.")

            if scales:
                try:
                    scales = [int(scale) for scale in scales.split(",")]
                except ValueError:
                    raise AtlasPrintException("Invalid number in SCALES.")

            additional_params = {
                k: v
                for k, v in params.items()
                if k
                not in (
                    "TEMPLATE",
                    "EXP_FILTER",
                    "SCALE",
                    "SCALES",
                    "FORMAT",
                    "MAP",
                    "REQUEST",
                    "SERVICE",
                )
            }
            Logger().info(
                "Additional params: " + str(additional_params["PERMIT_REQUEST_ID"])
            )
            # When the project has OAPIF datasources, the sources must first be reloaded.
            # In order to prevent massive request to DB, a basic server side filter is added
            OAPIFRefresher.refresh_geocity_oapif_layers_for_current_atlas_feature(
                additional_params["PERMIT_REQUEST_ID"]
            )
            Logger().info("Refreshed: " + str(additional_params["PERMIT_REQUEST_ID"]))

            output_path = print_layout(
                project=project,
                layout_name=params["TEMPLATE"],
                output_format=output_format,
                scale=scale,
                scales=scales,
                feature_filter=feature_filter,
                **additional_params,
            )
        except AtlasPrintException as e:
            raise AtlasPrintError(
                400,
                "ATLAS - Error from the user while generating the PDF: {}".format(e),
            )
        except Exception:
            self.logger.critical(
                "Unhandled exception:\n{}".format(traceback.format_exc())
            )
            raise AtlasPrintError(500, "Internal 'atlasprint' service error")

        path = Path(output_path)
        if not path.exists():
            raise AtlasPrintError(404, "ATLAS {} not found".format(output_format.name))

        # Send PDF
        response.setHeader("Content-Type", output_format.value)
        response.setStatusCode(200)
        try:
            response.write(path.read_bytes())
            path.unlink()
        except Exception:
            self.logger.critical(
                "Error occurred while reading {} file".format(output_format.name)
            )
            raise
Пример #37
0
def print_layout(
    project: QgsProject,
    layout_name: str,
    output_format: OutputFormat,
    feature_filter: str = None,
    scales: list = None,
    scale: int = 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

    :param output_format: The output format, default to PDF if not provided.

    :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 output_format == OutputFormat.Svg:
        settings = QgsLayoutExporter.SvgExportSettings()
    elif output_format in (OutputFormat.Png, OutputFormat.Jpeg):
        settings = QgsLayoutExporter.ImageExportSettings()
    else:
        # PDF by default
        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)
        atlas.updateFeatures()

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

        if scales:
            atlas_layout.referenceMap().setAtlasScalingMode(
                QgsLayoutItemMap.Predefined)
            settings.predefinedMapScales = scales

        if (not scales and atlas_layout.referenceMap().atlasScalingMode()
                == QgsLayoutItemMap.Predefined):
            use_project = project.useProjectScales()
            map_scales = project.mapScales()
            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()
            settings.predefinedMapScales = 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 "{key}" {found} in layout, value "{value}"'.
            format(key=key,
                   found="found" if found else "not found",
                   value=value))

    file_name = "{}_{}.{}".format(clean_string(layout_name), uuid4(),
                                  output_format.name.lower())
    export_path = Path(tempfile.gettempdir()).joinpath(file_name)

    Logger().info("Exporting the request in {} using {}".format(
        export_path, output_format.value))

    if output_format in (OutputFormat.Png, OutputFormat.Jpeg):
        exporter = QgsLayoutExporter(atlas_layout or report_layout)
        result = exporter.exportToImage(str(export_path), settings)
        error = result_message(result)
    elif output_format in (OutputFormat.Svg, ):
        exporter = QgsLayoutExporter(atlas_layout or report_layout)
        result = exporter.exportToSvg(str(export_path), settings)
        error = result_message(result)
    else:
        # Default to PDF
        result, error = QgsLayoutExporter.exportToPdf(atlas or report_layout,
                                                      str(export_path),
                                                      settings)
        # Let's override error message
        _ = error
        error = result_message(result)

    if result != QgsLayoutExporter.Success:
        raise Exception("Export not generated in QGIS exporter {} : {}".format(
            export_path, error))

    if not export_path.is_file():
        logger.warning(
            "No error from QGIS Exporter, but the file does not exist.\n"
            "Message from QGIS exporter : {}\n"
            "File path : {}\n".format(error, export_path))
        raise Exception(
            "Export OK from QGIS, but file not found on the file system : {}".
            format(export_path))

    return export_path
Пример #38
0
 def hydrometer_get_hydrometers(self):
     """ Populate hydrometers depending on selected connec """   
                             
     # Get selected connec
     selected = utils_giswater.getWidgetText(self.dlg.hydrometer_connec)
     
     # If any conenc selected, get again all hydrometers
     if selected == 'null':        
         self.populate_combo('hydrometer_layer', self.dlg.hydrometer_id, self.params['hydrometer_field_urban_propierties_code'], self.params['hydrometer_field_code'])            
         return
     
     # Get connec_id
     elem = self.dlg.hydrometer_connec.itemData(self.dlg.hydrometer_connec.currentIndex())
     code = elem[0] # to know the index see the query that populate the combo   
     records = [[-1, '']]
     
     # Set filter expression
     layer = self.layers['hydrometer_layer'] 
     idx_field_code = layer.fieldNameIndex(self.params['hydrometer_field_urban_propierties_code'])            
     idx_field_number = layer.fieldNameIndex(self.params['hydrometer_field_code'])   
     aux = self.params['hydrometer_field_urban_propierties_code'] + "  = '" + str(code) + "'"
     
     # Check filter and existence of fields       
     expr = QgsExpression(aux)     
     if expr.hasParserError():    
         message = expr.parserErrorString() + ": " + aux
         self.controller.show_warning(message)    
         return               
     if idx_field_code == -1:    
         message = "Field '{}' not found in layer '{}'. Open '{}' and check parameter '{}'" \
             .format(self.params['hydrometer_field_urban_propierties_code'], layer.name(), self.setting_file, 'hydrometer_field_urban_propierties_code')            
         self.controller.show_warning(message)         
         return      
     if idx_field_number == -1:    
         message = "Field '{}' not found in layer '{}'. Open '{}' and check parameter '{}'" \
             .format(self.params['hydrometer_field_code'], layer.name(), self.setting_file, 'hydrometer_field_code')            
         self.controller.show_warning(message)         
         return      
         
     # Get a featureIterator from an expression:
     # Get features from the iterator and do something
     it = layer.getFeatures(QgsFeatureRequest(expr))
     for feature in it: 
         attrs = feature.attributes() 
         field_number = attrs[idx_field_number]    
         if not type(field_number) is QPyNullVariant:
             elem = [code, field_number]
             records.append(elem)
               
     # Fill hydrometers
     records_sorted = sorted(records, key=operator.itemgetter(1))
     self.dlg.hydrometer_id.blockSignals(True)
     self.dlg.hydrometer_id.clear()
     hydrometer_list = []
     #hydrometer_list.append('')
     for record in records_sorted:
         self.dlg.hydrometer_id.addItem(str(record[1]), record)
         if record[1] != '':
             hydrometer_list.append(str(record[1]))
     self.set_model_by_list(hydrometer_list, self.dlg.hydrometer_id)
     self.hydrometer_zoom(self.params['hydrometer_urban_propierties_field_code'], self.dlg.hydrometer_connec)
     self.dlg.hydrometer_id.blockSignals(False)  
Пример #39
0
    def address_get_numbers(self, combo, field_code, fill_combo=False):
        """ Populate civic numbers depending on value of selected @combo. Build an expression with @field_code """

        # Get selected street
        selected = utils_giswater.getWidgetText(combo)
        if selected == 'null':
            return

        # Get street code
        elem = combo.itemData(combo.currentIndex())
        code = elem[0]  # to know the index see the query that populate the combo
        records = [[-1, '']]
        
        # Set filter expression
        layer = self.layers['portal_layer']
        idx_field_code = layer.fieldNameIndex(field_code)
        idx_field_number = layer.fieldNameIndex(self.params['portal_field_number'])
        aux = field_code + "  = '" + str(code) + "'"

        # Check filter and existence of fields
        expr = QgsExpression(aux)
        if expr.hasParserError():
            message = expr.parserErrorString() + ": " + aux
            self.controller.show_warning(message)
            return
        if idx_field_code == -1:
            message = "Field '{}' not found in layer '{}'. Open '{}' and check parameter '{}'" \
                .format(self.params['portal_field_code'], layer.name(), self.setting_file, 'portal_field_code')
            self.controller.show_warning(message)
            return
        if idx_field_number == -1:
            message = "Field '{}' not found in layer '{}'. Open '{}' and check parameter '{}'" \
                .format(self.params['portal_field_number'], layer.name(), self.setting_file, 'portal_field_number')
            self.controller.show_warning(message)
            return

        self.dlg.address_number.blockSignals(True)
        self.dlg.address_number.clear()

        if fill_combo:
            it = layer.getFeatures(QgsFeatureRequest(expr))
            for feature in it:
                attrs = feature.attributes()
                field_number = attrs[idx_field_number]
                if not type(field_number) is QPyNullVariant:
                    elem = [code, field_number]
                    records.append(elem)

            # Fill numbers combo
            records_sorted = sorted(records, key=operator.itemgetter(1))

            for record in records_sorted:
                self.dlg.address_number.addItem(str(record[1]), record)
            self.dlg.address_number.blockSignals(False)

        # Get a featureIterator from an expression:
        # Select featureswith the ids obtained
        it = layer.getFeatures(QgsFeatureRequest(expr))
        ids = [i.id() for i in it]
        layer.selectByIds(ids)

        # Zoom to selected feature of the layer
        self.zoom_to_selected_features(layer)
Пример #40
0
def layer_value(feature, layer, defaultconfig):
    if not canvas:
        roam.utils.warning(
            "No canvas set for using layer_values default function")
        return None
    layers = []
    # layer name can also be a list of layers to search
    layername = defaultconfig['layer']
    if isinstance(layername, basestring):
        layers.append(layername)
    else:
        layers = layername

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

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

            rect.scale(20)

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

        expression = expression.replace("$roamgeometry", "@roamgeometry")

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

        context = QgsExpressionContext()
        scope = QgsExpressionContextScope()
        context.appendScope(scope)
        scope.setVariable("roamgeometry", feature.geometry())

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

    raise DefaultError('No features found')
    def responseComplete(self):
        '''
        Send new response
        '''
        self.request = self.serverIface.requestHandler()
        params = self.request.parameterMap()

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

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

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

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

        self.project_path = params['MAP']
        self.composer_name = params['TEMPLATE']
        self.feature_filter = params['EXP_FILTER']

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

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

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

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

        return
Пример #42
0
    def get_print(self, params: Dict[str, str], response: QgsServerResponse,
                  project: QgsProject) -> None:
        """ Get print document
        """

        template = params.get('TEMPLATE')
        feature_filter = params.get('EXP_FILTER', None)
        scale = params.get('SCALE')
        scales = params.get('SCALES')

        try:
            if not template:
                raise AtlasPrintException('TEMPLATE is required')

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

            if scale and scales:
                raise AtlasPrintException(
                    'SCALE and SCALES can not be used together.')

            if scale:
                try:
                    scale = int(scale)
                except ValueError:
                    raise AtlasPrintException('Invalid number in SCALE.')

            if scales:
                try:
                    scales = [int(scale) for scale in scales.split(',')]
                except ValueError:
                    raise AtlasPrintException('Invalid number in SCALES.')

            additional_params = {
                k: v
                for k, v in params.items()
                if k not in ['TEMPLATE', 'EXP_FILTER', 'SCALE', 'SCALES']
            }

            pdf_path = print_layout(project=project,
                                    layout_name=params['TEMPLATE'],
                                    scale=scale,
                                    scales=scales,
                                    feature_filter=feature_filter,
                                    **additional_params)
        except AtlasPrintException as e:
            raise AtlasPrintError(
                400,
                'ATLAS - Error from the user while generating the PDF: {}'.
                format(e))
        except Exception:
            self.logger.critical("Unhandled exception:\n{}".format(
                traceback.format_exc()))
            raise AtlasPrintError(500, "Internal 'atlasprint' service error")

        path = Path(pdf_path)
        if not path.exists():
            raise AtlasPrintError(404, "ATLAS PDF not found")

        # Send PDF
        response.setHeader('Content-Type', 'application/pdf')
        response.setStatusCode(200)
        try:
            response.write(path.read_bytes())
            path.unlink()
        except Exception:
            self.logger.critical("Error occured while reading PDF file")
            raise
Пример #43
0
    def showExpressionsBuilder(self):
        context = createExpressionContext()
        dlg = QgsExpressionBuilderDialog(None, str(self.leText.text()), self,
                                         'generic', context)

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

        dlg.setWindowTitle(self.tr('Expression based input'))
        if dlg.exec_() == QDialog.Accepted:
            exp = QgsExpression(dlg.expressionText())
            if not exp.hasParserError():
                self.setValue(dlg.expressionText())
    def export_all_features(self):
        pdf_painter = None
        """Export map to pdf atlas style (one page per feature)"""
        if VRP_DEBUG is True: QgsMessageLog.logMessage(u'exporting map', DLG_CAPTION)
        try:

            result = self.__delete_pdf()
            if not result is None:
                return result

            ids = []
            exp = QgsExpression(self.feature_filter)
            if exp.hasParserError():
                raise Exception(exp.parserErrorString())
            exp.prepare(self.coverage_layer.pendingFields())
            for feature in self.coverage_layer.getFeatures():
                value = exp.evaluate(feature)
                if exp.hasEvalError():
                    raise ValueError(exp.evalErrorString())
                if bool(value):
                    if VRP_DEBUG is True: QgsMessageLog.logMessage(u'export map, feature id:{0}'.format(feature.id()), DLG_CAPTION)
                    ids.append(feature.id())
            self.coverage_layer.select(ids)
            bbox = self.coverage_layer.boundingBoxOfSelected()
            self.canvas.zoomToSelected(self.coverage_layer)
            if VRP_DEBUG is True: QgsMessageLog.logMessage(u'bbox:{0}'.format(bbox.toString()), DLG_CAPTION)

            #self.map_renderer.setExtent(bbox)
            #self.map_renderer.updateScale()

            #read plotlayout
            composition = QgsComposition(self.map_renderer)
            self.composition = composition
            composition.setPlotStyle(QgsComposition.Print)
            error, xml_doc = self.__read_template()
            if not error is None:
                return error
            if composition.loadFromTemplate(xml_doc) is False:
                return u'Konnte Template nicht laden!\n{0}'.format(self.template_qpt)

            #read textinfo layout
            self.comp_textinfo = QgsComposition(self.map_renderer)
            self.comp_textinfo.setPlotStyle(QgsComposition.Print)
            error, xml_doc = self.__read_template(True)
            if not error is None:
                return error
            if self.comp_textinfo.loadFromTemplate(xml_doc) is False:
                return u'Konnte Template nicht laden!\n{0}'.format(self.settings.textinfo_layout())


            new_ext = bbox
            if QGis.QGIS_VERSION_INT > 20200:
                compmaps = self.__get_items(QgsComposerMap)
                if len(compmaps) < 1:
                    return u'Kein Kartenfenster im Layout vorhanden!'
                compmap = compmaps[0]
            else:
                if len(composition.composerMapItems()) < 1:
                    return u'Kein Kartenfenster im Layout vorhanden!'
                compmap = composition.composerMapItems()[0]

            self.composermap = compmap
            #self.composermap.setPreviewMode(QgsComposerMap.Render)
            #self.composermap.setPreviewMode(QgsComposerMap.Rectangle)
            #taken from QgsComposerMap::setNewAtlasFeatureExtent (not yet available in QGIS 2.0)
            #http://www.qgis.org/api/qgscomposermap_8cpp_source.html#l00610
            old_ratio = compmap.rect().width() / compmap.rect().height()
            new_ratio = new_ext.width() / new_ext.height()
            if old_ratio < new_ratio:
                new_height = new_ext.width() / old_ratio
                delta_height = new_height - new_ext.height()
                new_ext.setYMinimum( bbox.yMinimum() - delta_height / 2)
                new_ext.setYMaximum(bbox.yMaximum() + delta_height / 2)
            else:
                new_width = old_ratio * new_ext.height()
                delta_width = new_width - new_ext.width()
                new_ext.setXMinimum(bbox.xMinimum() - delta_width / 2)
                new_ext.setXMaximum(bbox.xMaximum() + delta_width / 2)

            if VRP_DEBUG is True: QgsMessageLog.logMessage(u'bbox old:{0}'.format(compmap.extent().toString()), DLG_CAPTION)
            compmap.setNewExtent(new_ext)
            if VRP_DEBUG is True: QgsMessageLog.logMessage(u'bbox new:{0}'.format(compmap.extent().toString()), DLG_CAPTION)
            #round up to next 1000
            compmap.setNewScale(math.ceil((compmap.scale()/1000.0)) * 1000.0)
            if VRP_DEBUG is True: QgsMessageLog.logMessage(u'bbox new (after scale):{0}'.format(compmap.extent().toString()), DLG_CAPTION)

            #add ORTHO after new extent -> performance
            if not self.ortho is None:
                self.ortho_lyr = self.__add_raster_layer(self.ortho, self.lyrname_ortho)
                self.__reorder_layers()

            self.comp_leg = self.__get_items(QgsComposerLegend)
            self.comp_lbl = self.__get_items(QgsComposerLabel)


            self.__update_composer_items(self.settings.dkm_gemeinde(self.gem_name)['lyrnamegstk'])

            if VRP_DEBUG is True:
                QgsMessageLog.logMessage(u'paperWidth:{0} paperHeight:{1}'.format(composition.paperWidth(), composition.paperHeight()), DLG_CAPTION)

            printer = QPrinter()
            printer.setOutputFormat(QPrinter.PdfFormat)
            printer.setOutputFileName(self.pdf_map)
            printer.setPaperSize(QSizeF(composition.paperWidth(), composition.paperHeight()), QPrinter.Millimeter)
            printer.setFullPage(True)
            printer.setColorMode(QPrinter.Color)
            printer.setResolution(composition.printResolution())

            pdf_painter = QPainter(printer)
            paper_rect_pixel = printer.pageRect(QPrinter.DevicePixel)
            paper_rect_mm = printer.pageRect(QPrinter.Millimeter)
            QgsPaintEngineHack.fixEngineFlags(printer.paintEngine())
            #DKM only
            if len(self.themen) < 1:
                composition.render(pdf_painter, paper_rect_pixel, paper_rect_mm)
            else:
                self.statistics = OrderedDict()
                try:
                    pass
                    #lyr = QgsVectorLayer('/home/bergw/VoGIS-Raumplanung-Daten/Geodaten/Raumplanung/Flaechenwidmung/Dornbirn/Flaechenwidmungsplan/fwp_flaeche.shp', 'flaeiw', 'ogr')
                    #lyr.loadNamedStyle('/home/bergw/VoGIS-Raumplanung-Daten/Geodaten/Raumplanung/Flaechenwidmung/Vorarlberg/Flaechenwidmungsplan/fwp_flaeche.qml')
                    #QgsMapLayerRegistry.instance().addMapLayer(lyr)
                except:
                    QgsMessageLog.logMessage('new lyr:{0}'.format(sys.exc_info()[0]), DLG_CAPTION)
                #QgsMapLayerRegistry.instance().addMapLayer(lyr)
                cntr = 0
                for thema, sub_themen in self.themen.iteritems():
                    if VRP_DEBUG is True: QgsMessageLog.logMessage('drucke Thema:{0}'.format(thema.name), DLG_CAPTION)
                    if sub_themen is None:
                        layers = self.__add_layers(thema)
                        self.__calculate_statistics(thema, thema, layers)
                        #no qml -> not visible -> means no map
                        if self.__at_least_one_visible(layers) is True:
                            if cntr > 0:
                                printer.newPage()
                            self.__reorder_layers()
                            self.__update_composer_items(thema.name, layers=layers)
                            composition.renderPage(pdf_painter, 0)
                            QgsMapLayerRegistry.instance().removeMapLayers([lyr.id() for lyr in layers])
                            cntr += 1
                        else:
                            QgsMapLayerRegistry.instance().removeMapLayers([lyr.id() for lyr in layers])
                    if not sub_themen is None:
                        for sub_thema in sub_themen:
                            if VRP_DEBUG is True: QgsMessageLog.logMessage(u'drucke SubThema:{0}'.format(sub_thema.name), DLG_CAPTION)
                            layers = self.__add_layers(sub_thema)
                            self.__calculate_statistics(thema, sub_thema, layers)
                            #no qml -> not visible -> means no map
                            if self.__at_least_one_visible(layers) is True:
                                if cntr > 0:
                                    printer.newPage()
                                self.__reorder_layers()
                                self.__update_composer_items(thema.name, subthema=sub_thema.name, layers=layers)
                                composition.renderPage(pdf_painter, 0)
                                QgsMapLayerRegistry.instance().removeMapLayers([lyr.id() for lyr in layers])
                                cntr += 1
                            else:
                                QgsMapLayerRegistry.instance().removeMapLayers([lyr.id() for lyr in layers])
            #output statistics
            if len(self.statistics) > 0:
                printer.setPaperSize(QSizeF(210, 297), QPrinter.Millimeter)
                tabelle = self.__get_item_byid(self.comp_textinfo, 'TABELLE')
                if tabelle is None:
                    self.iface.messageBar().pushMessage(u'Layout (Textinfo): Kein Textelement mit ID "TABELLE" vorhanden.', QgsMessageBar.CRITICAL)
                else:
                    try:
                        str_flaechen = ''
                        idx = 0
                        for gnr, stats in self.statistics.iteritems():
                            comma = ', ' if idx > 0 else ''
                            str_flaechen += u'{0}{1} ({2:.2f}m²)'.format(comma, gnr, stats[0].flaeche)
                            idx += 1
                        lbls = self.__get_items(QgsComposerLabel, self.comp_textinfo)
                        self.__update_composer_items('', labels=lbls, gnrflaeche=str_flaechen)
                        html = tabelle.text()
                        html += u'<table>'
                        #gnrcnt = 0
                        for gnr, stats in self.statistics.iteritems():
                            #if gnrcnt > 0:
                            #    html += u'<tr class="abstand"><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>'
                            html += u'<tr><th class="gnr"></th><th class="gnr">{0}</th><th class="gnr"></th></tr>'.format(gnr)
                            #html += u'<tr class="abstand"><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>'
                            curr_thema = ''
                            for stat in stats:
                                if stat.thema != curr_thema:
                                    html += u'<tr><th class="thema"></th><th class="thema">{0}</th><th class="thema"></th></tr>'.format(stat.thema)
                                curr_thema = stat.thema
                                for thema, subthema in stat.subthemen.iteritems():
                                    for quelle in subthema:
                                        html += u'<tr><td class="col1">{0}</td>'.format(quelle.name)
                                        attr_val = ''
                                        attr_area = ''
                                        for text, area in quelle.txt_area.iteritems():
                                            attr_val += u'{0}<br />'.format(text)
                                            attr_area += u'{0:.2f}m² <br />'.format(area)
                                        html += u'<td class="col2">{0}</td><td class="col3">{1}</td></tr>'.format(attr_val, attr_area)
                            #gnrcnt += 1
                        html += u'</table>'
                        tabelle.setText(html)
                        printer.newPage()
                        self.comp_textinfo.renderPage(pdf_painter, 0)
                    except:
                        msg = 'Statistikausgabe:\n\n{0}'.format(traceback.format_exc())
                        QgsMessageLog.logMessage(msg, DLG_CAPTION)
                        self.iface.messageBar().pushMessage(msg, QgsMessageBar.CRITICAL)
        except:
            msg = 'export pdf (catch all):\n\n{0}'.format(traceback.format_exc())
            QgsMessageLog.logMessage(msg, DLG_CAPTION)
            self.iface.messageBar().pushMessage(msg.replace(u'\n', u''), QgsMessageBar.CRITICAL)
            return msg
        finally:
            #end pdf
            if not pdf_painter is None:
                pdf_painter.end()
        return None
Пример #45
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        if source is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUT))

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

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

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

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

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

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

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

            if not f.hasGeometry():
                continue

            current_progress = total * current
            feedback.setProgress(current_progress)

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

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

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

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

            index = QgsSpatialIndex()
            points = dict()

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

            random.seed()

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

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

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

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

        feedback.setProgress(100)

        return {self.OUTPUT: dest_id}
Пример #46
0
    def processAlgorithm(self, progress):
        layer = self.getParameterValue(self.INPUT_LAYER)
        mapping = self.getParameterValue(self.FIELDS_MAPPING)
        output = self.getOutputFromName(self.OUTPUT_LAYER)

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

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

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

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

            outFeat.setGeometry(inFeat.geometry())

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

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

            writer.addFeature(outFeat)

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

        del writer

        if not calculationSuccess:
            raise GeoAlgorithmExecutionException(
                self.tr('An error occurred while evaluating the calculation'
                        ' string:\n') + error)
Пример #47
0
    def save_vector_data(self,
                         metadata_layer,
                         post_layer_data,
                         has_transactions,
                         post_save_signal=True,
                         **kwargs):
        """Save vector editing data

        :param metadata_layer: metadata of the layer being edited
        :type metadata_layer: MetadataVectorLayer
        :param post_layer_data: post data with 'add', 'delete' etc.
        :type post_layer_data: dict
        :param has_transactions: true if the layer support transactions
        :type has_transactions: bool
        :param post_save_signal: if this is a post_save_signal call, defaults to True
        :type post_save_signal: bool, optional
        """

        # Check atomic capabilities for validation
        # -----------------------------------------------
        #for mode_editing in (EDITING_POST_DATA_ADDED, EDITING_POST_DATA_UPDATED, EDITING_POST_DATA_DELETED):

        # try to get layer model object from metatada_layer
        layer = getattr(metadata_layer, 'layer', self.layer)

        if EDITING_POST_DATA_ADDED in post_layer_data and len(
                post_layer_data[EDITING_POST_DATA_ADDED]) > 0:
            if not self.request.user.has_perm('qdjango.add_feature', layer):
                raise ValidationError(
                    _('Sorry but your user doesn\'t has \'Add Feature\' capability'
                      ))

        if EDITING_POST_DATA_DELETED in post_layer_data and len(
                post_layer_data[EDITING_POST_DATA_DELETED]) > 0:
            if not self.request.user.has_perm('qdjango.delete_feature', layer):
                raise ValidationError(
                    _('Sorry but your user doesn\'t has \'Delete Feature\' capability'
                      ))

        if EDITING_POST_DATA_UPDATED in post_layer_data and len(
                post_layer_data[EDITING_POST_DATA_UPDATED]) > 0:
            if not self.request.user.has_perm('qdjango.change_feature', layer) and \
                    not self.request.user.has_perm('qdjango.change_attr_feature', layer):
                raise ValidationError(
                    _('Sorry but your user doesn\'t has \'Change or Change Attributes Features\' capability'
                      ))

        # get initial featurelocked
        metadata_layer.lock.getInitialFeatureLockedIds()

        # get lockids from client
        metadata_layer.lock.setLockeFeaturesFromClient(
            post_layer_data['lockids'])

        # data for response
        insert_ids = list()
        lock_ids = list()

        # FIXME: check this out
        # for add check if is a metadata_layer and referenced field is a pk
        is_referenced_field_is_pk = 'referenced_layer_insert_ids' in kwargs and kwargs['referenced_layer_insert_ids'] \
            and hasattr(metadata_layer, 'referenced_field_is_pk') \
            and metadata_layer.referenced_field_is_pk

        # Get the layer
        qgis_layer = metadata_layer.qgis_layer

        for mode_editing in (EDITING_POST_DATA_ADDED,
                             EDITING_POST_DATA_UPDATED):

            if mode_editing in post_layer_data:

                for geojson_feature in post_layer_data[mode_editing]:
                    data_extra_fields = {'feature': geojson_feature}

                    # Clear any old error
                    qgis_layer.dataProvider().clearErrors()

                    # add media data
                    self.add_media_property(geojson_feature, metadata_layer)

                    # for GEOSGeometry of Django 2.2 it must add crs to feature if is not set if a geo feature
                    if metadata_layer.geometry_type != QGIS_LAYER_TYPE_NO_GEOM:
                        if geojson_feature[
                                'geometry'] and 'crs' not in geojson_feature[
                                    'geometry']:
                            geojson_feature['geometry'][
                                'crs'] = "{}:{}".format(
                                    self.layer.project.group.srid.auth_name,
                                    self.layer.project.group.srid.auth_srid)

                    # reproject data if necessary
                    if kwargs[
                            'reproject'] and metadata_layer.geometry_type != QGIS_LAYER_TYPE_NO_GEOM:
                        self.reproject_feature(geojson_feature, to_layer=True)

                    # case relation data ADD, if father referenced field is pk
                    if is_referenced_field_is_pk:
                        for newid in kwargs['referenced_layer_insert_ids']:
                            if geojson_feature['properties'][
                                    metadata_layer.
                                    referencing_field] == newid['clientid']:
                                geojson_feature['properties'][
                                    metadata_layer.
                                    referencing_field] = newid['id']

                    if mode_editing == EDITING_POST_DATA_UPDATED:
                        # control feature locked
                        if not metadata_layer.lock.checkFeatureLocked(
                                geojson_feature['id']):
                            raise Exception(
                                self.no_more_lock_feature_msg.format(
                                    geojson_feature['id'],
                                    metadata_layer.client_var))

                    # Send for validation
                    # Note that this may raise a validation error
                    pre_save_maplayer.send(self,
                                           layer_metadata=metadata_layer,
                                           mode=mode_editing,
                                           data=data_extra_fields,
                                           user=self.request.user)

                    # Validate and save
                    try:

                        original_feature = None
                        feature = QgsFeature(qgis_layer.fields())
                        if mode_editing == EDITING_POST_DATA_UPDATED:

                            # add patch for shapefile type, geojson_feature['id'] id int() instead of str()
                            # path to fix into QGIS api
                            geojson_feature[
                                'id'] = get_layer_fids_from_server_fids(
                                    [str(geojson_feature['id'])],
                                    qgis_layer)[0]
                            feature.setId(geojson_feature['id'])

                            # Get feature from data provider before update
                            original_feature = qgis_layer.getFeature(
                                geojson_feature['id'])

                        # We use this feature for geometry parsing only:
                        imported_feature = QgsJsonUtils.stringToFeatureList(
                            json.dumps(geojson_feature),
                            qgis_layer.fields(),
                            None  # UTF8 codec
                        )[0]

                        feature.setGeometry(imported_feature.geometry())

                        # There is something wrong in QGIS 3.10 (fixed in later versions)
                        # so, better loop through the fields and set attributes individually
                        for name, value in geojson_feature['properties'].items(
                        ):
                            feature.setAttribute(name, value)

                        # Loop again for set expressions value:
                        # For update store expression result to use later into update condition
                        field_expresion_values = {}
                        for qgis_field in qgis_layer.fields():
                            if qgis_field.defaultValueDefinition().expression(
                            ):
                                exp = QgsExpression(
                                    qgis_field.defaultValueDefinition(
                                    ).expression())
                                if exp.rootNode().nodeType(
                                ) != QgsExpressionNode.ntLiteral and not exp.hasParserError(
                                ):
                                    context = QgsExpressionContextUtils.createFeatureBasedContext(
                                        feature, qgis_layer.fields())
                                    context.appendScopes(
                                        QgsExpressionContextUtils.
                                        globalProjectLayerScopes(qgis_layer))
                                    result = exp.evaluate(context)
                                    if not exp.hasEvalError():
                                        feature.setAttribute(
                                            qgis_field.name(), result)

                                        # Check update if expression default value has to run also on update e not
                                        # only on insert newone
                                        if qgis_field.defaultValueDefinition(
                                        ).applyOnUpdate():
                                            field_expresion_values[
                                                qgis_field.name()] = result

                            elif qgis_field.typeName() in ('date', 'datetime',
                                                           'time'):

                                if qgis_field.typeName() == 'date':
                                    qtype = QDate
                                elif qgis_field.typeName() == 'datetime':
                                    qtype = QDateTime
                                else:
                                    qtype = QTime

                                field_idx = qgis_layer.fields().indexFromName(
                                    qgis_field.name())
                                options = qgis_layer.editorWidgetSetup(
                                    field_idx).config()

                                if 'field_iso_format' in options and not options[
                                        'field_iso_format']:
                                    if geojson_feature['properties'][
                                            qgis_field.name()]:
                                        value = qtype.fromString(
                                            geojson_feature['properties'][
                                                qgis_field.name()],
                                            options['field_format'])
                                        feature.setAttribute(
                                            qgis_field.name(), value)

                        # Call validator!
                        errors = feature_validator(feature,
                                                   metadata_layer.qgis_layer)
                        if errors:
                            raise ValidationError(errors)

                        # Save the feature
                        if mode_editing == EDITING_POST_DATA_ADDED:
                            if has_transactions:
                                if not qgis_layer.addFeature(feature):
                                    raise Exception(
                                        _('Error adding feature: %s') %
                                        ', '.join(qgis_layer.dataProvider().
                                                  errors()))
                            else:
                                if not qgis_layer.dataProvider().addFeature(
                                        feature):
                                    raise Exception(
                                        _('Error adding feature: %s') %
                                        ', '.join(qgis_layer.dataProvider().
                                                  errors()))

                                # Patch for Spatialite provider on pk
                                if qgis_layer.dataProvider().name(
                                ) == 'spatialite':
                                    pks = qgis_layer.primaryKeyAttributes()
                                    if len(pks) > 1:
                                        raise Exception(
                                            _(f'Error adding feature on Spatialite provider: '
                                              f'layer {qgis_layer.id()} has more than one pk column'
                                              ))

                                    # update pk attribute:
                                    feature.setAttribute(
                                        pks[0],
                                        server_fid(feature,
                                                   qgis_layer.dataProvider()))

                        elif mode_editing == EDITING_POST_DATA_UPDATED:
                            attr_map = {}
                            for name, value in geojson_feature[
                                    'properties'].items():
                                if name in qgis_layer.dataProvider(
                                ).fieldNameMap():
                                    if name in field_expresion_values:
                                        value = field_expresion_values[name]
                                    attr_map[qgis_layer.dataProvider().
                                             fieldNameMap()[name]] = value

                            if has_transactions:
                                if not qgis_layer.changeAttributeValues(
                                        geojson_feature['id'], attr_map):
                                    raise Exception(
                                        _('Error changing attribute values: %s'
                                          ) %
                                        ', '.join(qgis_layer.dataProvider().
                                                  errors()))
                                # Check for errors because of https://github.com/qgis/QGIS/issues/36583
                                if qgis_layer.dataProvider().errors():
                                    raise Exception(', '.join(
                                        qgis_layer.dataProvider().errors()))
                                if not feature.geometry().isNull(
                                ) and not qgis_layer.changeGeometry(
                                        geojson_feature['id'],
                                        feature.geometry()):
                                    raise Exception(
                                        _('Error changing geometry: %s') %
                                        ', '.join(qgis_layer.dataProvider().
                                                  errors()))
                            else:
                                if not qgis_layer.dataProvider(
                                ).changeAttributeValues(
                                    {geojson_feature['id']: attr_map}):
                                    raise Exception(
                                        _('Error changing attribute values: %s'
                                          ) %
                                        ', '.join(qgis_layer.dataProvider().
                                                  errors()))
                                if not feature.geometry().isNull(
                                ) and not qgis_layer.dataProvider(
                                ).changeGeometryValues({
                                        geojson_feature['id']:
                                        feature.geometry()
                                }):
                                    raise Exception(
                                        _('Error changing geometry: %s') %
                                        ', '.join(qgis_layer.dataProvider().
                                                  errors()))

                        to_res = {}
                        to_res_lock = {}

                        if mode_editing == EDITING_POST_DATA_ADDED:

                            # to exclude QgsFormater used into QgsJsonjExporter is necessary build by hand single json feature
                            ex = QgsJsonExporter(qgis_layer)
                            ex.setIncludeAttributes(False)

                            fnames = [f.name() for f in feature.fields()]
                            jfeature = json.loads(
                                ex.exportFeature(
                                    feature,
                                    dict(zip(fnames, feature.attributes()))))

                            to_res.update({
                                'clientid':
                                geojson_feature['id'],
                                # This might be the internal QGIS feature id (< 0)
                                'id':
                                server_fid(
                                    feature,
                                    metadata_layer.qgis_layer.dataProvider()),
                                'properties':
                                jfeature['properties']
                            })

                            # lock news:
                            to_res_lock = metadata_layer.lock.modelLock2dict(
                                metadata_layer.lock.lockFeature(server_fid(
                                    feature,
                                    metadata_layer.qgis_layer.dataProvider()),
                                                                save=True))

                        if bool(to_res):
                            insert_ids.append(to_res)
                        if bool(to_res_lock):
                            lock_ids.append(to_res_lock)

                        # Send post vase signal
                        post_save_maplayer.send(
                            self,
                            layer_metadata=metadata_layer,
                            mode=mode_editing,
                            data=data_extra_fields,
                            user=self.request.user,
                            original_feature=original_feature,
                            to_res=to_res)

                    except ValidationError as ex:
                        raise ValidationError({
                            metadata_layer.client_var: {
                                mode_editing: {
                                    'id': geojson_feature['id'],
                                    'fields': ex.detail,
                                }
                            }
                        })

                    except Exception as ex:
                        raise ValidationError({
                            metadata_layer.client_var: {
                                mode_editing: {
                                    'id': geojson_feature['id'],
                                    'fields': str(ex),
                                }
                            }
                        })

        # erasing feature if to do
        if EDITING_POST_DATA_DELETED in post_layer_data:

            fids = post_layer_data[EDITING_POST_DATA_DELETED]

            # get feature fids from server fids from client.
            fids = get_layer_fids_from_server_fids([str(id) for id in fids],
                                                   qgis_layer)

            for feature_id in fids:

                # control feature locked
                if not metadata_layer.lock.checkFeatureLocked(str(feature_id)):
                    raise Exception(
                        self.no_more_lock_feature_msg.format(
                            feature_id, metadata_layer.client_var))

                # Get feature to delete
                ex = QgsJsonExporter(qgis_layer)
                deleted_feature = ex.exportFeature(
                    qgis_layer.getFeature(feature_id))

                pre_delete_maplayer.send(self,
                                         layer_metatada=metadata_layer,
                                         data=deleted_feature,
                                         user=self.request.user)

                qgis_layer.dataProvider().clearErrors()

                if has_transactions:
                    if not qgis_layer.deleteFeatures(
                        [feature_id]) or qgis_layer.dataProvider().errors():
                        raise Exception(
                            _('Cannot delete feature: %s') %
                            ', '.join(qgis_layer.dataProvider().errors()))
                else:
                    if not qgis_layer.dataProvider().deleteFeatures(
                        [feature_id]) or qgis_layer.dataProvider().errors():
                        raise Exception(
                            _('Cannot delete feature: %s') %
                            ', '.join(qgis_layer.dataProvider().errors()))

        return insert_ids, lock_ids
Пример #48
0
    def processAlgorithm(self, feedback):
        layer = self.getParameterValue(self.INPUT_LAYER)
        mapping = self.getParameterValue(self.FIELDS_MAPPING)
        output = self.getOutputFromName(self.OUTPUT_LAYER)

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

        da = QgsDistanceArea()
        da.setSourceCrs(layer.crs())
        da.setEllipsoidalMode(True)
        da.setEllipsoid(QgsProject.instance().ellipsoid())

        exp_context = layer.createExpressionContext()

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

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

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

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

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

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

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

                writer.addFeature(outFeat)

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

        del writer

        if error_exp is not None:
            raise GeoAlgorithmExecutionException(
                self.tr(u'Evaluation error in expression "{}": {}').format(
                    str(error_exp.expression()),
                    str(error_exp.parserErrorString())))
Пример #49
0
    def processAlgorithm(self, progress):
        layer = self.getParameterValue(self.INPUT_LAYER)
        mapping = self.getParameterValue(self.FIELDS_MAPPING)
        output = self.getOutputFromName(self.OUTPUT_LAYER)

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

        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(
                        unicode(field_def['expression']),
                        unicode(expression.parserErrorString())))
            expression.prepare(exp_context)
            if expression.hasEvalError():
                raise GeoAlgorithmExecutionException(
                    self.tr(u'Evaluation error in expression "{}": {}').format(
                        unicode(field_def['expression']),
                        unicode(expression.evalErrorString())))
            expressions.append(expression)

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

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

            geometry = inFeat.geometry()
            if geometry is not None:
                outFeat.setGeometry(geometry)

            attrs = []
            for i in xrange(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)
Пример #50
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        if source is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUT))

        close_path = self.parameterAsBool(parameters, self.CLOSE_PATH, context)
        group_field_name = self.parameterAsString(parameters, self.GROUP_FIELD,
                                                  context)
        order_field_name = self.parameterAsString(parameters, self.ORDER_FIELD,
                                                  context)
        order_expression = self.parameterAsString(parameters,
                                                  self.ORDER_EXPRESSION,
                                                  context)
        date_format = self.parameterAsString(parameters, self.DATE_FORMAT,
                                             context)
        text_dir = self.parameterAsString(parameters, self.OUTPUT_TEXT_DIR,
                                          context)

        group_field_index = source.fields().lookupField(group_field_name)

        if group_field_index >= 0:
            group_field_def = source.fields().at(group_field_index)
        else:
            group_field_def = None

        if order_field_name:
            order_expression = QgsExpression.quotedColumnRef(order_field_name)

        if not order_expression:
            raise QgsProcessingException(
                self.tr('ORDER_EXPRESSION parameter is missing.'))

        expression_context = self.createExpressionContext(
            parameters, context, source)
        expression = QgsExpression(order_expression)
        if expression.hasParserError():
            raise QgsProcessingException(expression.parserErrorString())
        expression.prepare(expression_context)
        order_field_type = QVariant.String
        if expression.isField():
            field_name = next(iter(expression.referencedColumns()))
            order_field_type = source.fields().field(field_name).type()

        fields = QgsFields()
        if group_field_def is not None:
            fields.append(group_field_def)
        begin_field = QgsField('begin', order_field_type)
        fields.append(begin_field)
        end_field = QgsField('end', order_field_type)
        fields.append(end_field)

        output_wkb = QgsWkbTypes.LineString
        if QgsWkbTypes.hasM(source.wkbType()):
            output_wkb = QgsWkbTypes.addM(output_wkb)
        if QgsWkbTypes.hasZ(source.wkbType()):
            output_wkb = QgsWkbTypes.addZ(output_wkb)

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

        if text_dir and not (os.path.exists(text_dir)):
            raise QgsProcessingException(
                self.tr("The text output directory does not exist"))

        points = dict()
        required_fields = expression.referencedColumns()
        required_fields.add(group_field_name)
        features = source.getFeatures(
            QgsFeatureRequest().setSubsetOfAttributes(required_fields,
                                                      source.fields()),
            QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks)
        total = 100.0 / source.featureCount() if source.featureCount() else 0
        for current, f in enumerate(features):
            if feedback.isCanceled():
                break

            if not f.hasGeometry():
                continue

            point = f.geometry().constGet().clone()
            if group_field_index >= 0:
                group = f[group_field_index]
            else:
                group = 1
            expression_context.setFeature(f)
            order = expression.evaluate(expression_context)
            if date_format != '':
                order = datetime.strptime(str(order), date_format)
            if group in points:
                points[group].append((order, point))
            else:
                points[group] = [(order, point)]

            feedback.setProgress(int(current * total))

        feedback.setProgress(0)

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

        current = 0
        total = 100.0 / len(points) if points else 1
        for group, vertices in points.items():
            if feedback.isCanceled():
                break

            vertices.sort(key=lambda x: (x[0] is None, x[0]))
            f = QgsFeature()
            attributes = []
            if group_field_index >= 0:
                attributes.append(group)
            attributes.extend([vertices[0][0], vertices[-1][0]])
            f.setAttributes(attributes)
            line = [node[1] for node in vertices]

            if close_path is True:
                if line[0] != line[-1]:
                    line.append(line[0])

            if text_dir:
                fileName = os.path.join(text_dir, '%s.txt' % group)

                with open(fileName, 'w') as fl:
                    fl.write('angle=Azimuth\n')
                    fl.write('heading=Coordinate_System\n')
                    fl.write('dist_units=Default\n')

                    for i in range(len(line)):
                        if i == 0:
                            fl.write('startAt=%f;%f;90\n' %
                                     (line[i].x(), line[i].y()))
                            fl.write('survey=Polygonal\n')
                            fl.write('[data]\n')
                        else:
                            angle = line[i - 1].azimuth(line[i])
                            distance = da.measureLine(QgsPointXY(line[i - 1]),
                                                      QgsPointXY(line[i]))
                            fl.write('%f;%f;90\n' % (angle, distance))

            f.setGeometry(QgsGeometry(QgsLineString(line)))
            sink.addFeature(f, QgsFeatureSink.FastInsert)
            current += 1
            feedback.setProgress(int(current * total))

        return {self.OUTPUT: dest_id}
Пример #51
0
    def data( self ):
        if self._dataLoaded:
            return self._x, self._y, self._z
        self._dataLoaded=True
        self._x = None
        self._y = None
        self._z = None
        self._gridShape=None
        self._gridTested=False
        self._dataLoaded=True

        source=self._source
        zField=self._zField
        if source is None or zField is None or zField == '':
            return self._x, self._y, self._z

        discardTolerance=self._discardTolerance
        feedback=self._feedback

        total = source.featureCount()
        percent = 100.0 / total if total > 0 else 0

        count = 0
        x = list()
        y = list()
        z = list()
        try:
            if source.fields().lookupField(zField) >= 0:
                zField='"'+zField.replace('"','""')+'"'
            expression=QgsExpression(zField)
            if expression.hasParserError():
                raise ContourError(tr("Cannot parse")+" "+zField)
            fields=source.fields()
            context=QgsExpressionContext()
            context.setFields(fields)
            if not expression.prepare(context):
                raise ContourError(tr("Cannot evaluate value")+ " "+zField)
            request = QgsFeatureRequest()
            request.setSubsetOfAttributes( expression.referencedColumns(),fields)
            if self._sourceFids is not None:
                request.setFilterFids(self._sourceFids)
            for current,feat in enumerate(source.getFeatures( request )):
                try:
                    if feedback.isCanceled():
                        raise ContourError('Cancelled by user')
                    feedback.setProgress(int(current * percent))
                    context.setFeature(feat)
                    zval=expression.evaluate(context)
                    if zval is None or (isinstance(zval,QVariant) and zval.isNull()):
                        continue
                    try:
                        zval=float(zval)
                    except ValueError:
                        raise ContourError(tr("Z value {0} is not number")
                                                   .format(zval))
                    if zval is not None:
                        fgeom = feat.geometry()
                        if QgsWkbTypes.flatType(fgeom.wkbType()) != QgsWkbTypes.Point:
                            raise ContourError(tr("Invalid geometry type for contouring - must be point geometry"))
                        geom=fgeom.asPoint()
                        x.append(geom.x())
                        y.append(geom.y())
                        z.append(zval)
                except Exception as ex:
                    raise
                count = count + 1

            npt=len(x)
            if npt > 0:
                x=np.array(x)
                y=np.array(y)
                z=np.array(z)
                if discardTolerance > 0:
                    index=ContourUtils.discardDuplicatePoints(
                        x,y,discardTolerance,self.crs().isGeographic())
                    npt1=len(index)
                    if npt1 < npt:
                        x=x[index]
                        y=y[index]
                        z=z[index]
                        feedback.pushInfo(tr("{0} near duplicate points discarded - tolerance {1}")
                                          .format(npt-npt1,discardTolerance))
        except ContourError as ce:
            feedback.reportError(ce.message())
            feedback.setProgress(0)
            return self._x,self._y,self._z
        finally:
            feedback.setProgress(0)

        if len(x) < 3:
            feedback.reportError(tr("Too few points to contour"))
            return self._x, self._y, self._z
        self._x=x
        self._y=y
        self._z=z
        return self._x, self._y, self._z
Пример #52
0
    def showExpressionsBuilder(self):
        context = self.param.expressionContext()
        dlg = QgsExpressionBuilderDialog(None, str(self.leText.text()), self,
                                         'generic', context)

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

        dlg.setWindowTitle(self.tr('Expression based input'))
        if dlg.exec_() == QDialog.Accepted:
            exp = QgsExpression(dlg.expressionText())
            if not exp.hasParserError():
                self.setValue(dlg.expressionText())
Пример #53
0
    def convert(expression: str, engine, advanced, context: Context):  # pylint: disable=too-many-branches
        """
        Converts an expression which uses the specified engine
        """
        expression_type = ''
        if isinstance(engine, AnnotationVBScriptEngine):
            expression_type = 'VBScript'
        elif isinstance(engine, AnnotationPythonEngine):
            expression_type = 'Python'
        elif isinstance(engine, AnnotationJScriptEngine):
            expression_type = 'JScript'

        if advanced:
            if context.unsupported_object_callback:
                if context.layer_name:
                    context.unsupported_object_callback(
                        '{}: Cannot automatically convert advanced {} expression: {}'.format(context.layer_name,
                                                                                             expression_type,
                                                                                             expression),
                        level=Context.WARNING)
                elif context.symbol_name:
                    context.unsupported_object_callback(
                        '{}: Cannot automatically convert advanced {} expression: {}'.format(context.symbol_name,
                                                                                             expression_type,
                                                                                             expression),
                        level=Context.WARNING)
                else:
                    context.unsupported_object_callback(
                        'Cannot automatically convert advanced {} expression: {}'.format(expression_type, expression),
                        level=Context.WARNING)
            return expression

        if isinstance(engine, AnnotationVBScriptEngine):
            res = ExpressionConverter.convert_vbscript_expression(expression, context)
        elif isinstance(engine, AnnotationPythonEngine):
            res = ExpressionConverter.convert_python_expression(expression)
        elif isinstance(engine, AnnotationJScriptEngine):
            res = ExpressionConverter.convert_js_expression(expression)
        else:
            res = ExpressionConverter.convert_esri_expression(expression)

        exp = QgsExpression(res)
        if not advanced and exp.hasParserError() and context.unsupported_object_callback:
            if context.layer_name:
                context.unsupported_object_callback(
                    '{}: Could not automatically convert {} expression:\n{}\nPlease check and repair this expression'.format(
                        context.layer_name,
                        expression_type,
                        expression),
                    level=Context.WARNING)
            elif context.symbol_name:
                context.unsupported_object_callback(
                    '{}: Cannot automatically convert {} expression:\n{}\nPlease check and repair this expression'.format(
                        context.symbol_name,
                        expression_type, expression),
                    level=Context.WARNING)
            else:
                context.unsupported_object_callback(
                    'Cannot automatically convert {} expression:\n{}\nPlease check and repair this expression'.format(
                        expression_type, expression),
                    level=Context.WARNING)

        return res
Пример #54
0
class GeometryByExpression(QgisFeatureBasedAlgorithm):

    OUTPUT_GEOMETRY = 'OUTPUT_GEOMETRY'
    WITH_Z = 'WITH_Z'
    WITH_M = 'WITH_M'
    EXPRESSION = 'EXPRESSION'

    def group(self):
        return self.tr('Vector geometry')

    def groupId(self):
        return 'vectorgeometry'

    def flags(self):
        return super().flags(
        ) & ~QgsProcessingAlgorithm.FlagSupportsInPlaceEdits

    def __init__(self):
        super().__init__()
        self.geometry_types = [self.tr('Polygon'), 'Line', 'Point']

    def initParameters(self, config=None):
        self.addParameter(
            QgsProcessingParameterEnum(self.OUTPUT_GEOMETRY,
                                       self.tr('Output geometry type'),
                                       options=self.geometry_types,
                                       defaultValue=0))
        self.addParameter(
            QgsProcessingParameterBoolean(
                self.WITH_Z,
                self.tr('Output geometry has z dimension'),
                defaultValue=False))
        self.addParameter(
            QgsProcessingParameterBoolean(
                self.WITH_M,
                self.tr('Output geometry has m values'),
                defaultValue=False))

        self.addParameter(
            QgsProcessingParameterExpression(self.EXPRESSION,
                                             self.tr("Geometry expression"),
                                             defaultValue='$geometry',
                                             parentLayerParameterName='INPUT'))

    def name(self):
        return 'geometrybyexpression'

    def displayName(self):
        return self.tr('Geometry by expression')

    def outputName(self):
        return self.tr('Modified geometry')

    def prepareAlgorithm(self, parameters, context, feedback):
        self.geometry_type = self.parameterAsEnum(parameters,
                                                  self.OUTPUT_GEOMETRY,
                                                  context)
        self.wkb_type = None
        if self.geometry_type == 0:
            self.wkb_type = QgsWkbTypes.Polygon
        elif self.geometry_type == 1:
            self.wkb_type = QgsWkbTypes.LineString
        else:
            self.wkb_type = QgsWkbTypes.Point
        if self.parameterAsBool(parameters, self.WITH_Z, context):
            self.wkb_type = QgsWkbTypes.addZ(self.wkb_type)
        if self.parameterAsBool(parameters, self.WITH_M, context):
            self.wkb_type = QgsWkbTypes.addM(self.wkb_type)

        self.expression = QgsExpression(
            self.parameterAsString(parameters, self.EXPRESSION, context))
        if self.expression.hasParserError():
            feedback.reportError(self.expression.parserErrorString())
            return False

        self.expression_context = self.createExpressionContext(
            parameters, context)
        self.expression.prepare(self.expression_context)

        return True

    def outputWkbType(self, input_wkb_type):
        return self.wkb_type

    def inputLayerTypes(self):
        return [QgsProcessing.TypeVector]

    def sourceFlags(self):
        return QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks

    def processFeature(self, feature, context, feedback):
        self.expression_context.setFeature(feature)
        value = self.expression.evaluate(self.expression_context)
        if self.expression.hasEvalError():
            raise QgsProcessingException(
                self.tr('Evaluation error: {0}').format(
                    self.expression.evalErrorString()))

        if not value:
            feature.setGeometry(QgsGeometry())
        else:
            if not isinstance(value, QgsGeometry):
                raise QgsProcessingException(
                    self.tr('{} is not a geometry').format(value))
            feature.setGeometry(value)
        return [feature]
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        ueberhoehung = self.parameterAsDouble(parameters, self.INPUTZFACTOR,
                                              context)
        baseLineLayer = self.parameterAsVectorLayer(parameters,
                                                    self.INPUTBASELINE,
                                                    context)
        vectorLayer = self.parameterAsVectorLayer(parameters,
                                                  self.INPUTVECTORLAYER,
                                                  context)
        baselineIDFieldName = self.parameterAsExpression(
            parameters, self.PROFIL_BASELINE_ID, context)
        offsetFieldName = self.parameterAsString(parameters, self.OFFSETFIELD,
                                                 context)
        vectorLayerBaselineIDFieldName = self.parameterAsExpression(
            parameters, self.INPUTVECTORLAYER_BASLINE_ID, context)

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

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

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

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

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

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

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

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

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

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

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

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

            try:

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

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

                # get Profile Baseline by ID

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

                # baseline ID
                exprBaseLineID = QgsExpression(baselineIDFieldName)

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

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

                selection = baseLineLayer.getFeatures(
                    QgsFeatureRequest(exprBaseLine))

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

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

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

                subFeatureList = []

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

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

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

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

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

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

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

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

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

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

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

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

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

        return {self.OUTPUT: dest_id}
    def responseComplete(self):
        """
        Send new response
        """
        self.handler = self.serverIface.requestHandler()
        params = self.handler.parameterMap()

        # Check if needed params are passed
        # If not, do not change QGIS Server response
        service = params.get('SERVICE')
        if not service:
            return

        if service.lower() != 'wms':
            return

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

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

        # Check if needed params are set
        required = ['TEMPLATE', 'EXP_FILTER']

        # For QGIS a report is the same as an atlas. so we use the same calls
        if params['REQUEST'].lower() == 'getreport':
            required = ['TEMPLATE']
            params['REQUEST'] = 'GetPrintAtlas'
            # a report has no filters so we can ignore the EXP_FILTER
            params['EXP_FILTER'] = '""'

        if not all(elem in params for elem in required):
            body = {
                'status': 'fail',
                'message': 'Missing parameters: {} required.'.format(
                    ', '.join(required))
            }
            self.setJsonResponse('400', body)
            return

        self.composer_name = params['TEMPLATE']
        self.feature_filter = params['EXP_FILTER']

        # check expression
        expression = QgsExpression(self.feature_filter)
        if expression.hasParserError():
            body = {
                'status': 'fail',
                'message': 'An error occurred while parsing the given expression: %s' % expression.parserErrorString()
                }
            QgsMessageLog.logMessage('ATLAS - ERROR EXPRESSION: {}'.format(expression.parserErrorString()), 'atlasprint', Qgis.Critical)
            self.setJsonResponse('400', body)
            return

        # noinspection PyBroadException
        try:
            pdf = self.print(
                composer_name=self.composer_name,
                predefined_scales=self.predefined_scales,
                feature_filter=self.feature_filter
            )
        except Exception as e:
            pdf = None
            QgsMessageLog.logMessage('ATLAS - PDF CREATION ERROR: {}'.format(e), 'atlasprint', Qgis.Critical)

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

        # Send PDF
        self.handler.clear()
        self.handler.setResponseHeader('Content-type', 'application/pdf')
        self.handler.setResponseHeader('Status', '200')

        # noinspection PyBroadException
        try:
            with open(pdf, 'rb') as f:
                loads = f.readlines()
                ba = QByteArray(b''.join(loads))
                self.handler.appendBody(ba)
        except Exception as e:
            QgsMessageLog.logMessage('ATLAS - PDF READING ERROR: {}'.format(e), 'atlasprint', Qgis.Critical)
            body = {
                'status': 'fail',
                'message': 'Error occured while reading PDF file',
            }
            self.setJsonResponse('500', body)
        finally:
            os.remove(pdf)

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

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

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

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

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

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

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

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

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

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

        # Get the form feature
        form_feat = form_feature_list[0]

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

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

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

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

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

        exp_f.prepare(exp_context)

        req = QgsFeatureRequest(exp_f, exp_context)

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

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

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

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

        separator = ''
        for feat in layer.getFeatures(req):
            fid = layername + '.' + getServerFid(feat, pkAttributes)
            response.write(separator +
                           jsonExporter.exportFeature(feat, {}, fid))
            response.flush()
            separator = ',\n'
        response.write(']}')
        return
Пример #58
0
    def processLoading(self):
        """
        Load all the layers in QGIS
        and apply corresponding style
        """
        self.startTime = datetime.now()
        QApplication.setOverrideCursor(Qt.WaitCursor)

        # default style to apply for Cadastre layers
        self.themeDir = str(self.dialog.liTheme.currentText())
        if not os.path.exists(
                os.path.join(self.qc.plugin_dir, "styles/%s" % self.themeDir)):
            self.themeDir = self.defaultThemeDir

        # set Cadastre SVG path if not set
        cadastreSvgPath = os.path.join(self.qc.plugin_dir,
                                       "styles/%s/svg" % self.themeDir)
        s = QSettings()
        qgisSvgPaths = s.value("svg/searchPathsForSVG", 10, type=str)
        a = list(qgisSvgPaths)
        if cadastreSvgPath not in a:
            a.append(cadastreSvgPath)
            s.setValue("svg/searchPathsForSVG", a)
            self.qc.updateLog(
                u"* Le chemin contenant les SVG du plugin Cadastre a été ajouté dans les options de QGIS"
            )

        # Get selected options
        providerName = self.dialog.dbpluginclass.providerName()
        qgisCadastreLayers = []
        self.dialog.schema = str(self.dialog.liDbSchema.currentText())
        self.dialog.totalSteps = len(self.qgisCadastreLayerList)

        # Run the loading
        self.updateTimer()
        self.qc.updateLog(u'Chargement des tables :')

        # Get database list of tables
        if self.dialog.dbType == 'postgis':
            schemaSearch = [
                s for s in self.dialog.db.schemas()
                if s.name == self.dialog.schema
            ]
            schemaInst = schemaSearch[0]
            dbTables = self.dialog.db.tables(schemaInst)
        if self.dialog.dbType == 'spatialite':
            dbTables = self.dialog.db.tables()

        # Get commune filter by expression
        communeExpression = self.dialog.communeFilter.text().strip()
        communeFilter = None
        cExp = QgsExpression(communeExpression)
        if communeExpression != '' and not cExp.hasParserError():
            self.qc.updateLog(u'Filtrage à partir des communes : %s' %
                              communeExpression)
            cReq = QgsFeatureRequest(cExp)
            cTableList = [a for a in dbTables if a.name == 'geo_commune']
            cTable = cTableList[0]
            cUniqueCol = 'ogc_fid'
            cSchema = self.dialog.schema
            cGeomCol = 'geom'
            cLayerUri = self.dialog.db.uri()
            cLayerUri.setDataSource(cSchema, cTable.name, cGeomCol, '',
                                    cUniqueCol)
            clayer = QgsVectorLayer(cLayerUri.uri(), 'com', providerName)
            cfeatures = clayer.getFeatures(cReq)
            cids = [a['commune'] for a in cfeatures]
            if len(cids):
                communeFilter = cids
        else:
            self.qc.updateLog(
                u'Filtrage à partir des communes, expression invalide : %s' %
                cExp.parserErrorString())

        # Loop throuhg qgisQastreLayerList and load each corresponding table
        for item in self.qgisCadastreLayerList:

            if item['label'] not in self.mainLayers and self.dialog.cbMainLayersOnly.isChecked(
            ):
                continue

            if 'dbType' in item and item['dbType'] != self.dialog.dbType:
                continue

            # update progress bar
            self.qc.updateLog(u'* %s' % item['label'])
            self.dialog.step += 1
            self.qc.updateProgressBar()

            # Tables - Get db_manager table instance
            tableList = [a for a in dbTables if a.name == item['table']]
            if len(tableList) == 0 and 'isView' not in item:
                self.qc.updateLog(u'  - Aucune table trouvée pour %s' %
                                  item['label'])
                continue

            if tableList:
                table = tableList[0]
                source = table.name
                try:
                    uniqueField = table.getValidQGisUniqueFields(True)
                    uniqueCol = uniqueField.name
                except:
                    uniqueCol = 'ogc_fid'

            schema = self.dialog.schema

            # View
            if 'isView' in item:
                if self.dialog.dbType == 'spatialite':
                    schemaReplace = ''
                else:
                    schemaReplace = '"%s".' % self.dialog.schema
                source = item['table'].replace('schema.', schemaReplace)
                uniqueCol = item['key']
                schema = None

            sql = item['sql']
            geomCol = item['geom']

            if communeFilter:
                communeFilterText = "'" + "', '".join(communeFilter) + "'"
                nschema = ''
                if self.dialog.dbType == 'postgis':
                    nschema = '"%s".' % schema
                if 'subset' in item:
                    subset = item['subset']
                    sql += subset % communeFilterText
                else:
                    itemcol = item['table']
                    if item['table'] == 'geo_label':
                        itemcol = 'ogc_fid'
                    subset = itemcol + '''
                         IN (

                            SELECT b.''' + itemcol + '''
                            FROM  ''' + nschema + item['table'] + ''' b
                            JOIN  ''' + nschema + '''geo_commune c
                            ON ST_Within(b.geom, c.geom)
                            WHERE 2>1
                            AND c.geo_commune IN ( %s )

                        )
                    '''
                    if sql:
                        sql += ' AND '
                    sql += subset % communeFilterText

            # Create vector layer
            alayerUri = self.dialog.db.uri()
            alayerUri.setDataSource(schema, source, geomCol, sql, uniqueCol)

            vlayer = QgsVectorLayer(alayerUri.uri(), item['label'],
                                    providerName)

            # apply style
            qmlPath = os.path.join(
                self.qc.plugin_dir,
                "styles/%s/%s.qml" % (self.themeDir, item['name']))
            if os.path.exists(qmlPath):
                vlayer.loadNamedStyle(qmlPath)

            # append vector layer to the list
            qgisCadastreLayers.append(vlayer)

        self.updateTimer()

        # Get canvas and disable rendering
        from qgis.utils import iface
        canvas = iface.mapCanvas()
        canvas.freeze(True)

        # Add all layers to QGIS registry (but not yet to the layer tree)
        self.qc.updateLog(u'Ajout des couches dans le registre de QGIS')
        QgsProject.instance().addMapLayers(qgisCadastreLayers, False)
        self.updateTimer()

        # Create a group "Cadastre" and move all layers into it
        self.qc.updateLog(u'Ajout des couches dans le groupe Cadastre')
        root = QgsProject.instance().layerTreeRoot()
        g1 = root.findGroup(u"Cadastre")
        if g1:
            gf = root.findGroup(u"Fond")
            if not gf:
                gf = g1.addGroup("Fond")

            ge = root.findGroup(u'Étiquettes cadastre')
            if not ge:
                ge = gf.addGroup(u'Étiquettes cadastre')

            gd = root.findGroup(u"Données cadastre")
            if not gd:
                gd = gf.addGroup(u"Données cadastre")
        else:
            g1 = root.insertGroup(0, "Cadastre")
            gf = g1.addGroup("Fond")
            ge = gf.addGroup(u'Étiquettes cadastre')
            gd = gf.addGroup(u'Données cadastre')

        variables = QgsProject.instance().customVariables()
        for layer in qgisCadastreLayers:
            # ~ layer.updateExtents()
            # Get layertree item
            nodeLayer = QgsLayerTreeLayer(layer)

            # Get layer options
            qlayer = [
                a for a in self.qgisCadastreLayerList
                if a['label'] == layer.name()
            ]
            if qlayer:
                qlayer = qlayer[0]

                # Move layer to proper group
                if qlayer['group'] == 'E':
                    ge.insertChildNode(0, nodeLayer)
                elif qlayer['group'] == 'D':
                    gd.insertChildNode(0, nodeLayer)
                else:
                    g1.insertChildNode(0, nodeLayer)

                # Enable/Disable layer
                if not qlayer['active']:
                    nodeLayer.setItemVisibilityChecked(Qt.Unchecked)
            else:
                # Move layer to Cadastre group
                g1.insertChildNode(-1, nodeLayer)

            # Do not expand layer legend
            nodeLayer.setExpanded(False)

            # set varaibles
            if layer.name() in self.variableLayers:
                varlayer = self.variableLayers[layer.name()]
                variables['cadastre_' + varlayer['var_key'] +
                          '_layer_id'] = layer.id()
                variables['cadastre_' + varlayer['var_key'] +
                          '_unique_field'] = varlayer['unique_field']

        QgsProject.instance().setCustomVariables(variables)

        self.updateTimer()

        # Zoom to full extent
        self.qc.updateLog(u'Zoom sur les couches')
        canvas.zoomToFullExtent()
        canvas.freeze(False)
        canvas.refresh()
        self.updateTimer()

        # progress bar
        self.dialog.step += 1
        self.qc.updateProgressBar()

        # Emit signal
        self.qc.updateLog(u'Mise à jour des outils cadastre')
        self.cadastreLoadingFinished.emit()
        self.updateTimer()

        # Final message
        QApplication.restoreOverrideCursor()
        QMessageBox.information(
            self.dialog, u"Cadastre",
            u"Les données ont bien été chargées dans QGIS")
        self.dialog.pbProcess.setValue(0)

        QApplication.restoreOverrideCursor()
Пример #59
0
    def read_config(self, key=""):
        # the following code reads the configuration file which setups the plugin to search in the correct database,
        # table and method

        settings = QgsSettings()
        settings.beginGroup("/Discovery")

        connection = settings.value(key + "connection", "", type=str)
        self.data_type = settings.value(key + "data_type", "", type=str)
        self.file = settings.value(key + "file", "", type=str)
        self.postgisschema = settings.value(key + "schema", "", type=str)
        self.postgistable = settings.value(key + "table", "", type=str)
        self.postgissearchcolumn = settings.value(key + "search_column", "", type=str)
        self.escapespecchars = settings.value(key + "escape_spec_chars", False, type=bool)
        self.echosearchcolumn = settings.value(key + "echo_search_column", True, type=bool)
        self.postgisdisplaycolumn = settings.value(key + "display_columns", "", type=str)
        self.postgisgeomcolumn = settings.value(key + "geom_column", "", type=str)
        if settings.value("marker_time_enabled", True, type=bool):
            self.display_time = settings.value("marker_time", 5000, type=int)
        else:
            self.display_time = -1
        if settings.value("bar_info_time_enabled", True, type=bool):
            self.bar_info_time = settings.value("bar_info_time", 30, type=int)
        else:
             self.bar_info_time = 0
        self.limit_results = settings.value("limit_results", 1000, type=int)
        self.info_to_clipboard = settings.value("info_to_clipboard", True, type=bool)

        scale_expr = settings.value(key + "scale_expr", "", type=str)
        bbox_expr = settings.value(key + "bbox_expr", "", type=str)

        if self.is_displayed:
            self.hide_marker()
            self.hide_rubber_band()
            self.is_displayed = False

        self.make_enabled(False)   # assume the config is invalid first

        self.db_conn = None
        if self.data_type == "postgres":
            self.conn_info = dbutils.get_postgres_conn_info(connection)
            self.layer = None

            if len(connection) == 0 or len(self.postgisschema) == 0 or len(self.postgistable) == 0 or \
                    len(self.postgissearchcolumn) == 0 or len(self.postgisgeomcolumn) == 0:
                return

            if len(self.conn_info) == 0:
                iface.messageBar().pushMessage("Discovery", "The database connection '%s' does not exist!" % connection,
                                               level=Qgis.Critical)
                return
        if self.data_type == "mssql":
            self.conn_info = mssql_utils.get_mssql_conn_info(connection)
            self.layer = None

            if len(connection) == 0 or len(self.postgisschema) == 0 or len(self.postgistable) == 0 or \
                    len(self.postgissearchcolumn) == 0 or len(self.postgisgeomcolumn) == 0:
                return

            if len(self.conn_info) == 0:
                iface.messageBar().pushMessage("Discovery", "The database connection '%s' does not exist!" % connection,
                                               level=Qgis.Critical)
                return
        elif self.data_type == "gpkg":
            self.layer = QgsVectorLayer(self.file + '|layername=' + self.postgistable, self.postgistable, 'ogr')
            self.conn_info = None
        self.extra_expr_columns = []
        self.scale_expr = None
        self.bbox_expr = None

        self.make_enabled(True)

        # optional scale expression when zooming in to results
        if len(scale_expr) != 0:
            expr = QgsExpression(scale_expr)
            if expr.hasParserError():
                iface.messageBar().pushMessage("Discovery", "Invalid scale expression: " + expr.parserErrorString(),
                                               level=Qgis.Warning)
            else:
                self.scale_expr = scale_expr
                self.extra_expr_columns += expr.referencedColumns()

        # optional bbox expression when zooming in to results
        if len(bbox_expr) != 0:
            expr = QgsExpression(bbox_expr)
            if expr.hasParserError():
                iface.messageBar().pushMessage("Discovery", "Invalid bbox expression: " + expr.parserErrorString(),
                                               level=Qgis.Warning)
            else:
                self.bbox_expr = bbox_expr
                self.extra_expr_columns += expr.referencedColumns()
Пример #60
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