Пример #1
0
 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))
Пример #2
0
    def newField(self, field=None):
        if field is None:
            return {
                'input': '',
                'aggregate': '',
                'delimiter': '',
                'name': '',
                'type': QVariant.Invalid,
                'length': 0,
                'precision': 0,
            }

        default_aggregate = ''
        if field.type() in (QVariant.Int,
                            QVariant.Double,
                            QVariant.LongLong):
            default_aggregate = 'sum'
        if field.type() == QVariant.DateTime:
            default_aggregate = ''
        if field.type() == QVariant.String:
            default_aggregate = 'concatenate'

        return {
            'input': QgsExpression.quotedColumnRef(field.name()),
            'aggregate': default_aggregate,
            'delimiter': ',',
            'name': field.name(),
            'type': field.type(),
            'length': field.length(),
            'precision': field.precision(),
        }
Пример #3
0
 def _id_query_string(self, id):
     if self.timeLayer.hasIdAttribute():
         idColumn = self.timeLayer.getIdAttribute()
         return " AND {}={}".format(QgsExpression.quotedColumnRef(idColumn),
                                    self._value_for_query(id, idColumn))
     else:
         return ""
Пример #4
0
 def setModelData(self, editor, model, index):
     if not editor:
         return
     (value, isExpression, isValid) = editor.currentField()
     if isExpression is True:
         model.setData(index, value)
     else:
         model.setData(index, QgsExpression.quotedColumnRef(value))
Пример #5
0
    def processAlgorithm(self, parameters, context, feedback):
        layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)

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

        fields = layer.fields()

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

        fieldType = fields[idx].type()

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

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

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

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

        layer.selectByExpression(expression_string, behavior)

        return {self.OUTPUT: parameters[self.INPUT]}
Пример #6
0
    def newField(self, field=None):
        if field is None:
            return {'name': '',
                    'type': QVariant.Invalid,
                    'length': 0,
                    'precision': 0,
                    'expression': ''}

        return {'name': field.name(),
                'type': field.type(),
                'length': field.length(),
                'precision': field.precision(),
                'expression': QgsExpression.quotedColumnRef(field.name())}
Пример #7
0
    def newField(self, field=None):
        if field is None:
            return {
                'name': '',
                'type': QVariant.Invalid,
                'length': 0,
                'precision': 0,
                'expression': ''
            }

        return {
            'name': field.name(),
            'type': field.type(),
            'length': field.length(),
            'precision': field.precision(),
            'expression': QgsExpression.quotedColumnRef(field.name())
        }
Пример #8
0
    def processAlgorithm(self, feedback):
        layer = dataobjects.getObjectFromUri(self.getParameterValue(
            self.INPUT))
        fieldName = self.getParameterValue(self.FIELD)
        operator = self.OPERATORS[self.getParameterValue(self.OPERATOR)]
        value = self.getParameterValue(self.VALUE)

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

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

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

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

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

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

        del writer
Пример #9
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))

        fieldName = self.parameterAsString(parameters, self.FIELD, context)
        directory = self.parameterAsString(parameters, self.OUTPUT, context)

        mkdir(directory)

        fieldIndex = source.fields().lookupField(fieldName)
        uniqueValues = source.uniqueValues(fieldIndex)
        baseName = os.path.join(directory, '{0}'.format(fieldName))

        fields = source.fields()
        crs = source.sourceCrs()
        geomType = source.wkbType()

        total = 100.0 / len(uniqueValues) if uniqueValues else 1
        output_layers = []

        for current, i in enumerate(uniqueValues):
            if feedback.isCanceled():
                break
            fName = u'{0}_{1}.shp'.format(baseName, str(i).strip())
            feedback.pushInfo(self.tr('Creating layer: {}').format(fName))

            sink, dest = QgsProcessingUtils.createFeatureSink(fName, context, fields, geomType, crs)

            filter = '{} = {}'.format(QgsExpression.quotedColumnRef(fieldName), QgsExpression.quotedValue(i))
            req = QgsFeatureRequest().setFilterExpression(filter)

            count = 0
            for f in source.getFeatures(req):
                if feedback.isCanceled():
                    break
                sink.addFeature(f, QgsFeatureSink.FastInsert)
                count += 1
            feedback.pushInfo(self.tr('Added {} features to layer').format(count))
            output_layers.append(fName)
            del sink

            feedback.setProgress(int(current * total))

        return {self.OUTPUT: directory, self.OUTPUT_LAYERS: output_layers}
