def testZeroArgFunctionsTakeNoArgs(self):
     QgsExpression.registerFunction(self.special)
     special = self.special
     self.assertEqual(special.name(), 'special')
     exp = QgsExpression('special()')
     result = exp.evaluate()
     self.assertEqual('test', result)
 def testHandlesNull(self):
     context = QgsExpressionContext()
     QgsExpression.registerFunction(self.null_mean)
     exp = QgsExpression('null_mean(1, 2, NULL, 3)')
     result = exp.evaluate(context)
     self.assertFalse(exp.hasEvalError())
     self.assertEqual(result, 2)
示例#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, 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 _time_query_string(self, epoch, col, symbol="="):
     if self.timeLayer.getDateType() == time_util.DateTypes.IntegerTimestamps:
         return "{} {} {}".format(QgsExpression.quotedColumnRef(col), symbol, epoch)
     else:
         timeStr = time_util.epoch_to_str(epoch, self.timeLayer.getTimeFormat())
         return "{} {} {}".format(QgsExpression.quotedColumnRef(col), symbol,
                                  QgsExpression.quotedString(timeStr))
示例#5
0
def exp2func(expstr, name=None, mapLib=None):
    """
    Convert a QgsExpression into a JS function.
    """
    global whenfunctions
    whenfunctions = []
    exp = QgsExpression(expstr)
    js = walkExpression(exp.rootNode(), mapLib=mapLib)
    if name is None:
        import random
        import string
        name = ''.join(random.choice(string.ascii_lowercase) for _ in range(4))
    name += "_eval_expression"
    temp = """
function %s(context) {
    // %s

    var feature = context.feature;
    %s
    if (feature.properties) {
        return %s;
    } else {
        return %s;
    }
}""" % (name,
        exp.dump(),
        "\n".join(whenfunctions),
        js,
        js.replace("feature.properties['", "feature['"))
    return temp, name, exp.dump()
    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 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
示例#8
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
    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)
 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
示例#11
0
文件: outputs.py 项目: spono/QGIS
    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()
示例#12
0
 def testZeroArgFunctionsTakeNoArgs(self):
     QgsExpression.registerFunction(self.special)
     special = self.special
     self.assertEqual(special.name(), "special")
     exp = QgsExpression("special()")
     result = exp.evaluate()
     self.assertEqual("test", result)
示例#13
0
def layer_value(feature, layer, defaultconfig):
    layername = defaultconfig['layer']
    expression = defaultconfig['expression']
    field = defaultconfig['field']

    searchlayer = QgsMapLayerRegistry.instance().mapLayersByName(layername)[0]
    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)
        else:
            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())

    for f in features:
        if exp.evaluate(f):
            return f[field]

    raise DefaultError('No features found')
    def add_flooded_field(self, shapefile_path):
        """Create the layer from the local shp adding the flooded field.

        .. versionadded:: 3.3

        Use this method to add a calculated field to a shapefile. The shapefile
        should have a field called 'count' containing the number of flood
        reports for the field. The field values will be set to 0 if the count
        field is < 1, otherwise it will be set to 1.

        :param shapefile_path: Path to the shapefile that will have the flooded
            field added.
        :type shapefile_path: basestring

        :return: A vector layer with the flooded field added.
        :rtype: QgsVectorLayer
        """
        layer = QgsVectorLayer(
            shapefile_path, self.tr('Jakarta Floods'), 'ogr')
        # Add a calculated field indicating if a poly is flooded or not
        # from PyQt4.QtCore import QVariant
        layer.startEditing()
        field = QgsField('flooded', QVariant.Int)
        layer.dataProvider().addAttributes([field])
        layer.commitChanges()
        layer.startEditing()
        idx = layer.fieldNameIndex('flooded')
        expression = QgsExpression('state > 0')
        expression.prepare(layer.pendingFields())
        for feature in layer.getFeatures():
            feature[idx] = expression.evaluate(feature)
            layer.updateFeature(feature)
        layer.commitChanges()
        return layer
示例#15
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
示例#16
0
    def _expressionValues(self, text):
        strings = self.dialog.getAvailableValuesOfType(
            [QgsProcessingParameterString, QgsProcessingParameterNumber], [])
        model_params = [(self.dialog.resolveValueDescription(s), s) for s in strings]

        variables = QgsExpression.referencedVariables(text)

        # replace description by parameter's name (diverging after model save)
        descriptions = QgsExpression.referencedVariables(text)

        for k, v in model_params:
            if k in descriptions:
                text = text.replace('[% @{} %]'.format(k), '[% @{} %]'.format(v.parameterName()))

        src = QgsProcessingModelChildParameterSource.fromExpressionText(text)

        # add parameters currently used by the expression
        expression_values = []
        expression_values.append(src)

        for k, v in model_params:
            if k in variables:
                expression_values.append(v)

        return expression_values
示例#17
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)       
         
         
示例#18
0
 def expression_iterator(self, layer, expression, geometryStorage):
     featReq = QgsFeatureRequest()
     expression = QgsExpression(expression)
     context = QgsExpressionContext()
     self.stopLoop = False
     i = 0
     for f in layer.getFeatures(featReq):
         QCoreApplication.processEvents()
         if self.stopLoop:
             break
         self.recordingSearchProgress.emit(i)
         i += 1
         context.setFeature(f)
         evaluated = unicode(expression.evaluate(context))
         if expression.hasEvalError():
             continue
         if f.geometry() is None or f.geometry().centroid() is None:
             continue
         centroid = f.geometry().centroid().asPoint()
         if geometryStorage == 'wkb':
             geom = binascii.b2a_hex(f.geometry().asWkb())
         elif geometryStorage == 'wkt':
             geom = f.geometry().exportToWkt()
         elif geometryStorage == 'extent':
             geom = f.geometry().boundingBox().asWktPolygon()
         yield ( evaluated, centroid.x(), centroid.y(), geom )
示例#19
0
    def __ok(self, withVertex, withPoint):
        """
        To apply the interpolation
        :param withVertex: if we want a new interpolated vertex
        :param withPoint: if we want a new interpolated point
        """
        line_v2, curved = GeometryV2.asLineV2(self.__selectedFeature.geometry(), self.__iface)
        vertex_v2 = QgsPointV2()
        vertex_id = QgsVertexId()
        line_v2.closestSegment(QgsPointV2(self.__mapPoint), vertex_v2, vertex_id, 0)

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

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

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

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

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

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

        self.__iface.mapCanvas().refresh()

        self.__done()
        self.__findVertex = True
示例#20
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())
示例#21
0
 def testCanUnregisterFunction(self):
     QgsExpression.registerFunction(self.testfun)
     index = QgsExpression.functionIndex("testfun")
     self.assertTrue(not index == -1)
     error = QgsExpression.unregisterFunction("testfun")
     self.assertTrue(error)
     index = QgsExpression.functionIndex("testfun")
     self.assertTrue(index == -1)
示例#22
0
 def testCanUnregisterFunction(self):
     QgsExpression.registerFunction(self.testfun)
     index = QgsExpression.functionIndex('testfun')
     self.assertNotEqual(index, -1)
     error = QgsExpression.unregisterFunction('testfun')
     self.assertTrue(error)
     index = QgsExpression.functionIndex('testfun')
     self.assertEqual(index, -1)
示例#23
0
 def showExpressionsBuilder(self):
     context = self.alg.createExpressionContext({}, createContext())
     dlg = QgsExpressionBuilderDialog(None, self.leText.text(), self, 'generic',
                                      context)
     dlg.setWindowTitle(self.tr('Expression based output'))
     if dlg.exec_() == QDialog.Accepted:
         expression = QgsExpression(dlg.expressionText())
         self.leText.setText(expression.evaluate(context))