Пример #10
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))

        fieldName = self.parameterAsString(parameters, self.FIELD, context)
        directory = self.parameterAsString(parameters, self.OUTPUT, context)

        mkdir(directory)

        fieldIndex = source.fields().lookupField(fieldName)
        uniqueValues = source.uniqueValues(fieldIndex)
        baseName = os.path.join(directory, '{0}'.format(fieldName))

        fields = source.fields()
        crs = source.sourceCrs()
        geomType = source.wkbType()

        total = 100.0 / len(uniqueValues) if uniqueValues else 1
        output_layers = []

        for current, i in enumerate(uniqueValues):
            if feedback.isCanceled():
                break
            fName = '{0}_{1}.gpkg'.format(baseName, str(i).strip())
            feedback.pushInfo(self.tr('Creating layer: {}').format(fName))

            sink, dest = QgsProcessingUtils.createFeatureSink(fName, context, fields, geomType, crs)

            filter = '{} = {}'.format(QgsExpression.quotedColumnRef(fieldName), QgsExpression.quotedValue(i))
            req = QgsFeatureRequest().setFilterExpression(filter)

            count = 0
            for f in source.getFeatures(req):
                if feedback.isCanceled():
                    break
                sink.addFeature(f, QgsFeatureSink.FastInsert)
                count += 1
            feedback.pushInfo(self.tr('Added {} features to layer').format(count))
            output_layers.append(fName)
            del sink

            feedback.setProgress(int(current * total))

        return {self.OUTPUT: directory, self.OUTPUT_LAYERS: output_layers}
Пример #11
0
    def processAlgorithm(self, feedback):
        layer = dataobjects.getLayerFromString(self.getParameterValue(self.INPUT))
        fieldName = self.getParameterValue(self.FIELD)
        operator = self.OPERATORS[self.getParameterValue(self.OPERATOR)]
        value = self.getParameterValue(self.VALUE)

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

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

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

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

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

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

        del writer
Пример #12
0
    def processAlgorithm(self, parameters, context, feedback):
        layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)

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

        fields = layer.fields()

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

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

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

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

        layer.selectByExpression(expression_string)
        return {self.OUTPUT: parameters[self.INPUT]}
Пример #13
0
    def setModelData(self, editor, model, index):
        if not editor:
            return

        column = index.column()

        fieldType = FieldsMappingModel.columns[column]['type']
        if fieldType == QVariant.Type:
            value = editor.itemData(editor.currentIndex())
            if value is None:
                value = QVariant.Invalid
            model.setData(index, value)

        elif fieldType == QgsExpression:
            (value, isExpression, isValid) = editor.currentField()
            if isExpression is True:
                model.setData(index, value)
            else:
                model.setData(index, QgsExpression.quotedColumnRef(value))

        else:
            QStyledItemDelegate.setModelData(self, editor, model, index)
Пример #14
0
    def setModelData(self, editor, model, index):
        if not editor:
            return

        column = index.column()

        fieldType = FieldsMappingModel.columns[column]['type']
        if fieldType == QVariant.Type:
            value = editor.currentData()
            if value is None:
                value = QVariant.Invalid
            model.setData(index, value)

        elif fieldType == QgsExpression:
            (value, isExpression, isValid) = editor.currentField()
            if isExpression is True:
                model.setData(index, value)
            else:
                model.setData(index, QgsExpression.quotedColumnRef(value))

        else:
            QStyledItemDelegate.setModelData(self, editor, model, index)
Пример #15
0
    def processAlgorithm(self, feedback):
        fileName = self.getParameterValue(self.INPUT)
        layer = dataobjects.getLayerFromString(fileName)
        fieldName = self.getParameterValue(self.FIELD)
        operator = self.OPERATORS[self.getParameterValue(self.OPERATOR)]
        value = self.getParameterValue(self.VALUE)

        fields = layer.fields()

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

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

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

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

        layer.selectByExpression(expression_string)
        self.setOutputValue(self.OUTPUT, fileName)
Пример #16
0
    def processAlgorithm(self, parameters, context, feedback):
        layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)

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

        fields = layer.fields()

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

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

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

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

        layer.selectByExpression(expression_string)
        return {self.OUTPUT: parameters[self.INPUT]}