示例#24
0
文件: BatchPanel.py 项目: qgis/QGIS
    def populateByExpression(self, adding=False):
        """
        Populates the panel using an expression
        """
        context = dataobjects.createContext()
        expression_context = context.expressionContext()

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

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

        expression_context.appendScope(alg_scope)

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

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

        if not dlg.exec_():
            return

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

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

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

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

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

                expression_context.appendScope(alg_scope)

                # rebuild a new expression every time -- we don't want the expression compiler to replace
                # variables with precompiled values
                exp = QgsExpression(dlg.expressionText())
                value = exp.evaluate(expression_context)
                self.setRowValue(row, value, context)
    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()                             
 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)  
示例#27
0
 def testAutoArgsAreExpanded(self):
     function = self.expandargs
     args = function.params()
     self.assertEqual(args, 3)
     values = [1, 2, 3]
     exp = QgsExpression("")
     result = function.func(values, None, exp, None)
     # Make sure there is no eval error
     self.assertEqual(exp.evalErrorString(), "")
     self.assertEqual(result, (1, 2, 3))
示例#28
0
    def testHelp(self):
        QgsExpression.registerFunction(self.help_with_variable)
        html = ('<h3>help_with_variable function</h3><br>'
                'The help comes from a variable.')
        self.assertEqual(self.help_with_variable.helpText(), html)

        QgsExpression.registerFunction(self.help_with_docstring)
        html = ('<h3>help_with_docstring function</h3><br>'
                'The help comes from the python docstring.')
        self.assertEqual(self.help_with_docstring.helpText(), html)
示例#29
0
 def __call__(self, features):
     func = self.filterfunc
     if not hasattr(self.filterfunc, '__call__'):
         exp = QgsExpression(self.filterfunc)
         fields = self.layer.pendingFields()
         exp.prepare(fields)
         func = exp.evaluate
     # Return a generator of features that match the given where check.
     for f in features:
         if func(f):
             yield f
示例#30
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) 
示例#31
0
 def testCanRegisterGeometryFunction(self):
     success = QgsExpression.registerFunction(self.geomtest)
     self.assertTrue(success)
示例#32
0
def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exceptions=False):
    """Executes an algorithm modifying features in-place in the input layer.

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

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

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

    active_layer = parameters['INPUT']

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

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

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

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

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

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

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

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

        active_layer.beginEditCommand(alg.displayName())

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

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

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

            results, ok = {}, True

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

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

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

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

                new_features = []

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

                active_layer.deleteFeatures(active_layer.selectedFeatureIds())

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

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

        active_layer.endEditCommand()

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

        return ok, results

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

    return False, {}
示例#33
0
 def testReferencedColumnsNoSet(self):
     QgsExpression.registerFunction(self.no_referenced_columns_set)
     exp = QgsExpression('no_referenced_columns_set()')
     self.assertEqual(exp.referencedColumns(),
                      {QgsFeatureRequest.ALL_ATTRIBUTES})
示例#34
0
def _remove_selected_from_relation(agg_id: int, src_primary_key: str,
                                   src_layer_name: str, rel_primary_key: str,
                                   rel_layer_name: str):

    # get project instance
    project = QgsProject.instance()

    # get layers needed
    src_layer = project.mapLayersByName(src_layer_name)

    # Control if layers exists
    if not len(src_layer):
        iface.messageBar().pushCritical(
            'Véloroutes',
            'La couche {} n\'a pas été trouvée'.format(src_layer_name))
        return
    src_layer = src_layer[0]

    rel_layer = project.mapLayersByName(rel_layer_name)
    if not len(rel_layer):
        iface.messageBar().pushCritical(
            'Véloroutes',
            'La table {} n\'a pas été trouvée'.format(rel_layer_name))
        return
    rel_layer = rel_layer[0]

    # count number of features selected from src_layer
    count = src_layer.selectedFeatureCount()
    if count < 1:
        iface.messageBar().pushCritical(
            'Véloroutes',
            'Vous devez sélectionner au moins un objet de la couche {}'.format(
                src_layer_name))
        return

    # get list rel_layer
    couple_rel = []
    for feat in rel_layer.getFeatures(
            QgsExpression.createFieldEqualityExpression(
                src_primary_key, agg_id)):
        couple_rel.append((feat[src_primary_key], feat[rel_primary_key]))

    # create list of couples between src_primary_key and rel_primary_key
    features = src_layer.getSelectedFeatures()
    couple_id = []
    for feat in features:
        couple_id.append((agg_id, feat[rel_primary_key]))

    # test between two lists
    match_list = []

    for item in couple_rel:
        if item in couple_id:
            match_list.append(item)

    # test if match_list is empty
    if len(match_list) < 1:
        iface.messageBar().pushInfo(
            'Véloroutes',
            'Pas d\'objet de la couche {} à supprimer'.format(rel_layer_name))
        return
    rel_layer.startEditing()
    for feat in rel_layer.getFeatures(
            QgsExpression.createFieldEqualityExpression(
                src_primary_key, agg_id)):
        if (feat[src_primary_key], feat[rel_primary_key]) in match_list:
            rel_layer.deleteFeature(feat.id())
    rel_layer.commitChanges()
    msg = "{} objet(s) ont été supprimées de la couche {}".format(
        len(match_list), rel_layer_name)
    iface.messageBar().pushInfo('Véloroutes', msg)
示例#35
0
    QSpinBox,
    QStyledItemDelegate,
)

from qgis.core import QgsExpression

from processing.algs.qgis.ui.FieldsMappingPanel import (
    ExpressionDelegate,
    FieldsMappingModel,
    FieldsMappingPanel,
    FieldsMappingWidgetWrapper,
    FieldTypeDelegate,
)

AGGREGATES = ['first_value']
for function in QgsExpression.Functions():
    if function.name()[0] == '_':
        continue
    if function.isDeprecated():
        continue
    # if ( func->isContextual() ):
    if "Aggregates" in function.groups():
        if function.name() in ('aggregate', 'relation_aggregate'):
            continue
        AGGREGATES.append(function.name())
AGGREGATES = sorted(AGGREGATES)


class AggregatesModel(FieldsMappingModel):
    def configure(self):
        self.columns = [{
示例#36
0
    def prepareAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, 'INPUT', context)
        if source is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUT))

        mapping = self.parameterAsFieldsMapping(parameters,
                                                self.FIELDS_MAPPING, context)

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

        da = QgsDistanceArea()
        da.setSourceCrs(source.sourceCrs(), context.transformContext())
        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)))
            if field_def['expression']:
                expression = QgsExpression(field_def['expression'])
                expression.setGeomCalculator(da)
                expression.setDistanceUnits(context.project().distanceUnits())
                expression.setAreaUnits(context.project().areaUnits())
                if expression.hasParserError():
                    feedback.reportError(
                        self.tr(u'Parser error in expression "{}": {}').format(
                            expression.expression(),
                            expression.parserErrorString()))
                    return False
                self.expressions.append(expression)
            else:
                self.expressions.append(None)
        return True
示例#37
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())
示例#38
0
 def testCanReregisterAfterUnregister(self):
     QgsExpression.registerFunction(self.testfun)
     QgsExpression.unregisterFunction("testfun")
     success = QgsExpression.registerFunction(self.testfun)
     self.assertTrue(success)
示例#39
0
 def testCanEvaluateFunction(self):
     QgsExpression.registerFunction(self.testfun)
     exp = QgsExpression('testfun(1)')
     result = exp.evaluate()
     self.assertEqual('Testing_1', result)
示例#40
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        if source is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUT))

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

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

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

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

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

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

        expression.prepare(exp_context)

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

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

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

        return {self.OUTPUT: dest_id}
示例#41
0
    def processAlgorithm(self, parameters, context, feedback):
        # Get variables from dialog
        source = self.parameterAsSource(parameters, self.INPUT, context)
        if source is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUT))

        field_name = self.parameterAsString(parameters, self.FIELD, context)
        kneighbors = self.parameterAsInt(parameters, self.KNEIGHBORS, context)
        use_field = bool(field_name)

        field_index = -1

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

        current = 0

        # Get properties of the field the grouping is based on
        if use_field:
            field_index = source.fields().lookupField(field_name)
            if field_index >= 0:
                fields.append(
                    source.fields()[field_index]
                )  # Add a field with the name of the grouping field

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

                success = False
                fid = 0

                # Get unique values of grouping field
                unique_values = source.uniqueValues(field_index)
                total = 100.0 / float(
                    source.featureCount() * len(unique_values))

                for unique in unique_values:
                    points = []
                    filter = QgsExpression.createFieldEqualityExpression(
                        field_name, unique)
                    request = QgsFeatureRequest().setFilterExpression(filter)
                    request.setSubsetOfAttributes([])
                    # Get features with the grouping attribute equal to the current grouping value
                    features = source.getFeatures(request)
                    for in_feature in features:
                        if feedback.isCanceled():
                            break
                        # Add points or vertices of more complex geometry
                        points.extend(extract_points(in_feature.geometry()))
                        current += 1
                        feedback.setProgress(int(current * total))
                    # A minimum of 3 points is necessary to proceed
                    if len(points) >= 3:
                        out_feature = QgsFeature()
                        the_hull = concave_hull(points, kneighbors)
                        if the_hull:
                            vertex = [
                                QgsPointXY(point[0], point[1])
                                for point in the_hull
                            ]
                            poly = QgsGeometry().fromPolygonXY([vertex])

                            out_feature.setGeometry(poly)
                            # Give the polygon the same attribute as the point grouping attribute
                            out_feature.setAttributes([fid, unique])
                            sink.addFeature(out_feature,
                                            QgsFeatureSink.FastInsert)
                            success = True  # at least one polygon created
                    fid += 1
                if not success:
                    raise QgsProcessingException(
                        'No hulls could be created. Most likely there were not at least three unique points in any of the groups.'
                    )
            else:
                # Field parameter provided but can't read from it
                raise QgsProcessingException('Unable to find grouping field')

        else:
            # Not grouped by field
            # Initialize writer
            (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                                   context, fields,
                                                   QgsWkbTypes.Polygon,
                                                   source.sourceCrs())
            if sink is None:
                raise QgsProcessingException(
                    self.invalidSinkError(parameters, self.OUTPUT))

            points = []
            request = QgsFeatureRequest()
            request.setSubsetOfAttributes([])
            features = source.getFeatures(request)  # Get all features
            total = 100.0 / source.featureCount() if source.featureCount(
            ) else 0
            for in_feature in features:
                if feedback.isCanceled():
                    break
                # Add points or vertices of more complex geometry
                points.extend(extract_points(in_feature.geometry()))
                current += 1
                feedback.setProgress(int(current * total))

            # A minimum of 3 points is necessary to proceed
            if len(points) >= 3:
                out_feature = QgsFeature()
                the_hull = concave_hull(points, kneighbors)
                if the_hull:
                    vertex = [
                        QgsPointXY(point[0], point[1]) for point in the_hull
                    ]
                    poly = QgsGeometry().fromPolygonXY([vertex])

                    out_feature.setGeometry(poly)
                    out_feature.setAttributes([0])
                    sink.addFeature(out_feature, QgsFeatureSink.FastInsert)
                else:
                    # the_hull returns None only when there are less than three points after cleaning
                    raise QgsProcessingException(
                        'At least three unique points are required to create a concave hull.'
                    )
            else:
                raise QgsProcessingException(
                    'At least three points are required to create a concave hull.'
                )

        return {self.OUTPUT: dest_id}
示例#42
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_LAYER))
        fieldName = self.getParameterValue(self.FIELD_NAME)
        fieldType = self.TYPES[self.getParameterValue(self.FIELD_TYPE)]
        width = self.getParameterValue(self.FIELD_LENGTH)
        precision = self.getParameterValue(self.FIELD_PRECISION)
        newField = self.getParameterValue(self.NEW_FIELD)
        formula = self.getParameterValue(self.FORMULA)

        output = self.getOutputFromName(self.OUTPUT_LAYER)

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

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

        exp = QgsExpression(formula)

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

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

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

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

        error = ''
        calculationSuccess = True

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

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

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

        if not calculationSuccess:
            raise GeoAlgorithmExecutionException(
                self.tr('An error occurred while evaluating the calculation '
                        'string:\n%s' % error))
示例#43
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 __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 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]
joinObject = QgsVectorJoinInfo()
joinObject.joinLayerId = csvfile.id()
joinObject.joinFieldName = csvField
joinObject.targetFieldName = shpField
joinObject.memoryCache = True
shp.addJoin(joinObject)

shp.startEditing()

#step 1
myField = QgsField( 'Hill%', QVariant.Double)
shp.addAttribute( myField )
idx = shp.fieldNameIndex( 'Hill%' )

#step 2
e = QgsExpression( 'if("csv_pres_clinton" + "csv_pres_trump">0,("csv_pres_clinton"-"csv_pres_trump")/("csv_pres_clinton"+"csv_pres_trump"),0)' )
e.prepare( shp.pendingFields() )

for f in shp.getFeatures():
    f[idx] = e.evaluate( f )
    shp.updateFeature( f )

shp.commitChanges()
shp.startEditing()

#step 1
myField = QgsField( 'X', QVariant.Double)
myField2 = QgsField( 'Y', QVariant.Double)
shp.addAttribute( myField )
shp.addAttribute( myField2 )
idx = shp.fieldNameIndex( 'X' )
示例#45
0
 def testCantOverrideBuiltinsWithRegister(self):
     success = QgsExpression.registerFunction(self.sqrt)
     self.assertFalse(success)
示例#46
0
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        sourceL = self.parameterAsSource(parameters, self.INPUT_L, context)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        return {self.OUTPUT: html}
示例#47
0
    def processAlgorithm(self, context, feedback):
        layer = QgsProcessingUtils.mapLayerFromString(
            self.getParameterValue(self.INPUT_LAYER), context)
        fieldName = self.getParameterValue(self.FIELD_NAME)
        fieldType = self.TYPES[self.getParameterValue(self.FIELD_TYPE)]
        width = self.getParameterValue(self.FIELD_LENGTH)
        precision = self.getParameterValue(self.FIELD_PRECISION)
        newField = self.getParameterValue(self.NEW_FIELD)
        formula = self.getParameterValue(self.FORMULA)

        output = self.getOutputFromName(self.OUTPUT_LAYER)

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

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

        exp = QgsExpression(formula)

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

        exp_context = QgsExpressionContext(
            QgsExpressionContextUtils.globalProjectLayerScopes(layer))

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

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

        error = ''
        calculationSuccess = True

        features = QgsProcessingUtils.getFeatures(layer, context)
        total = 100.0 / QgsProcessingUtils.featureCount(layer, context)

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

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

        if not calculationSuccess:
            raise GeoAlgorithmExecutionException(
                self.tr('An error occurred while evaluating the calculation '
                        'string:\n{0}').format(error))
示例#48
0
 def testQgsExpressionRepr(self):
     e = QgsExpression('my expression')
     self.assertEqual(e.__repr__(), "<QgsExpression: 'my expression'>")
示例#49
0
 def testCantReregister(self):
     QgsExpression.registerFunction(self.testfun)
     success = QgsExpression.registerFunction(self.testfun)
     self.assertFalse(success)
示例#50
0
    def processAlgorithm(self, progress):
        layer = self.getParameterValue(self.INPUT_LAYER)
        mapping = self.getParameterValue(self.FIELDS_MAPPING)
        output = self.getOutputFromName(self.OUTPUT_LAYER)

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

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

        exp_context = layer.createExpressionContext()

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

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

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

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

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

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

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

            writer.addFeature(outFeat)

            progress.setPercentage(int(current * total))

        del writer

        if error_exp is not None:
            raise GeoAlgorithmExecutionException(
                self.tr(u'Evaluation error in expression "{}": {}').format(
                    unicode(error_exp.expression()),
                    unicode(error_exp.parserErrorString())))
示例#51
0
    def processAlgorithm(self, parameters, context, feedback):
        layers = self.parameterAsLayerList(parameters, self.INPUT_DATASOURCES,
                                           context)
        query = self.parameterAsString(parameters, self.INPUT_QUERY, context)
        uid_field = self.parameterAsString(parameters, self.INPUT_UID_FIELD,
                                           context)
        geometry_field = self.parameterAsString(parameters,
                                                self.INPUT_GEOMETRY_FIELD,
                                                context)
        geometry_type = self.parameterAsEnum(parameters,
                                             self.INPUT_GEOMETRY_TYPE, context)
        geometry_crs = self.parameterAsCrs(parameters, self.INPUT_GEOMETRY_CRS,
                                           context)

        df = QgsVirtualLayerDefinition()
        for layerIdx, layer in enumerate(layers):
            df.addSource('input{}'.format(layerIdx + 1), layer.id())

        if query == '':
            raise QgsProcessingException(
                self.
                tr('Empty SQL. Please enter valid SQL expression and try again.'
                   ))
        else:
            localContext = self.createExpressionContext(parameters, context)
            expandedQuery = QgsExpression.replaceExpressionText(
                query, localContext)
            df.setQuery(expandedQuery)

        if uid_field:
            df.setUid(uid_field)

        if geometry_type == 1:  # no geometry
            df.setGeometryWkbType(QgsWkbTypes.NoGeometry)
        else:
            if geometry_field:
                df.setGeometryField(geometry_field)
            if geometry_type > 1:
                df.setGeometryWkbType(geometry_type - 1)
            if geometry_crs.isValid():
                df.setGeometrySrid(geometry_crs.postgisSrid())

        vLayer = QgsVectorLayer(df.toString(), "temp_vlayer", "virtual")
        if not vLayer.isValid():
            raise QgsProcessingException(
                vLayer.dataProvider().error().message())

        (sink, dest_id) = self.parameterAsSink(
            parameters, self.OUTPUT, context, vLayer.fields(),
            vLayer.wkbType() if geometry_type != 1 else 1, vLayer.crs())
        if sink is None:
            raise QgsProcessingException(
                self.invalidSinkError(parameters, self.OUTPUT))

        features = vLayer.getFeatures()
        total = 100.0 / vLayer.featureCount() if vLayer.featureCount() else 0
        for current, inFeat in enumerate(features):
            if feedback.isCanceled():
                break

            sink.addFeature(inFeat, QgsFeatureSink.FastInsert)
            feedback.setProgress(int(current * total))
        return {self.OUTPUT: dest_id}
示例#52
0
 def testCanBeRegistered(self):
     QgsExpression.registerFunction(self.testfun)
     index = QgsExpression.functionIndex('testfun')
     self.assertNotEqual(index, -1)
示例#53
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)
示例#54
0
 def tearDown(self):
     QgsExpression.unregisterFunction('testfun')
示例#55
0
    def __ok(self, withVertex, withPoint):
        """
        To realize the interpolation
        :param withVertex: if we want a new interpolated vertex
        :param withPoint: if we want a new interpolated point
        """
        line_v2, curved = GeometryV2.asLineV2(
            self.__selectedFeature.geometry(), self.__iface)
        vertex_v2 = QgsPointV2()
        vertex_id = QgsVertexId()
        line_v2.closestSegment(QgsPointV2(self.__mapPoint), vertex_v2,
                               vertex_id, 0)

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

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

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

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

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

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

        self.__iface.mapCanvas().refresh()

        self.__done()
        self.__findVertex = True
示例#56
0
 def testCantOverrideBuiltinsWithUnregister(self):
     success = QgsExpression.unregisterFunction("sqrt")
     self.assertFalse(success)
示例#57
0
    def testLegendScopeVariables(self):
        layout = QgsLayout(QgsProject.instance())
        layout.initializeDefaults()

        legend = QgsLayoutItemLegend(layout)
        legend.setTitle("Legend")
        layout.addLayoutItem(legend)

        legend.setColumnCount(2)
        legend.setWrapString('d')
        legend.setLegendFilterOutAtlas(True)

        expc = legend.createExpressionContext()
        exp1 = QgsExpression("@legend_title")
        self.assertEqual(exp1.evaluate(expc), "Legend")
        exp2 = QgsExpression("@legend_column_count")
        self.assertEqual(exp2.evaluate(expc), 2)
        exp3 = QgsExpression("@legend_wrap_string")
        self.assertEqual(exp3.evaluate(expc), 'd')
        exp4 = QgsExpression("@legend_split_layers")
        self.assertEqual(exp4.evaluate(expc), False)
        exp5 = QgsExpression("@legend_filter_out_atlas")
        self.assertEqual(exp5.evaluate(expc), True)

        map = QgsLayoutItemMap(layout)
        map.attemptSetSceneRect(QRectF(20, 20, 80, 80))
        map.setFrameEnabled(True)
        map.setExtent(
            QgsRectangle(781662.375, 3339523.125, 793062.375, 3345223.125))
        layout.addLayoutItem(map)
        map.setScale(15000)
        legend.setLinkedMap(map)
        expc2 = legend.createExpressionContext()
        exp6 = QgsExpression("@map_scale")
        self.assertAlmostEqual(exp6.evaluate(expc2), 15000, 2)
示例#58
0
 def testReferencedColumnsSet(self):
     QgsExpression.registerFunction(self.referenced_columns_set)
     exp = QgsExpression('referenced_columns_set()')
     self.assertEqual(set(exp.referencedColumns()), set(['a', 'b']))
示例#59
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(),
                                         QgsFeatureSink.RegeneratePrimaryKey)
        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.addFeature(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}
示例#60
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_LAYER))
        fieldName = self.getParameterValue(self.FIELD_NAME)
        fieldType = self.TYPES[self.getParameterValue(self.FIELD_TYPE)]
        width = self.getParameterValue(self.FIELD_LENGTH)
        precision = self.getParameterValue(self.FIELD_PRECISION)
        newField = self.getParameterValue(self.NEW_FIELD)
        formula = self.getParameterValue(self.FORMULA)

        output = self.getOutputFromName(self.OUTPUT_LAYER)

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

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

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

        exp = QgsExpression(formula)

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

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

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

        # add layer to registry to fix https://issues.qgis.org/issues/17300
        # it is necessary only for aggregate expressions that verify that layer
        # is registered
        removeRegistryAfterEvaluation = False
        if not QgsMapLayerRegistry.instance().mapLayer(layer.id()):
            removeRegistryAfterEvaluation = True
            QgsMapLayerRegistry.instance().addMapLayer(layer,
                                                       addToLegend=False)

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

        error = ''
        calculationSuccess = True

        features = vector.features(layer)
        total = 100.0 / len(features) if len(features) > 0 else 1

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

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

        # remove from registry if added for expression requirement
        # see above comment about fix #17300
        if removeRegistryAfterEvaluation:
            QgsMapLayerRegistry.instance().removeMapLayer(layer)

        if not calculationSuccess:
            raise GeoAlgorithmExecutionException(
                self.tr('An error occurred while evaluating the calculation '
                        'string:\n%s' % error))