Пример #17
0
    def get_lizmap_layer_filter(self, layer: 'QgsVectorLayer') -> str:
        """ Get lizmap layer filter based on login filter """
        layer_filter = ''

        # Get Lizmap config
        cfg = self.get_lizmap_config()
        if not cfg:
            # Return empty filter
            return layer_filter

        # Get layers config
        cfg_layers = get_lizmap_layers_config(cfg)
        if not cfg_layers:
            # Return empty filter
            return layer_filter

        # Get layer name
        layer_name = layer.name()
        # Check that
        if layer_name not in cfg_layers:
            # Return empty filter
            return layer_filter

        # Get layer login filter
        cfg_layer_login_filter = get_lizmap_layer_login_filter(cfg, layer_name)
        if not cfg_layer_login_filter:
            # Return empty filter
            return layer_filter

        # Layer login fliter only for edition does not filter layer
        is_edition_only = 'edition_only' in cfg_layer_login_filter
        if is_edition_only and config_value_to_boolean(
                cfg_layer_login_filter['edition_only']):
            return layer_filter

        # Get Lizmap user groups provided by the request
        groups = self.get_lizmap_groups()
        user_login = self.get_lizmap_user_login()

        # If groups is empty, no Lizmap user groups provided by the request
        # Return empty filter
        if len(groups) == 0 and not user_login:
            return layer_filter

        # Override filter
        override_filter = self.get_lizmap_override_filter()
        if override_filter:
            return layer_filter

        attribute = cfg_layer_login_filter['filterAttribute']

        # Default filter for no user connected
        # we use expression tools also for subset string
        layer_filter = QgsExpression.createFieldEqualityExpression(
            attribute, 'all')

        # If groups is not empty but the only group like user login has no name
        # Return the filter for no user connected
        if len(groups) == 1 and groups[0] == '' and user_login == '':
            return layer_filter

        # List of quoted values for expression
        quoted_values = []
        if config_value_to_boolean(cfg_layer_login_filter['filterPrivate']):
            # If filter is private use user_login
            quoted_values.append(QgsExpression.quotedString(user_login))
        else:
            # Else use user groups
            quoted_values = [QgsExpression.quotedString(g) for g in groups]
        # Add all to quoted values
        quoted_values.append(QgsExpression.quotedString('all'))

        # Build filter
        layer_filter = '{} IN ({})'.format(
            QgsExpression.quotedColumnRef(attribute), ', '.join(quoted_values))

        # Return build filter
        return layer_filter
Пример #18
0
    def layer_to_QgsVectorLayer(
            source_layer,  # pylint: disable=too-many-locals,too-many-branches,too-many-statements
            input_file,
            context: Context,
            fallback_crs=QgsCoordinateReferenceSystem(),
            defer_layer_uri_set: bool = False):
        """
        Converts a vector layer
        """
        if source_layer.__class__.__name__ == 'CadFeatureLayer':
            layer = source_layer.layer
        else:
            layer = source_layer

        crs = CrsConverter.convert_crs(
            layer.layer_extent.crs,
            context) if layer.layer_extent else QgsCoordinateReferenceSystem()
        if not crs.isValid():
            crs = fallback_crs

        subset_string = ''
        if layer.selection_set:
            subset_string = 'fid in ({})'.format(','.join(
                [str(s) for s in layer.selection_set]))
        elif layer.definition_query:
            subset_string = ExpressionConverter.convert_esri_sql(
                layer.definition_query)

        base, _ = os.path.split(input_file)

        uri, wkb_type, provider, encoding, file_name = VectorLayerConverter.get_uri(
            source_layer=source_layer,
            obj=layer,
            base=base,
            crs=crs,
            subset=subset_string,
            context=context)

        if wkb_type is None or wkb_type == QgsWkbTypes.Unknown:
            wkb_type = VectorLayerConverter.layer_to_wkb_type(layer)
        context.layer_type_hint = wkb_type

        if Qgis.QGIS_VERSION_INT >= 31600:
            # try to get the layer name so that we can remove it from field references.
            # e.g. if layer name is polys then qgis won't support to arcgis style "polys.field" format
            parts = QgsProviderRegistry.instance().decodeUri(provider, uri)
            context.main_layer_name = parts.get('layerName')
            if not context.main_layer_name and provider == 'ogr':
                context.main_layer_name = Path(parts['path']).stem

            if context.main_layer_name:
                subset_string = subset_string.replace(
                    context.main_layer_name + '.', '')
        else:
            context.main_layer_name = None

        if provider == 'ogr' and (not file_name
                                  or not os.path.exists(file_name)
                                  ) and context.invalid_layer_resolver:
            res = context.invalid_layer_resolver(layer.name, uri, wkb_type)
            uri = res.uri
            provider = res.providerKey

        if Qgis.QGIS_VERSION_INT >= 31000:
            opts = QgsVectorLayer.LayerOptions()
            if wkb_type is not None:
                opts.fallbackWkbType = wkb_type

            if provider == 'ogr' and subset_string:
                uri += '|subset={}'.format(subset_string)

            original_uri = uri
            if defer_layer_uri_set:
                uri = 'xxxxxxxxx' + uri

            vl = QgsVectorLayer(uri, layer.name, provider, opts)
            if defer_layer_uri_set:
                vl.setCustomProperty('original_uri', original_uri)
        else:
            vl = QgsMemoryProviderUtils.createMemoryLayer(
                layer.name, QgsFields(), wkb_type, crs)

        # context.style_folder, _ = os.path.split(output_file)
        if layer.renderer:
            renderer = VectorRendererConverter.convert_renderer(
                layer.renderer, context)
            try:
                if not renderer.usingSymbolLevels():
                    renderer.setUsingSymbolLevels(
                        layer.use_advanced_symbol_levels)
            except AttributeError:
                pass

            if layer.use_page_definition_query:
                filter_expression = '"{}" {} @atlas_pagename'.format(
                    layer.page_name_field, layer.page_name_match_operator)
                root_rule = QgsRuleBasedRenderer.Rule(None)

                # special case -- convert a simple renderer
                if isinstance(renderer, QgsSingleSymbolRenderer):
                    filter_rule = QgsRuleBasedRenderer.Rule(
                        renderer.symbol().clone())
                    filter_rule.setFilterExpression(filter_expression)
                    filter_rule.setLabel(layer.name)
                    filter_rule.setDescription(layer.name)
                    root_rule.appendChild(filter_rule)
                else:
                    source_rule_renderer = QgsRuleBasedRenderer.convertFromRenderer(
                        renderer)
                    filter_rule = QgsRuleBasedRenderer.Rule(None)
                    filter_rule.setFilterExpression(filter_expression)
                    filter_rule.setLabel('Current Atlas Page')
                    filter_rule.setDescription('Current Atlas Page')
                    root_rule.appendChild(filter_rule)
                    for child in source_rule_renderer.rootRule().children():
                        filter_rule.appendChild(child.clone())

                renderer = QgsRuleBasedRenderer(root_rule)

            if renderer:
                vl.setRenderer(renderer)
                vl.triggerRepaint()
        else:
            vl.setRenderer(QgsNullSymbolRenderer())
            vl.triggerRepaint()

        metadata = vl.metadata()
        metadata.setAbstract(layer.description)
        vl.setMetadata(metadata)  #

        # layer.zoom_max = "don't show when zoomed out beyond"
        zoom_max = layer.zoom_max
        # layer.zoom_min = "don't show when zoomed in beyond"
        zoom_min = layer.zoom_min

        enabled_scale_range = bool(zoom_max or zoom_min)
        if zoom_max and zoom_min and zoom_min > zoom_max:
            # inconsistent scale range -- zoom_max should be bigger number than zoom_min
            zoom_min, zoom_max = zoom_max, zoom_min

        # qgis minimum scale = don't show when zoomed out beyond, i.e. ArcGIS zoom_max
        vl.setMinimumScale(
            zoom_max if enabled_scale_range else layer.stored_zoom_max)
        # qgis maximum scale = don't show when zoomed in beyond, i.e. ArcGIS zoom_min
        vl.setMaximumScale(
            zoom_min if enabled_scale_range else layer.stored_zoom_min)
        vl.setScaleBasedVisibility(enabled_scale_range)

        vl.setOpacity(1.0 - (layer.transparency or 0) / 100)

        if layer.display_expression_properties and layer.display_expression_properties.expression and layer.display_expression_properties.expression_parser is not None:
            vl.setDisplayExpression(
                ExpressionConverter.convert(
                    layer.display_expression_properties.expression,
                    layer.display_expression_properties.expression_parser,
                    layer.display_expression_properties.advanced, context))

        if Qgis.QGIS_VERSION_INT < 31000:
            vl.setDataSource(uri, layer.name, provider)

        if encoding:
            vl.dataProvider().setEncoding(encoding)

        if subset_string:
            vl.setSubsetString(subset_string)

        vl.setCrs(crs)

        for e in layer.extensions:
            if e.__class__.__name__ == 'ServerLayerExtension':
                if 'CopyrightText' in e.properties.properties:
                    layer_credits = e.properties.properties['CopyrightText']
                    metadata = vl.metadata()
                    rights = metadata.rights()
                    rights.append(layer_credits)
                    metadata.setRights(rights)
                    vl.setMetadata(metadata)

        LabelConverter.convert_annotation_collection(
            layer.annotation_collection, dest_layer=vl, context=context)
        vl.setLabelsEnabled(layer.labels_enabled)

        DiagramConverter.convert_diagrams(layer.renderer,
                                          dest_layer=vl,
                                          context=context)

        # setup joins
        join_layer = VectorLayerConverter.add_joined_layer(
            source_layer=layer,
            input_file=input_file,
            base_layer=vl,
            context=context)

        context.dataset_name = ''

        vl.setLegend(QgsMapLayerLegend.defaultVectorLegend(vl))

        if layer.hyperlinks:
            VectorLayerConverter.convert_hyperlinks(layer.hyperlinks, vl)

        vl.setDisplayExpression(
            QgsExpression.quotedColumnRef(layer.display_field))

        res = [vl]
        if join_layer:
            res.append(join_layer)

        context.main_layer_name = None
        return res
    def style_maps(layer,
                   style_by,
                   iface,
                   output_type='damages-rlzs',
                   perils=None,
                   add_null_class=False,
                   render_higher_on_top=False,
                   repaint=True,
                   use_sgc_style=False):
        symbol = QgsSymbol.defaultSymbol(layer.geometryType())
        # see properties at:
        # https://qgis.org/api/qgsmarkersymbollayerv2_8cpp_source.html#l01073
        symbol.setOpacity(1)
        if isinstance(symbol, QgsMarkerSymbol):
            # do it only for the layer with points
            symbol.symbolLayer(0).setStrokeStyle(Qt.PenStyle(Qt.NoPen))

        style = get_style(layer, iface.messageBar())

        # this is the default, as specified in the user settings
        ramp = QgsGradientColorRamp(style['color_from'], style['color_to'])
        style_mode = style['style_mode']

        # in most cases, we override the user-specified setting, and use
        # instead a setting that was required by scientists
        if output_type in OQ_TO_LAYER_TYPES:
            default_qgs_style = QgsStyle().defaultStyle()
            default_color_ramp_names = default_qgs_style.colorRampNames()
            if output_type in (
                    'damages-rlzs',
                    'avg_losses-rlzs',
                    'avg_losses-stats',
            ):
                # options are EqualInterval, Quantile, Jenks, StdDev, Pretty
                # jenks = natural breaks
                if Qgis.QGIS_VERSION_INT < 31000:
                    style_mode = QgsGraduatedSymbolRenderer.Jenks
                else:
                    style_mode = 'Jenks'
                ramp_type_idx = default_color_ramp_names.index('Reds')
                symbol.setColor(QColor(RAMP_EXTREME_COLORS['Reds']['top']))
                inverted = False
            elif (output_type in ('gmf_data', 'ruptures')
                  or (output_type == 'hmaps' and not use_sgc_style)):
                # options are EqualInterval, Quantile, Jenks, StdDev, Pretty
                # jenks = natural breaks
                if output_type == 'ruptures':
                    if Qgis.QGIS_VERSION_INT < 31000:
                        style_mode = QgsGraduatedSymbolRenderer.Pretty
                    else:
                        style_mode = 'PrettyBreaks'
                else:
                    if Qgis.QGIS_VERSION_INT < 31000:
                        style_mode = QgsGraduatedSymbolRenderer.EqualInterval
                    else:
                        style_mode = 'EqualInterval'
                ramp_type_idx = default_color_ramp_names.index('Spectral')
                inverted = True
                symbol.setColor(QColor(RAMP_EXTREME_COLORS['Reds']['top']))
            elif output_type == 'hmaps' and use_sgc_style:
                # FIXME: for SGC they were using size 10000 map units

                # options are EqualInterval, Quantile, Jenks, StdDev, Pretty
                # jenks = natural breaks
                if Qgis.QGIS_VERSION_INT < 31000:
                    style_mode = QgsGraduatedSymbolRenderer.Pretty
                else:
                    style_mode = 'PrettyBreaks'
                try:
                    ramp_type_idx = default_color_ramp_names.index(
                        'SGC_Green2Red_Hmap_Color_Ramp')
                except ValueError:
                    raise ValueError(
                        'Color ramp SGC_Green2Red_Hmap_Color_Ramp was '
                        'not found. Please import it from '
                        'Settings -> Style Manager, loading '
                        'svir/resources/sgc_green2red_hmap_color_ramp.xml')
                inverted = False
                registry = QgsApplication.symbolLayerRegistry()
                symbol_props = {
                    'name': 'square',
                    'color': '0,0,0',
                    'color_border': '0,0,0',
                    'offset': '0,0',
                    'size': '1.5',  # FIXME
                    'angle': '0',
                }
                square = registry.symbolLayerMetadata(
                    "SimpleMarker").createSymbolLayer(symbol_props)
                symbol = QgsSymbol.defaultSymbol(layer.geometryType()).clone()
                symbol.deleteSymbolLayer(0)
                symbol.appendSymbolLayer(square)
                symbol.symbolLayer(0).setStrokeStyle(Qt.PenStyle(Qt.NoPen))
            elif output_type in ['asset_risk', 'input']:
                # options are EqualInterval, Quantile, Jenks, StdDev, Pretty
                # jenks = natural breaks
                if Qgis.QGIS_VERSION_INT < 31000:
                    style_mode = QgsGraduatedSymbolRenderer.EqualInterval
                else:
                    style_mode = 'EqualInterval'
                # exposure_strings = ['number', 'occupants', 'value']
                # setting exposure colors by default
                colors = {
                    'single': RAMP_EXTREME_COLORS['Blues']['top'],
                    'ramp_name': 'Blues'
                }
                inverted = False
                if output_type == 'asset_risk':
                    damage_strings = perils
                    for damage_string in damage_strings:
                        if damage_string in style_by:
                            colors = {
                                'single':
                                RAMP_EXTREME_COLORS['Spectral']['top'],
                                'ramp_name': 'Spectral'
                            }
                            inverted = True
                            break
                else:  # 'input'
                    colors = {
                        'single': RAMP_EXTREME_COLORS['Greens']['top'],
                        'ramp_name': 'Greens'
                    }
                    symbol.symbolLayer(0).setShape(
                        QgsSimpleMarkerSymbolLayerBase.Square)
                single_color = colors['single']
                ramp_name = colors['ramp_name']
                ramp_type_idx = default_color_ramp_names.index(ramp_name)
                symbol.setColor(QColor(single_color))
            else:
                raise NotImplementedError(
                    'Undefined color ramp for output type %s' % output_type)
            ramp = default_qgs_style.colorRamp(
                default_color_ramp_names[ramp_type_idx])
            if inverted:
                ramp.invert()
        # get unique values
        fni = layer.fields().indexOf(style_by)
        unique_values = layer.dataProvider().uniqueValues(fni)
        num_unique_values = len(unique_values - {NULL})
        if num_unique_values > 2:
            if Qgis.QGIS_VERSION_INT < 31000:
                renderer = QgsGraduatedSymbolRenderer.createRenderer(
                    layer, style_by, min(num_unique_values, style['classes']),
                    style_mode, symbol.clone(), ramp)
            else:
                renderer = QgsGraduatedSymbolRenderer(style_by, [])
                # NOTE: the following returns an instance of one of the
                #       subclasses of QgsClassificationMethod
                classification_method = \
                    QgsApplication.classificationMethodRegistry().method(
                        style_mode)
                renderer.setClassificationMethod(classification_method)
                renderer.updateColorRamp(ramp)
                renderer.updateSymbols(symbol.clone())
                renderer.updateClasses(
                    layer, min(num_unique_values, style['classes']))
            if not use_sgc_style:
                if Qgis.QGIS_VERSION_INT < 31000:
                    label_format = renderer.labelFormat()
                    # NOTE: the following line might be useful
                    # label_format.setTrimTrailingZeroes(True)
                    label_format.setPrecision(2)
                    renderer.setLabelFormat(label_format, updateRanges=True)
                else:
                    renderer.classificationMethod().setLabelPrecision(2)
                    renderer.calculateLabelPrecision()
        elif num_unique_values == 2:
            categories = []
            for unique_value in unique_values:
                symbol = symbol.clone()
                try:
                    symbol.setColor(
                        QColor(RAMP_EXTREME_COLORS[ramp_name]
                               ['bottom' if unique_value ==
                                min(unique_values) else 'top']))
                except Exception:
                    symbol.setColor(
                        QColor(style['color_from'] if unique_value ==
                               min(unique_values) else style['color_to']))
                category = QgsRendererCategory(unique_value, symbol,
                                               str(unique_value))
                # entry for the list of category items
                categories.append(category)
            renderer = QgsCategorizedSymbolRenderer(style_by, categories)
        else:
            renderer = QgsSingleSymbolRenderer(symbol.clone())
        if add_null_class and NULL in unique_values:
            # add a class for NULL values
            rule_renderer = QgsRuleBasedRenderer(symbol.clone())
            root_rule = rule_renderer.rootRule()
            not_null_rule = root_rule.children()[0].clone()
            # strip parentheses from stringified color HSL
            not_null_rule.setFilterExpression(
                '%s IS NOT NULL' % QgsExpression.quotedColumnRef(style_by))
            not_null_rule.setLabel('%s:' % style_by)
            root_rule.appendChild(not_null_rule)
            null_rule = root_rule.children()[0].clone()
            null_rule.setSymbol(
                QgsFillSymbol.createSimple({
                    'color': '160,160,160',
                    'style': 'diagonal_x'
                }))
            null_rule.setFilterExpression(
                '%s IS NULL' % QgsExpression.quotedColumnRef(style_by))
            null_rule.setLabel(tr('No points'))
            root_rule.appendChild(null_rule)
            if isinstance(renderer, QgsGraduatedSymbolRenderer):
                # create value ranges
                rule_renderer.refineRuleRanges(not_null_rule, renderer)
                # remove default rule
            elif isinstance(renderer, QgsCategorizedSymbolRenderer):
                rule_renderer.refineRuleCategoris(not_null_rule, renderer)
            for rule in rule_renderer.rootRule().children()[1].children():
                label = rule.label()
                # by default, labels are like:
                # ('"collapse-structural-ASH_DRY_sum" >= 0.0000 AND
                # "collapse-structural-ASH_DRY_sum" <= 2.3949')
                first, second = label.split(" AND ")
                bottom = first.rsplit(" ", 1)[1]
                top = second.rsplit(" ", 1)[1]
                simplified = "%s - %s" % (bottom, top)
                rule.setLabel(simplified)
            root_rule.removeChildAt(0)
            renderer = rule_renderer
        if render_higher_on_top:
            renderer.setUsingSymbolLevels(True)
            symbol_items = [item for item in renderer.legendSymbolItems()]
            for i in range(len(symbol_items)):
                sym = symbol_items[i].symbol().clone()
                key = symbol_items[i].ruleKey()
                for lay in range(sym.symbolLayerCount()):
                    sym.symbolLayer(lay).setRenderingPass(i)
                renderer.setLegendSymbolItem(key, sym)
        layer.setRenderer(renderer)
        if not use_sgc_style:
            layer.setOpacity(0.7)
        if repaint:
            layer.triggerRepaint()
            iface.setActiveLayer(layer)
            iface.zoomToActiveLayer()
            # NOTE QGIS3: probably not needed
            # iface.layerTreeView().refreshLayerSymbology(layer.id())
            iface.mapCanvas().refresh()
Пример #20
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        if source is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUT))

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

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

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

        if order_field_name:
            order_expression = QgsExpression.quotedColumnRef(order_field_name)

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

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

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

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

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

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

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

            if not f.hasGeometry():
                continue

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

            feedback.setProgress(int(current * total))

        feedback.setProgress(0)

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

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

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

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

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

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

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

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

        return {self.OUTPUT: dest_id}