示例#1
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)
示例#2
0
    def check_for_update_events(self, widget, value):
        if not self.feature:
            return

        from qgis.core import QgsExpression, QgsExpressionContext, QgsExpressionContextScope
        # If we don't have any events for this widgets just get out now
        if not widget.id in self.events:
            return

        events = self.events[widget.id]
        events = [event for event in events if event['event'].lower() == 'update']
        if not events:
            return

        feature = self.to_feature(no_defaults=True)

        for event in events:
            action = event['action'].lower()
            targetid = event['target']
            if targetid == widget.id:
                utils.log("Can't connect events to the same widget. ID {}".format(targetid))
                continue

            widget = self.get_widget_from_id(targetid)

            if not widget:
                utils.log("Can't find widget for id {} in form".format(targetid))
                continue

            condition = event['condition']
            expression = event['value']

            context = QgsExpressionContext()
            scope = QgsExpressionContextScope()
            scope.setVariable("value", value)
            scope.setVariable("field", widget.field)
            context.setFeature(feature)
            context.appendScope(scope)

            conditionexp = QgsExpression(condition)
            exp = QgsExpression(expression)

            if action.lower() == "show":
                widget.hidden = not conditionexp.evaluate(context)
            if action.lower() == "hide":
                widget.hidden = conditionexp.evaluate(context)
            if action == 'widget expression':
                if conditionexp.evaluate(context):
                    newvalue = self.widget_default(field, feature=feature)
                    widget.setvalue(newvalue)
            if action == 'set value':
                if conditionexp.evaluate(context):
                    newvalue = exp.evaluate(context)
                    widget.setvalue(newvalue)
示例#3
0
    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 qgis.PyQt.QtCore import QVariant
        layer.startEditing()
        # Add field with integer from 0 to 4 which represents the flood
        # class. Its the same as 'state' field except that is being treated
        # as a string.
        # This is used for cartography
        flood_class_field = QgsField('floodclass', QVariant.Int)
        layer.addAttribute(flood_class_field)
        layer.commitChanges()
        layer.startEditing()
        flood_class_idx = layer.fields().lookupField('floodclass')
        flood_class_expression = QgsExpression('to_int(state)')
        context = QgsExpressionContext()
        context.setFields(layer.fields())
        flood_class_expression.prepare(context)

        # Add field with boolean flag to say if the area is flooded
        # This is used by the impact function
        flooded_field = QgsField('flooded', QVariant.Int)
        layer.dataProvider().addAttributes([flooded_field])
        layer.commitChanges()
        layer.startEditing()
        flooded_idx = layer.fields().lookupField('flooded')
        flood_flag_expression = QgsExpression('state > 0')
        flood_flag_expression.prepare(context)
        for feature in layer.getFeatures():
            context.setFeature(feature)
            feature[flood_class_idx] = flood_class_expression.evaluate(context)
            feature[flooded_idx] = flood_flag_expression.evaluate(context)
            layer.updateFeature(feature)
        layer.commitChanges()
        return layer
示例#4
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)
示例#5
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()
 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)
示例#8
0
 def testExpression(self, row):
     self._errors[row] = None
     field = self._mapping[row]
     expression = QgsExpression(field['expression'])
     if expression.hasParserError():
         self._errors[row] = expression.parserErrorString()
         return
     if self._layer is None:
         return
     dp = self._layer.dataProvider()
     for feature in dp.getFeatures():
         expression.evaluate(feature, dp.fields())
         if expression.hasEvalError():
             self._errors[row] = expression.evalErrorString()
             return
         break
示例#9
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
示例#10
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
示例#11
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 )
示例#12
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
示例#14
0
    def get_feature_value(self, model=None):
        self.layer.startEditing()
        feature = None

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

        exp = QgsExpression(self.column.expression)

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

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

            return value
        else:
            return None
示例#15
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        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())
        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())

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

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

        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}
示例#16
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_LAYER))

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

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

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

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

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

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

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

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

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

        del writer
示例#17
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
示例#18
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))
示例#19
0
 def testExpression(self, row):
     self._errors[row] = None
     field = self._mapping[row]
     expression = QgsExpression(field['expression'])
     if expression.hasParserError():
         self._errors[row] = expression.parserErrorString()
         return
     if self._layer is None:
         return
     context = QgsExpressionContextUtils.createFeatureBasedContext(QgsFeature(), self._layer.fields())
     for feature in self._layer.getFeatures():
         context.setFeature(feature)
         expression.evaluate(context)
         if expression.hasEvalError():
             self._errors[row] = expression.evalErrorString()
             return
         break
示例#20
0
def where(layer, exp):
      exp = QgsExpression(exp)
      if exp.hasParserError():
         raise Exception(exp.parserErrorString())
      exp.prepare(layer.pendingFields())
      for feature in layer.getFeatures():
         value = exp.evaluate(feature)
         if exp.hasEvalError():
            raise ValueError(exp.evalErrorString())
         if bool(value):
            yield feature
示例#21
0
文件: defaults.py 项目: nicklv/Roam
def layer_value(feature, layer, defaultconfig):
    if not canvas:
        roam.utils.warning("No canvas set for using layer_values default function")
        return None
    layers = []
    # layer name can also be a list of layers to search
    layername = defaultconfig['layer']
    if isinstance(layername, basestring):
        layers.append(layername)
    else:
        layers = layername

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

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

            rect.scale(20)

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

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

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

    raise DefaultError('No features found')
示例#22
0
 def evaluateExpression(self, text):
     context = QgsExpressionContext()
     context.appendScope(QgsExpressionContextUtils.globalScope())
     context.appendScope(QgsExpressionContextUtils.projectScope())
     exp = QgsExpression(text)
     if exp.hasParserError():
         raise Exception(exp.parserErrorString())
     result = exp.evaluate(context)
     if exp.hasEvalError():
         raise ValueError(exp.evalErrorString())
     return result
示例#23
0
def sum_fields(layer, output_field_key, input_fields):
    """Sum the value of input_fields and put it as output_field.

    :param layer: The vector layer.
    :type layer: QgsVectorLayer

    :param output_field_key: The output field definition key.
    :type output_field_key: basestring

    :param input_fields: List of input fields' name.
    :type input_fields: list
    """
    field_definition = definition(output_field_key)
    output_field_name = field_definition['field_name']
    # If the fields only has one element
    if len(input_fields) == 1:
        # Name is different, copy it
        if input_fields[0] != output_field_name:
            to_rename = {input_fields[0]: output_field_name}
            # We copy only, it will be deleted later.
            # We can't rename the field, we need to copy it as the same
            # field might be used many times in the FMT tool.
            copy_fields(layer, to_rename)
        else:
            # Name is same, do nothing
            return
    else:
        # Creating expression
        # Put field name in a double quote. See #4248
        input_fields = ['"%s"' % f for f in input_fields]
        string_expression = ' + '.join(input_fields)
        sum_expression = QgsExpression(string_expression)
        context = QgsExpressionContext()
        context.setFields(layer.fields())
        sum_expression.prepare(context)

        # Get the output field index
        output_idx = layer.fields().lookupField(output_field_name)
        # Output index is not found
        layer.startEditing()
        if output_idx == -1:
            output_field = create_field_from_definition(field_definition)
            layer.addAttribute(output_field)
            output_idx = layer.fields().lookupField(output_field_name)

        # Iterate to all features
        for feature in layer.getFeatures():
            context.setFeature(feature)
            result = sum_expression.evaluate(context)
            feature[output_idx] = result
            layer.updateFeature(feature)

        layer.commitChanges()
示例#24
0
    def processAlgorithm(self, progress):
        fileName = self.getParameterValue(self.INPUT)
        layer = dataobjects.getObjectFromUri(fileName)
        fieldName = self.getParameterValue(self.FIELD)
        operator = self.OPERATORS[self.getParameterValue(self.OPERATOR)]
        value = self.getParameterValue(self.VALUE)

        fields = layer.pendingFields()

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

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

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

        expression = QgsExpression(expr)
        expression.prepare(fields)

        features = vector.features(layer)

        selected = []
        count = len(features)
        total = 100.0 / float(count)
        for count, f in enumerate(features):
            if expression.evaluate(f, fields):
                selected.append(f.id())
            progress.setPercentage(int(count * total))

        layer.setSelectedFeatures(selected)
        self.setOutputValue(self.OUTPUT, fileName)
示例#25
0
    def testConcurrency(self):
        """
        The connection pool has a maximum of 4 connections defined (+2 spare connections)
        Make sure that if we exhaust those 4 connections and force another connection
        it is actually using the spare connections and does not freeze.
        This situation normally happens when (at least) 4 rendering threads are active
        in parallel and one requires an expression to be evaluated.
        """
        # Acquire the maximum amount of concurrent connections
        iterators = list()
        for i in range(QgsApplication.instance().maxConcurrentConnectionsPerPool()):
            iterators.append(self.vl.getFeatures())

        # Run an expression that will also do a request and should use a spare
        # connection. It just should not deadlock here.

        feat = next(iterators[0])
        context = QgsExpressionContext()
        context.setFeature(feat)
        exp = QgsExpression('get_feature(\'{layer}\', \'pk\', 5)'.format(layer=self.vl.id()))
        exp.evaluate(context)
示例#26
0
    def testExpression(self, row):
        self._errors[row] = None
        field = self._mapping[row]
        exp_context = self.contextGenerator().createExpressionContext()

        expression = QgsExpression(field['expression'])
        expression.prepare(exp_context)
        if expression.hasParserError():
            self._errors[row] = expression.parserErrorString()
            return

        # test evaluation on the first feature
        if self._layer is None:
            return
        for feature in self._layer.getFeatures():
            exp_context.setFeature(feature)
            exp_context.lastScope().setVariable("row_number", 1)
            expression.evaluate(exp_context)
            if expression.hasEvalError():
                self._errors[row] = expression.evalErrorString()
            break
示例#27
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)
示例#28
0
    def _buildfromlayer(self, widget, layerconfig):
        layername = layerconfig['layer']
        keyfield = layerconfig['key']
        valuefield = layerconfig['value']
        filterexp = layerconfig.get('filter', None)

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

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

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

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

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

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

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

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

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

        if self.allownulls:
            widget.insertItem(0, '(no selection)', None)
示例#29
0
def sum_fields(layer, output_field_key, input_fields):
    """Sum the value of input_fields and put it as output_field.

    :param layer: The vector layer.
    :type layer: QgsVectorLayer

    :param output_field_key: The output field definition key.
    :type output_field_key: basestring

    :param input_fields: List of input fields' name.
    :type input_fields: list
    """
    field_definition = definition(output_field_key)
    output_field_name = field_definition['field_name']
    # If the fields only has one element
    if len(input_fields) == 1:
        # Name is different, copy it
        if input_fields[0] != output_field_name:
            copy_fields(layer, {
                input_fields[0]: output_field_name})
        # Name is same, do nothing
        else:
            return
    else:
        # Creating expression
        # Put field name in a double quote. See #4248
        input_fields = ['"%s"' % f for f in input_fields]
        string_expression = ' + '.join(input_fields)
        sum_expression = QgsExpression(string_expression)
        context = QgsExpressionContext()
        context.setFields(layer.pendingFields())
        sum_expression.prepare(context)

        # Get the output field index
        output_idx = layer.fieldNameIndex(output_field_name)
        # Output index is not found
        if output_idx == -1:
            output_field = create_field_from_definition(field_definition)
            layer.startEditing()
            layer.addAttribute(output_field)
            layer.commitChanges()
            output_idx = layer.fieldNameIndex(output_field_name)

        layer.startEditing()
        # Iterate to all features
        for feature in layer.getFeatures():
            context.setFeature(feature)
            result = sum_expression.evaluate(context)
            feature[output_idx] = result
            layer.updateFeature(feature)

        layer.commitChanges()
示例#30
0
    def processAlgorithm(self, parameters, context, feedback):
        layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)

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

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

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

        exp_context = QgsExpressionContext(QgsExpressionContextUtils.globalProjectLayerScopes(layer))

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

        features = QgsProcessingUtils.getFeatures(layer, context)
        total = 100.0 / QgsProcessingUtils.featureCount(layer, context)
        for current, input_feature in enumerate(features):
            output_feature = input_feature

            exp_context.setFeature(input_feature)
            value = expression.evaluate(exp_context)
            if expression.hasEvalError():
                raise GeoAlgorithmExecutionException(
                    self.tr('Evaluation error: {0}').format(expression.evalErrorString()))

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

            writer.addFeature(output_feature)
            feedback.setProgress(int(current * total))

        del writer
示例#31
0
    def populateByExpression(self, adding=False):
        """
        Populates the panel using an expression
        """
        context = dataobjects.createContext()
        expression_context = context.expressionContext()

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

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

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

        expression_context.appendScope(alg_scope)

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

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

        if not dlg.exec_():
            return

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

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

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

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

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

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

                expression_context.appendScope(alg_scope)

                # rebuild a new expression every time -- we don't want the expression compiler to replace
                # variables with precompiled values
                exp = QgsExpression(dlg.expressionText())
                value = exp.evaluate(expression_context)
                self.setRowValue(row, value, context)
            self.panel.tblParameters.setUpdatesEnabled(True)
示例#32
0
    def create_mesure_layer(self):
        """ Create an temporary point layer in the Qgis canvas """
        try:
            QApplication.setOverrideCursor(
                Qt.WaitCursor)  ## Start the 'wait' cursor
            if self.list_mesures:

                vl = QgsVectorLayer("Linestring?crs=" + self.selected_epsg,
                                    self.layer_name, "memory")
                pr = vl.dataProvider()

                # add fields
                pr.addAttributes([
                    QgsField("station", QVariant.String),
                    QgsField("st_num", QVariant.Int),
                    QgsField("st_y", QVariant.Double, "double", 12, 4),
                    QgsField("st_x", QVariant.Double, "double", 12, 4),
                    QgsField("st_h", QVariant.Double, "double", 10, 4),
                    QgsField("st_hi", QVariant.Double),
                    QgsField("vise", QVariant.String),
                    QgsField("vise_y", QVariant.Double, "double", 12, 4),
                    QgsField("vise_x", QVariant.Double, "double", 12, 4),
                    QgsField("vise_h", QVariant.Double, "double", 10, 4),
                    QgsField("vise_hs", QVariant.Double),
                    QgsField("vise_category", QVariant.Int),
                    QgsField("dhz", QVariant.Double),
                    QgsField("dh", QVariant.Double)
                ])
                vl.updateFields(
                )  # tell the vector layer to fetch changes from the provider

                # add features
                for item in self.list_mesures:
                    st_y = float(item[2])
                    st_x = float(item[3])
                    vise_y = float(item[7])
                    vise_x = float(item[8])
                    fet = QgsFeature()
                    fet.setGeometry(
                        QgsGeometry.fromPolyline(
                            [QgsPoint(st_y, st_x),
                             QgsPoint(vise_y, vise_x)]))
                    fet.setAttributes(list(item))
                    pr.addFeatures([fet])

                # Calculate the "dhz" and "dh" columns
                expression1 = QgsExpression(
                    "round((sqrt((st_y - vise_y)^2 + (st_x - vise_x)^2)), 3)")
                expression2 = QgsExpression(
                    "round((vise_h + vise_hs - st_h - st_hi), 3)")
                context = QgsExpressionContext()
                context.appendScopes(
                    QgsExpressionContextUtils.globalProjectLayerScopes(vl))

                vl.startEditing()
                for f in vl.getFeatures():
                    context.setFeature(f)
                    f["dhz"] = expression1.evaluate(context)
                    f["dh"] = expression2.evaluate(context)
                    vl.updateFeature(f)
                vl.commitChanges()

                # add preconfigured qgis.qml style file
                plugin_folder = os.path.dirname(os.path.dirname(__file__))
                qml_file = Path(plugin_folder) / "qml" / self.qml_style_mesure
                if qml_file.is_file(
                ):  # Test if file exist, avoid error if he is missing
                    vl.loadNamedStyle(str(qml_file))

                # update layer's extent when new features have been added
                vl.updateExtents()

                # zoom to the layer extent
                canvas = iface.mapCanvas()
                canvas.setExtent(vl.extent())

                # Show in project
                self.rmv_old_qgs_mesure_layer()
                QgsProject.instance().addMapLayer(vl)
        except:
            print(
                "Mesures -> Failed to create a new measurements Qgis layer (def create_mesure_layer)"
            )
            QApplication.restoreOverrideCursor()  ## Stop the 'wait' cursor
        finally:
            QApplication.restoreOverrideCursor()  ## Stop the 'wait' cursor
示例#33
0
    def _buildfromlayer(self, widget, layerconfig):
        layername = layerconfig['layer']
        keyfield = layerconfig['key']
        valuefield = layerconfig['value']
        filterexp = layerconfig.get('filter', None)

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

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

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

        attributes = {keyfieldindex, valuefieldindex}
        iconfieldindex = layer.fieldNameIndex('icon')
        if iconfieldindex > -1:
            attributes.add(iconfieldindex)

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

        flags = QgsFeatureRequest.NoGeometry

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

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

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

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

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

            item = QStandardItem(unicode(keyvalue))
            item.setData(unicode(valuvalue), Qt.UserRole)
            item.setIcon(icon)
            self.listmodel.appendRow(item)
示例#34
0
    def start_progress(self):
        import datetime
        start = datetime.datetime.now()
        # Check OS and dep
        if sys.platform == 'darwin':
            gdal_os_dep = '/Library/Frameworks/GDAL.framework/Versions/Current/Programs/'
        else:
            gdal_os_dep = ''

        if self.dlg.canvasButton.isChecked():
            # Map Canvas
            extentCanvasCRS = self.iface.mapCanvas()
            srs = extentCanvasCRS.mapSettings().destinationCrs()
            crs = str(srs.authid())
            # old_crs = osr.SpatialReference()
            # old_crs.ImportFromEPSG(int(crs[5:]))
            can_crs = QgsCoordinateReferenceSystem(int(crs[5:]))
            # can_wkt = extentCanvasCRS.mapRenderer().destinationCrs().toWkt()
            # can_crs = osr.SpatialReference()
            # can_crs.ImportFromWkt(can_wkt)
            # Raster Layer
            dem_layer = self.layerComboManagerDEM.currentLayer()
            dem_prov = dem_layer.dataProvider()
            dem_path = str(dem_prov.dataSourceUri())
            dem_raster = gdal.Open(dem_path)
            projdsm = osr.SpatialReference(wkt=dem_raster.GetProjection())
            projdsm.AutoIdentifyEPSG()
            projdsmepsg = int(projdsm.GetAttrValue('AUTHORITY', 1))
            dem_crs = QgsCoordinateReferenceSystem(projdsmepsg)

            # dem_wkt = dem_raster.GetProjection()
            # dem_crs = osr.SpatialReference()
            # dem_crs.ImportFromWkt(dem_wkt)
            if can_crs != dem_crs:
                extentCanvas = self.iface.mapCanvas().extent()
                extentDEM = dem_layer.extent()

                transformExt = QgsCoordinateTransform(can_crs, dem_crs)
                # transformExt = osr.CoordinateTransformation(can_crs, dem_crs)

                canminx = extentCanvas.xMinimum()
                canmaxx = extentCanvas.xMaximum()
                canminy = extentCanvas.yMinimum()
                canmaxy = extentCanvas.yMaximum()

                canxymin = transformExt.TransformPoint(canminx, canminy)
                canxymax = transformExt.TransformPoint(canmaxx, canmaxy)

                extDiffminx = canxymin[0] - extentDEM.xMinimum(
                )  # If smaller than zero = warning
                extDiffminy = canxymin[1] - extentDEM.yMinimum(
                )  # If smaller than zero = warning
                extDiffmaxx = canxymax[0] - extentDEM.xMaximum(
                )  # If larger than zero = warning
                extDiffmaxy = canxymax[0] - extentDEM.yMaximum(
                )  # If larger than zero = warning

                if extDiffminx < 0 or extDiffminy < 0 or extDiffmaxx > 0 or extDiffmaxy > 0:
                    QMessageBox.warning(
                        None,
                        "Warning! Extent of map canvas is larger than raster extent.",
                        "Change to an extent equal to or smaller than the raster extent."
                    )
                    return

        # Extent
        self.yMax = self.dlg.lineEditNorth.text()
        self.yMin = self.dlg.lineEditSouth.text()
        self.xMin = self.dlg.lineEditWest.text()
        self.xMax = self.dlg.lineEditEast.text()

        if not self.DSMoutputfile:
            QMessageBox.critical(None, "Error", "Specify a raster output file")
            return

        if self.dlg.checkBoxPolygon.isChecked() and not self.OSMoutputfile:
            QMessageBox.critical(None, "Error",
                                 "Specify an output file for OSM data")
            return

        # Acquiring geodata and attributes
        dem_layer = self.layerComboManagerDEM.currentLayer()
        if dem_layer is None:
            QMessageBox.critical(None, "Error",
                                 "No valid raster layer is selected")
            return
        else:
            provider = dem_layer.dataProvider()
            filepath_dem = str(provider.dataSourceUri())
        demRaster = gdal.Open(filepath_dem)
        dem_layer_crs = osr.SpatialReference()
        dem_layer_crs.ImportFromWkt(demRaster.GetProjection())
        self.dem_layer_unit = dem_layer_crs.GetAttrValue("UNIT")
        posUnits = [
            'metre', 'US survey foot', 'meter', 'm', 'ft', 'feet', 'foot',
            'ftUS', 'International foot'
        ]  # Possible units
        if not self.dem_layer_unit in posUnits:
            QMessageBox.critical(
                None, "Error",
                "Raster projection is not in metre or foot. Please reproject.")
            return

        polygon_layer = self.layerComboManagerPolygon.currentLayer()
        osm_layer = self.dlg.checkBoxOSM.isChecked()
        if polygon_layer is None and osm_layer is False:
            QMessageBox.critical(None, "Error",
                                 "No valid building height layer is selected")
            return
        elif polygon_layer:
            vlayer = QgsVectorLayer(polygon_layer.source(), "buildings", "ogr")
            fileInfo = QFileInfo(polygon_layer.source())
            polygon_ln = fileInfo.baseName()

            polygon_field = self.layerComboManagerPolygonField.currentField()
            idx = vlayer.fieldNameIndex(polygon_field)
            flname = vlayer.attributeDisplayName(idx)

            if idx == -1:
                QMessageBox.critical(
                    None, "Error",
                    "An attribute with unique fields must be selected")
                return

        ### main code ###

        self.dlg.progressBar.setRange(0, 5)

        self.dlg.progressBar.setValue(1)

        if self.dlg.checkBoxOSM.isChecked():
            # TODO replace osr.CoordinateTransformation with QgsCoordinateTransform
            dem_original = gdal.Open(filepath_dem)
            dem_wkt = dem_original.GetProjection()
            ras_crs = osr.SpatialReference()
            ras_crs.ImportFromWkt(dem_wkt)
            rasEPSG = ras_crs.GetAttrValue("PROJCS|AUTHORITY", 1)
            if self.dlg.layerButton.isChecked():
                old_crs = ras_crs
            elif self.dlg.canvasButton.isChecked():
                canvasCRS = self.iface.mapCanvas()
                outputWkt = canvasCRS.mapRenderer().destinationCrs().toWkt()
                old_crs = osr.SpatialReference()
                old_crs.ImportFromWkt(outputWkt)

            wgs84_wkt = """
            GEOGCS["WGS 84",
                DATUM["WGS_1984",
                    SPHEROID["WGS 84",6378137,298.257223563,
                        AUTHORITY["EPSG","7030"]],
                    AUTHORITY["EPSG","6326"]],
                PRIMEM["Greenwich",0,
                    AUTHORITY["EPSG","8901"]],
                UNIT["degree",0.01745329251994328,
                    AUTHORITY["EPSG","9122"]],
                AUTHORITY["EPSG","4326"]]"""

            new_crs = osr.SpatialReference()
            new_crs.ImportFromWkt(wgs84_wkt)

            transform = osr.CoordinateTransformation(old_crs, new_crs)

            minx = float(self.xMin)
            miny = float(self.yMin)
            maxx = float(self.xMax)
            maxy = float(self.yMax)
            lonlatmin = transform.TransformPoint(minx, miny)
            lonlatmax = transform.TransformPoint(maxx, maxy)

            if ras_crs != old_crs:
                rasTrans = osr.CoordinateTransformation(old_crs, ras_crs)
                raslonlatmin = rasTrans.TransformPoint(float(self.xMin),
                                                       float(self.yMin))
                raslonlatmax = rasTrans.TransformPoint(float(self.xMax),
                                                       float(self.yMax))
                #else:
                #raslonlatmin = [float(self.xMin), float(self.yMin)]
                #raslonlatmax = [float(self.xMax), float(self.yMax)]

                self.xMin = raslonlatmin[0]
                self.yMin = raslonlatmin[1]
                self.xMax = raslonlatmax[0]
                self.yMax = raslonlatmax[1]

            # Make data queries to overpass-api
            urlStr = 'http://overpass-api.de/api/map?bbox=' + str(
                lonlatmin[0]) + ',' + str(lonlatmin[1]) + ',' + str(
                    lonlatmax[0]) + ',' + str(lonlatmax[1])
            osmXml = urllib.urlopen(urlStr).read()
            #print urlStr

            # Make OSM building file
            osmPath = self.plugin_dir + '/temp/OSM_building.osm'
            osmFile = open(osmPath, 'w')
            osmFile.write(osmXml)
            if os.fstat(osmFile.fileno()).st_size < 1:
                urlStr = 'http://api.openstreetmap.org/api/0.6/map?bbox=' + str(
                    lonlatmin[0]) + ',' + str(lonlatmin[1]) + ',' + str(
                        lonlatmax[0]) + ',' + str(lonlatmax[1])
                osmXml = urllib.urlopen(urlStr).read()
                osmFile.write(osmXml)
                #print 'Open Street Map'
                if os.fstat(osmFile.fileno()).st_size < 1:
                    QMessageBox.critical(None, "Error",
                                         "No OSM data available")
                    return

            osmFile.close()

            outputshp = self.plugin_dir + '/temp/'

            osmToShape = gdal_os_dep + 'ogr2ogr --config OSM_CONFIG_FILE "' + self.plugin_dir + '/osmconf.ini" -skipfailures -t_srs EPSG:' + str(
                rasEPSG
            ) + ' -overwrite -nlt POLYGON -f "ESRI Shapefile" "' + outputshp + '" "' + osmPath + '"'

            if sys.platform == 'win32':
                si = subprocess.STARTUPINFO()
                si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
                subprocess.call(osmToShape, startupinfo=si)
            else:
                os.system(osmToShape)

            driver = ogr.GetDriverByName('ESRI Shapefile')
            driver.DeleteDataSource(outputshp + 'lines.shp')
            driver.DeleteDataSource(outputshp + 'multilinestrings.shp')
            driver.DeleteDataSource(outputshp + 'other_relations.shp')
            driver.DeleteDataSource(outputshp + 'points.shp')

            osmPolygonPath = outputshp + 'multipolygons.shp'
            vlayer = QgsVectorLayer(osmPolygonPath, 'multipolygons', 'ogr')
            polygon_layer = vlayer
            fileInfo = QFileInfo(polygon_layer.source())
            polygon_ln = fileInfo.baseName()

            def renameField(srcLayer, oldFieldName, newFieldName):
                ds = gdal.OpenEx(srcLayer.source(),
                                 gdal.OF_VECTOR | gdal.OF_UPDATE)
                ds.ExecuteSQL('ALTER TABLE {} RENAME COLUMN {} TO {}'.format(
                    srcLayer.name(), oldFieldName, newFieldName))
                srcLayer.reload()

            vlayer.startEditing()
            renameField(vlayer, 'building_l', 'bld_levels')
            renameField(vlayer, 'building_h', 'bld_hght')
            renameField(vlayer, 'building_c', 'bld_colour')
            renameField(vlayer, 'building_m', 'bld_materi')
            renameField(vlayer, 'building_u', 'bld_use')
            vlayer.commitChanges()

            vlayer.startEditing()
            vlayer.dataProvider().addAttributes(
                [QgsField('bld_height', QVariant.Double, 'double', 3, 2)])
            vlayer.updateFields()
            bld_lvl = vlayer.fieldNameIndex('bld_levels')
            hght = vlayer.fieldNameIndex('height')
            bld_hght = vlayer.fieldNameIndex('bld_hght')
            bld_height = vlayer.fieldNameIndex('bld_height')

            bldLvlHght = float(self.dlg.doubleSpinBoxBldLvl.value())
            illegal_chars = string.ascii_letters + "!#$%&'*+^_`|~:" + " "
            counterNone = 0
            counter = 0
            #counterWeird = 0
            for feature in vlayer.getFeatures():
                if feature[hght]:
                    try:
                        #feature[bld_height] = float(re.sub("[^0-9]", ".", str(feature[hght])))
                        feature[bld_height] = float(
                            str(feature[hght]).translate(None, illegal_chars))
                    except:
                        counterNone += 1
                elif feature[bld_hght]:
                    try:
                        #feature[bld_height] = float(re.sub("[^0-9]", ".", str(feature[bld_hght])))
                        feature[bld_height] = float(
                            str(feature[bld_hght]).translate(
                                None, illegal_chars))
                    except:
                        counterNone += 1
                elif feature[bld_lvl]:
                    try:
                        #feature[bld_height] = float(re.sub("[^0-9]", "", str(feature[bld_lvl])))*bldLvlHght
                        feature[bld_height] = float(
                            str(feature[bld_lvl]).translate(
                                None, illegal_chars)) * bldLvlHght
                    except:
                        counterNone += 1
                else:
                    counterNone += 1
                vlayer.updateFeature(feature)
                counter += 1
            vlayer.commitChanges()
            flname = vlayer.attributeDisplayName(bld_height)
            counterDiff = counter - counterNone

        # Zonal statistics
        vlayer.startEditing()
        zoneStat = QgsZonalStatistics(vlayer, filepath_dem, "stat_", 1,
                                      QgsZonalStatistics.Mean)
        zoneStat.calculateStatistics(None)
        vlayer.dataProvider().addAttributes(
            [QgsField('height_asl', QVariant.Double)])
        vlayer.updateFields()
        e = QgsExpression('stat_mean + ' + flname)
        e.prepare(vlayer.pendingFields())
        idx = vlayer.fieldNameIndex('height_asl')

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

        vlayer.commitChanges()

        vlayer.startEditing()
        idx2 = vlayer.fieldNameIndex('stat_mean')
        vlayer.dataProvider().deleteAttributes([idx2])
        vlayer.updateFields()
        vlayer.commitChanges()

        self.dlg.progressBar.setValue(2)

        # Convert polygon layer to raster

        # Define pixel_size and NoData value of new raster
        pixel_size = self.dlg.spinBox.value()  # half picture size

        # Create the destination data source

        gdalrasterize = gdal_os_dep + 'gdal_rasterize -a ' + 'height_asl' + ' -te ' + str(self.xMin) + ' ' + str(self.yMin) + ' ' + str(self.xMax) + ' ' + str(self.yMax) +\
                        ' -tr ' + str(pixel_size) + ' ' + str(pixel_size) + ' -l "' + str(polygon_ln) + '" "' \
                         + str(polygon_layer.source()) + '" "' + self.plugin_dir + '/temp/clipdsm.tif"'

        # gdalclipdem = gdal_os_dep + 'gdalwarp -dstnodata -9999 -q -overwrite -te ' + str(self.xMin) + ' ' + str(self.yMin) + ' ' + str(self.xMax) + ' ' + str(self.yMax) +\
        #               ' -tr ' + str(pixel_size) + ' ' + str(pixel_size) + \
        #               ' -of GTiff ' + '"' + filepath_dem + '" "' + self.plugin_dir + '/temp/clipdem.tif"'

        # Rasterize
        if sys.platform == 'win32':
            si = subprocess.STARTUPINFO()
            si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
            subprocess.call(gdalrasterize, startupinfo=si)
            # subprocess.call(gdalclipdem, startupinfo=si)
            gdal.Warp(self.plugin_dir + '/temp/clipdem.tif',
                      filepath_dem,
                      xRes=pixel_size,
                      yRes=pixel_size)
        else:
            os.system(gdalrasterize)
            # os.system(gdalclipdem)
            gdal.Warp(self.plugin_dir + '/temp/clipdem.tif',
                      filepath_dem,
                      xRes=pixel_size,
                      yRes=pixel_size)

        # Remove gdalwarp with gdal.Translate
        # bigraster = gdal.Open(filepath_dem)
        # bbox = (self.xMin, self.yMax, self.xMax, self.yMin)
        # gdal.Translate(self.plugin_dir + '/data/clipdem.tif', bigraster, projWin=bbox)

        self.dlg.progressBar.setValue(3)

        # Adding DSM to DEM
        # Read DEM
        dem_raster = gdal.Open(self.plugin_dir + '/temp/clipdem.tif')
        dem_array = np.array(dem_raster.ReadAsArray().astype(np.float))
        dsm_raster = gdal.Open(self.plugin_dir + '/temp/clipdsm.tif')
        dsm_array = np.array(dsm_raster.ReadAsArray().astype(np.float))

        indx = dsm_array.shape
        for ix in range(0, int(indx[0])):
            for iy in range(0, int(indx[1])):
                if int(dsm_array[ix, iy]) == 0:
                    dsm_array[ix, iy] = dem_array[ix, iy]

        if self.dlg.checkBoxPolygon.isChecked():
            vlayer.startEditing()
            idxHght = vlayer.fieldNameIndex('height_asl')
            idxBld = vlayer.fieldNameIndex('building')
            features = vlayer.getFeatures()
            #for f in vlayer.getFeatures():
            for f in features:
                geom = f.geometry()
                posUnitsMetre = ['metre', 'meter', 'm']  # Possible metre units
                posUnitsFt = [
                    'US survey foot', 'ft', 'feet', 'foot', 'ftUS',
                    'International foot'
                ]  # Possible foot units
                if self.dem_layer_unit in posUnitsMetre:
                    sqUnit = 1
                elif self.dem_layer_unit in posUnitsFt:
                    sqUnit = 10.76
                if int(geom.area()) > 50000 * sqUnit:
                    vlayer.deleteFeature(f.id())

                #if not f[idxHght]:
                #vlayer.deleteFeature(f.id())
                #elif not f[idxBld]:
                #vlayer.deleteFeature(f.id())
            vlayer.updateFields()
            vlayer.commitChanges()
            QgsVectorFileWriter.writeAsVectorFormat(vlayer,
                                                    str(self.OSMoutputfile),
                                                    "UTF-8", None,
                                                    "ESRI Shapefile")

        else:
            vlayer.startEditing()
            idx3 = vlayer.fieldNameIndex('height_asl')
            vlayer.dataProvider().deleteAttributes([idx3])
            vlayer.updateFields()
            vlayer.commitChanges()

        self.dlg.progressBar.setValue(4)

        # Save raster
        def saveraster(
            gdal_data, filename, raster
        ):  # gdal_data = raster extent, filename = output filename, raster = numpy array (raster to be saved)
            rows = gdal_data.RasterYSize
            cols = gdal_data.RasterXSize

            outDs = gdal.GetDriverByName("GTiff").Create(
                filename, cols, rows, int(1), gdal.GDT_Float32)
            outBand = outDs.GetRasterBand(1)

            # write the data
            outBand.WriteArray(raster, 0, 0)
            # flush data to disk, set the NoData value and calculate stats
            outBand.FlushCache()
            outBand.SetNoDataValue(-9999)

            # georeference the image and set the projection
            outDs.SetGeoTransform(gdal_data.GetGeoTransform())
            outDs.SetProjection(gdal_data.GetProjection())

        saveraster(dsm_raster, self.DSMoutputfile, dsm_array)

        # Load result into canvas
        rlayer = self.iface.addRasterLayer(self.DSMoutputfile)

        # Trigger a repaint
        if hasattr(rlayer, "setCacheImage"):
            rlayer.setCacheImage(None)
        rlayer.triggerRepaint()

        self.dlg.progressBar.setValue(5)

        #runTime = datetime.datetime.now() - start

        if self.dlg.checkBoxOSM.isChecked():
            QMessageBox.information(
                self.dlg, 'DSM Generator', 'Operation successful! ' +
                str(counterDiff) + ' building polygons out of ' +
                str(counter) + ' contained height values.')
            #self.iface.messageBar().pushMessage("DSM Generator. Operation successful! " + str(counterDiff) + " buildings out of " + str(counter) + " contained height values.", level=QgsMessageBar.INFO, duration=5)
        else:
            #self.iface.messageBar().pushMessage("DSM Generator. Operation successful!", level=QgsMessageBar.INFO, duration=5)
            QMessageBox.information(self.dlg, 'DSM Generator',
                                    'Operation successful!')

        self.resetPlugin()
示例#35
0
    def processAlgorithm(self, parameters, context: QgsProcessingContext,
                         feedback: QgsProcessingFeedback):
        """Here is where the processing itself takes place."""

        feedback.setProgress(0)

        # init params
        reach_layer = self.parameterAsVectorLayer(parameters, self.REACH_LAYER,
                                                  context)
        wastewater_node_layer = self.parameterAsVectorLayer(
            parameters, self.WASTEWATER_NODE_LAYER, context)
        value_expression = self.parameterAsExpression(parameters,
                                                      self.VALUE_EXPRESSION,
                                                      context)
        reach_pk_name = self.parameterAsFields(parameters, self.REACH_PK_NAME,
                                               context)[0]
        node_pk_name = self.parameterAsFields(parameters, self.NODE_PK_NAME,
                                              context)[0]
        node_from_fk_name = self.parameterAsFields(parameters,
                                                   self.NODE_FROM_FK_NAME,
                                                   context)[0]
        node_to_fk_name = self.parameterAsFields(parameters,
                                                 self.NODE_TO_FK_NAME,
                                                 context)[0]
        branch_behavior = self.parameterAsEnum(parameters,
                                               self.BRANCH_BEHAVIOR, context)
        create_loop_layer = self.parameterAsBool(parameters,
                                                 self.CREATE_LOOP_LAYER,
                                                 context)

        if branch_behavior == 0:
            aggregate_method = lambda values: min(values) if values else 0
        elif branch_behavior == 1:
            aggregate_method = lambda values: max(values) if values else 0
        elif branch_behavior == 2:
            aggregate_method = lambda values: statistics.mean(
                values) if values else 0
        else:
            aggregate_method = lambda values: feedback.pushError(
                'Aggregate method not implemented')

        # create feature sink
        fields = wastewater_node_layer.fields()
        fields.append(QgsField('value', QVariant.Double))
        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, fields,
                                               QgsWkbTypes.Point,
                                               reach_layer.sourceCrs())

        loop_sink = None
        loop_dest_id = None
        if create_loop_layer:
            (loop_sink,
             loop_dest_id) = self.parameterAsSink(parameters, self.LOOP_OUTPUT,
                                                  context, fields,
                                                  QgsWkbTypes.Point,
                                                  reach_layer.sourceCrs())

        if sink is None:
            raise QgsProcessingException(
                self.invalidSinkError(parameters, self.OUTPUT))

        feature_count = reach_layer.featureCount()

        reaches_by_from_node = dict()
        reaches_by_id = dict()

        expression = QgsExpression(value_expression)
        context = QgsExpressionContext(
            QgsExpressionContextUtils.globalProjectLayerScopes(reach_layer))
        expression.prepare(context)

        progress = 0
        feedback.setProgressText(self.tr('Indexing reaches'))
        for reach in reach_layer.getFeatures(QgsFeatureRequest()):
            if reach[node_from_fk_name] == NULL:
                continue

            context.setFeature(reach)
            value = expression.evaluate(context)
            reach_obj = Reach(reach[node_from_fk_name], reach[node_to_fk_name],
                              value, reach.geometry())
            reaches_by_from_node.setdefault(reach_obj.from_id,
                                            []).append(reach_obj)
            reaches_by_id[reach[reach_pk_name]] = reach_obj

            feedback.setProgress(progress / feature_count * 10)
            progress += 1

        loop_nodes = []
        current_feature = 0
        calculated_values = {}

        feedback.setProgressText(self.tr('Analyzing network'))
        for node in wastewater_node_layer.getFeatures():

            from_node_id = node[node_pk_name]

            processed_nodes = []
            times = []
            if from_node_id in reaches_by_from_node.keys():
                for reach in reaches_by_from_node[from_node_id]:
                    times.append(
                        self.calculate_branch(reach, reaches_by_from_node,
                                              reaches_by_id,
                                              list(processed_nodes),
                                              calculated_values,
                                              aggregate_method, loop_nodes,
                                              feedback))

            if times:
                time = aggregate_method(times)
            else:
                time = 0

            current_feature += 1

            calculated_values[node[node_pk_name]] = time
            new_node = QgsFeature(node)
            new_node.setFields(fields)
            new_node.setAttributes(node.attributes() + [time])

            sink.addFeature(new_node, QgsFeatureSink.FastInsert)

            if create_loop_layer and from_node_id in loop_nodes:
                loop_sink.addFeature(node, QgsFeatureSink.FastInsert)

            feedback.setProgress(10 + current_feature / feature_count * 90)

        result = {self.OUTPUT: dest_id}
        if create_loop_layer:
            result[self.LOOP_OUTPUT] = loop_dest_id

        return result
示例#36
0
    def addNewTrace(self):
        '''
        fill the table with the parameters added in the dialog
        '''
        row = self.traceTable.rowCount()
        self.traceTable.insertRow(row)

        # fill the table with each paramter entered
        self.traceTable.setItem(row, 0, QTableWidgetItem(str(self.index)))
        self.traceTable.setItem(
            row, 1, QTableWidgetItem(str(self.LayerCombo.currentText())))
        self.traceTable.setItem(
            row, 2, QTableWidgetItem(str(self.expField1.currentText())))
        self.traceTable.setItem(
            row, 3, QTableWidgetItem(str(self.expField2.currentText())))
        if self.dataDefined.isActive():
            self.traceTable.setItem(
                row, 4, QTableWidgetItem(str(self.dataDefined.getField())))
        else:
            self.traceTable.setItem(row, 4,
                                    QTableWidgetItem(str(self.Size.value())))
        self.traceTable.setItem(
            row, 5, QTableWidgetItem(str(self.symbolCombo.currentText())))
        self.traceTable.setItem(
            row, 6, QTableWidgetItem(str(self.colorButton.color().name())))
        self.traceTable.setItem(row, 7,
                                QTableWidgetItem(str(self.alpha.value())))

        self.index += 1

        # get layer and the selected fields (signals and update directly in the UI)

        # QgsVectorLayer
        lay1 = self.expField1.layer()
        # name of the field of the QgsVectorLayer
        lay1_f = self.expField1.currentText()
        # QgsVectorLayer
        lay2 = self.expField2.layer()
        # name of the field of the QgsVectorLayer
        lay2_f = self.expField2.currentText()

        # build the lists from the selected fields
        f1 = []
        f2 = []

        # cicle to use normal field or selected expression for first layer
        if self.expField1.currentField()[1] == False:
            for i in lay1.getFeatures():
                f1.append(i[lay1_f])
        else:
            filter1 = self.expField1.currentField()[0]
            exp1 = QgsExpression(filter1)
            for i in lay1.getFeatures():
                f1.append(exp1.evaluate(i, lay1.pendingFields()))

        # cicle to use normal field or selected expression for second layer
        if self.expField2.currentField()[1] == False:
            for i in lay2.getFeatures():
                f2.append(i[lay2_f])
        else:
            filter2 = self.expField2.currentField()[0]
            exp2 = QgsExpression(filter2)
            for i in lay2.getFeatures():
                f2.append(exp2.evaluate(i, lay2.pendingFields()))

        # get the hex code from the button
        colorhex = self.colorButton.color().name()

        # convert the hex code to a rgb tuple
        colorrgb = hex_to_rgb(colorhex)

        # color for the outline line
        colorhex2 = self.colorButton2.color().name()

        # convert the hex code to a rgb tuple
        colorrgb2 = hex_to_rgb(colorhex2)

        # value of the slider for the alpha channel
        alphavalue = self.alpha.value()

        # size settings
        if self.dataDefined.isActive() == False:
            markSize = self.Size.value()
        else:
            markSize = []
            if self.dataDefined.useExpression() == True:
                sizefilter = self.dataDefined.getExpression()
                sizeexp = QgsExpression(sizefilter)
                for i in self.LayerCombo.currentLayer().getFeatures():
                    markSize.append(
                        sizeexp.evaluate(
                            i,
                            self.LayerCombo.currentLayer().pendingFields()))
            else:
                for i in self.LayerCombo.currentLayer().getFeatures():
                    markSize.append(i[self.dataDefined.getField()])

        # symbol choice
        symbol = self.symbolCombo.currentText()

        # create dictionary with all the plot parameters (each time the button is clicked a ner dictionary is added as VALUE to the initial dictionary)

        self.plot_param = dict()
        self.plot_param["index"] = self.index
        self.plot_param["layer"] = (self.LayerCombo.currentLayer())
        self.plot_param["X"] = f1
        self.plot_param["Y"] = f2
        self.plot_param["Size"] = markSize
        self.plot_param["Marker"] = symbol
        self.plot_param["Color"] = colorrgb
        self.plot_param["OutLine_Color"] = colorrgb2
        self.plot_param["OutLine_Width"] = self.widthBox.value()
        self.plot_param["Transparency"] = alphavalue
        self.plot_param["Name"] = self.expField2.currentText()

        # add the dictionary with plot values to the initial dictionary
        self.superdict[row] = self.plot_param
示例#37
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)
示例#38
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        if source is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUT))

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

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

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

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

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

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

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

            if not f.hasGeometry():
                continue

            current_progress = total * current
            feedback.setProgress(current_progress)

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

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

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

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

            index = QgsSpatialIndex()
            points = dict()

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

            random.seed()

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

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

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

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

        feedback.setProgress(100)

        return {self.OUTPUT: dest_id}
示例#39
0
    def processAlgorithm(self, progress):
        layer = self.getParameterValue(self.INPUT_LAYER)
        mapping = self.getParameterValue(self.FIELDS_MAPPING)
        output = self.getOutputFromName(self.OUTPUT_LAYER)

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

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

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

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

            expression = QgsExpression(field_def['expression'])
            expression.setGeomCalculator(da)
            expression.setDistanceUnits(QgsProject.instance().distanceUnits())
            expression.setAreaUnits(QgsProject.instance().areaUnits())

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

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

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

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

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

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

            writer.addFeature(outFeat)

            progress.setPercentage(int(current * total))

        del writer

        if not calculationSuccess:
            raise GeoAlgorithmExecutionException(
                self.tr('An error occurred while evaluating the calculation'
                        ' string:\n') + error)
示例#40
0
    def reloadData(self):
        self.beginResetModel()
        self._document_list = []

        if self._relation.isValid() is False or self._feature.isValid(
        ) is False:
            self.endResetModel()
            return

        feature_list = []
        layer = self._relation.referencingLayer()
        request = self._relation.getRelatedFeaturesRequest(self._feature)
        for feature in layer.getFeatures(request):
            feature_list.append(feature)

        if self._nmRelation.isValid():
            filters = []
            for joinTableFeature in feature_list:
                referencedFeatureRequest = self._nmRelation.getReferencedFeatureRequest(
                    joinTableFeature)
                filterExpression = referencedFeatureRequest.filterExpression()
                filters.append("(" + filterExpression.expression() + ")")

            nmRequest = QgsFeatureRequest()
            nmRequest.setFilterExpression(" OR ".join(filters))

            feature_list = []
            layer = self._nmRelation.referencedLayer()
            for documentFeature in layer.getFeatures(nmRequest):
                feature_list.append(documentFeature)

        for documentFeature in feature_list:
            documents_path = str()
            if self._documents_path:
                exp = QgsExpression(self._documents_path)
                context = QgsExpressionContext()
                context.appendScopes(
                    QgsExpressionContextUtils.globalProjectLayerScopes(layer))
                context.setFeature(documentFeature)
                documents_path = exp.evaluate(context)

            document_filename = str()
            if self._document_filename:
                exp = QgsExpression(self._document_filename)
                context = QgsExpressionContext()
                context.appendScopes(
                    QgsExpressionContextUtils.globalProjectLayerScopes(layer))
                context.setFeature(documentFeature)
                document_filename = exp.evaluate(context)
            file_info = QFileInfo(QDir(str(documents_path)),
                                  str(document_filename))

            # ToolTip
            toolTipList = []
            toolTipList.append("<ul>")
            for field in documentFeature.fields():
                index = documentFeature.fields().indexFromName(field.name())
                toolTipList.append("<li><strong>{0}</strong>: {1}</li>".format(
                    field.displayName(), documentFeature[index]))
            toolTipList.append("</ul>")

            self._document_list.append({
                self.DocumentIdRole:
                documentFeature.id(),
                self.DocumentPathRole:
                file_info.filePath(),
                self.DocumentNameRole:
                file_info.fileName(),
                self.DocumentExistsRole:
                file_info.exists(),
                self.DocumentToolTipRole:
                "".join(toolTipList),
                self.DocumentIsImageRole:
                PreviewImageProvider.isMimeTypeSupported(file_info.filePath())
            })

        self.endResetModel()
示例#41
0
class GeometryByExpression(QgisFeatureBasedAlgorithm):

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

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

    def groupId(self):
        return 'vectorgeometry'

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

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

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

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

    def name(self):
        return 'geometrybyexpression'

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

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

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

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

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

        return True

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

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

    def sourceFlags(self):
        return QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks

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

        if not value:
            feature.setGeometry(QgsGeometry())
        else:
            if not isinstance(value, QgsGeometry):
                raise QgsProcessingException(
                    self.tr('{} is not a geometry').format(value))
            feature.setGeometry(value)
        return [feature]
示例#42
0
    def processAlgorithm(self, parameters, 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 / layer.featureCount() if layer.featureCount() else 0

        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, QgsFeatureSink.FastInsert)

            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))
示例#43
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}
示例#44
0
    def save_hazard_data(self):
        hazard_geojson = PetaJakartaAPI.get_aggregate_report(
            self.duration, self.level)

        if not hazard_geojson:
            raise PetaJakartaAPIError("Can't access PetaJakarta REST API")

        with open(self.hazard_path, 'w+') as f:
            f.write(hazard_geojson)

        # Save the layer as shp
        file_info = QFileInfo(self.hazard_path)
        hazard_layer = QgsVectorLayer(self.hazard_path, file_info.baseName(),
                                      'ogr', False)

        target_name = 'flood_data.shp'
        self.hazard_path = os.path.join(self.report_path, target_name)
        QgsVectorFileWriter.writeAsVectorFormat(hazard_layer, self.hazard_path,
                                                'CP1250', None,
                                                'ESRI Shapefile')

        file_info = QFileInfo(self.hazard_path)
        hazard_layer = QgsVectorLayer(self.hazard_path, file_info.baseName(),
                                      'ogr')

        hazard_layer.startEditing()
        field = QgsField('flooded', QVariant.Int)
        hazard_layer.dataProvider().addAttributes([field])
        hazard_layer.commitChanges()
        idx = hazard_layer.fieldNameIndex('flooded')
        expression = QgsExpression('count > 0')
        expression.prepare(hazard_layer.pendingFields())

        hazard_layer.startEditing()
        for feature in hazard_layer.getFeatures():
            feature[idx] = expression.evaluate(feature)
            hazard_layer.updateFeature(feature)

        hazard_layer.commitChanges()

        # writing keywords
        keyword_io = KeywordIO()

        keywords = {
            'field': 'flooded',
            'hazard': 'flood',
            'hazard_category': 'single_event',
            'keyword_version': '3.3',
            'layer_geometry': 'polygon',
            'layer_mode': 'classified',
            'layer_purpose': 'hazard',
            'title': 'Flood',
            'value_map': '{"wet": [1], "dry": [0]}',
            'vector_hazard_classification': 'flood_vector_hazard_classes'
        }

        keyword_io.write_keywords(hazard_layer, keywords)

        # archiving hazard layer
        with ZipFile(self.hazard_zip_path, 'w') as zf:
            for root, dirs, files in os.walk(self.report_path):
                for f in files:
                    _, ext = os.path.splitext(f)
                    if 'flood_data' in f:
                        filename = os.path.join(root, f)
                        zf.write(filename, arcname=f)
示例#45
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT_LAYER))
        fieldName = self.getParameterValue(self.FIELD_NAME)
        fieldType = self.TYPES[self.getParameterValue(self.FIELD_TYPE)]
        width = self.getParameterValue(self.FIELD_LENGTH)
        precision = self.getParameterValue(self.FIELD_PRECISION)
        newField = self.getParameterValue(self.NEW_FIELD)
        formula = self.getParameterValue(self.FORMULA)

        output = self.getOutputFromName(self.OUTPUT_LAYER)

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

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

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

        exp = QgsExpression(formula)

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

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

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

        error = ''
        calculationSuccess = True

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

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

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

        if not calculationSuccess:
            raise GeoAlgorithmExecutionException(
                self.tr('An error occured while evaluating the calculation '
                        'string:\n%s' % error))
示例#46
0
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        ueberhoehung = self.parameterAsInt(parameters, self.INPUTZFACTOR, context)
        vectorLayer = self.parameterAsVectorLayer(parameters, self.INPUTVECTORLAYER, context)
        baseLineLayer = self.parameterAsVectorLayer(parameters, self.INPUTBASELINE, context)
        offsetFieldName = self.parameterAsString(parameters, self.OFFSETFIELD, context)
        #offsetFieldIndex=-1
        
        #if not offsetFieldName=="":
            #fields = vectorLayer.fields()
            #offsetFieldIndex = vectorLayer.fields().lookupField(offsetFieldName)
        offsetExpr=QgsExpression(offsetFieldName)
        if offsetExpr.hasParserError():
            feedback.reportError("Offset Expression failed: " + offsetExpr.parserErrorString())
            offsetExpr="0"
            
        offsetExprContext = QgsExpressionContext()
        baseLineFeature=None
        baseLine=None
        #Basline Layer must have only 1 Feature
        if baseLineLayer.featureCount()==1:
        #baseLine must be the first feature
            baseLineFeature=next(baseLineLayer.getFeatures(QgsFeatureRequest().setLimit(1)))
            baseLine=baseLineFeature.geometry()
        elif len(baseLineLayer.selectedFeatures())==1:
            selection=baseLineLayer.selectedFeatures()
            #baseLine must be the first feature
            selFeats=[f for f in selection]
            baseLineFeature=selFeats[0]
            baseLine=baseLineFeature.geometry() 
        else:
            msg = self.tr("Error: BaseLine layer needs exactly one line feature! "+ str(baseLineLayer.featureCount()) + " Just select one feature!")
            feedback.reportError(msg)
            raise QgsProcessingException(msg)

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



        #take CRS from Project
        crsProject=QgsProject.instance().crs()         
        #check if layers have the same crs
        if not baseLineLayer.crs().authid()==crsProject.authid():
            # if not, transform to raster crs()
            trafo=QgsCoordinateTransform(baseLineLayer.crs(),crsProject,QgsProject.instance())
            #transform BaseLine
            opResult=baseLine.transform(trafo,QgsCoordinateTransform.ForwardTransform, False)

        
        linRef = LinearReferencingMaschine(baseLine, crsProject, feedback)
        
        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                context, vectorLayer.fields(), vectorLayer.wkbType(), crsProject)

        try:
            total = 100.0 / vectorLayer.featureCount()
        except:
            msg = self.tr("Keine Basislinie")
            feedback.reportError(msg)
            raise QgsProcessingException(msg)
        
        #check Selection of Inputlayer
        #if yes, use just the selection
        processfeatures=None
        if len(vectorLayer.selectedFeatures()) == 0:
            processfeatures = vectorLayer.getFeatures()
        else:
            processfeatures = vectorLayer.selectedFeatures() 

        
        i=0
        for feat in processfeatures: #vectorLayer.getFeatures():

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

            layerUtils=LayerUtils( crsProject, feedback)
            subFeatureList=layerUtils.multiPartToSinglePartFeature( feat )

            #preparation of profile geometrys
            prepSubFeatureList=[]
            for iP, f in enumerate(subFeatureList):
                if linRef.isSimpleLine or vectorLayer.geometryType() == 0 or vectorLayer.geometryType() == 1: #Point (Line nur temporär):
                    prepSubFeatureList.append( f ) #keep old feature                
                else:
                    # Basisline hat Knickpunkte, Profilgeometrien müssen ggf. mit zusätzlichen Stützpunkten gefüllt werden
                    # Baseline has breakpoints, we have to fill the profile geometrys with additional vertices
                    filledSingleGeom = None
                    if vectorLayer.geometryType() == 2: #Polygon
                        filledSingleGeomList = self.fillPolygonVertices( f.geometry() , linRef, crsProject, feedback)
                    #elif vectorLayer.geometryType() == 1: #Line
                    
                    if len(filledSingleGeomList) > 0:
                        for g in filledSingleGeomList:
                            #create a feature for each filled sub geometry
                            filledFeature=QgsFeature( f )
                            filledFeature.setGeometry( g )
                            filledFeature.setAttributes( f.attributes() )
                            prepSubFeatureList.append( filledFeature )
                    else:
                        prepSubFeatureList.append( f ) #keep old feature
                        feedback.reportError( "Feature geometry can not be filled: " + str( f.attributes() ) )


                
            #Back to Real World Transformation for each sub Feature
            realWorldSubFeatureList=[]
            for pFeat in prepSubFeatureList:
            
                #Create Real World geometry with LinearReferencingMaschine
                realWorldFeat=linRef.transformProfileFeatureToRealWorld( pFeat, vectorLayer.crs(), feedback, abstand, ueberhoehung )
                realWorldSubFeatureList.append( realWorldFeat )
                
            ##### ggf features könnten hier wieder gruppiert werden ######
                
            #write real worl Features to output layer
            for rwFeat in realWorldSubFeatureList:
                sink.addFeature(rwFeat, QgsFeatureSink.FastInsert)
 
 
            i=i+1
            # Update the progress bar
            feedback.setProgress(int(i * total))

        msgInfo=self.tr(str(i) + " Features were transformed to real world coordinates")
        feedback.pushInfo(msgInfo)
        # Return the results of the algorithm. In this case our only result is
        return {self.OUTPUT: dest_id}
示例#47
0
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        ueberhoehung = self.parameterAsInt(parameters, self.INPUTZFACTOR,
                                           context)
        rasterLayer = self.parameterAsRasterLayer(parameters, self.INPUTRASTER,
                                                  context)
        baseLineLayer = self.parameterAsVectorLayer(parameters,
                                                    self.INPUTBASELINE,
                                                    context)
        polygonLayer = self.parameterAsVectorLayer(parameters,
                                                   self.INPUTINTERSECTIONLAYER,
                                                   context)
        outputGeomType = self.parameterAsEnum(parameters, self.OUTPUTGEOMTYPE,
                                              context)
        exprBaselineID = self.parameterAsExpression(parameters,
                                                    self.SOURCE_BASLINE_ID,
                                                    context)

        mywkbType = None
        if outputGeomType == 1:  #'Points':
            mywkbType = 1

        else:  #0 Lines

            mywkbType = 2

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

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

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, fields, mywkbType,
                                               polygonLayer.sourceCrs())
        #try:

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

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

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

        # Compute the number of steps to display within the progress bar and
        # get features from source
        total = 100.0 / len(features) if len(features) else 0
        #names = [field.name()+"; " for field in fields]
        #feedback.pushInfo(''.join( names ) )
        #Clear Selection
        baseLineLayer.removeSelection()
        counter = 0
        for current, feature in enumerate(features):
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                break

            expr = QgsExpression(exprBaselineID)
            exprContext = QgsExpressionContext()
            exprContext.setFeature(feature)

            profilID = expr.evaluate(exprContext)  #, baseLineLayer.fields() )
            feedback.pushInfo(
                str(exprBaselineID) + ": Profil-ID: " + str(profilID))
            #select to current feature
            baseLineLayer.select(feature.id())
            #create profile feature for selected line
            #if False:
            #feedback.pushInfo( "Selection " + str( polygonLayer.selectedFeatureCount() ) + " Objects"  )
            feedback.pushInfo("Counter: " + str(counter))
            gradient_features = None
            try:
                gradient_features = self.runPolygonIntersection(
                    polygonLayer, baseLineLayer, rasterLayer, ueberhoehung,
                    outputGeomType, context, feedback)
                count = 0
                for grFeature in gradient_features:
                    #feedback.pushInfo("Type: " + str(type(grFeature)) )
                    if not str(type(
                            grFeature)) == "<class 'qgis._core.QgsFeature'>":
                        feedback.pushInfo("Abbruch Type: " +
                                          str(type(grFeature)))
                        break

                    newFeature = QgsFeature(fields)
                    attrs = grFeature.attributes()
                    #attrs.append( ueberhoehung ) # Wird bereits in runPolygonIntersection zugefügt
                    attrs.append(profilID)

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

            #Clear Selection
            baseLineLayer.removeSelection()

            # Update the progress bar
            feedback.setProgress(int(current * total))
            counter = counter + 1
        #except Exception as err:
        #    feedback.pushInfo("ERROR: "+ str(err.args) + " " + str(repr( err )) + " Fehler: "  )
        #
        #    print("ERROR:", err.args, repr( err ), "Fehler: " )

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

        # Return the results of the algorithm. In this case our only result is
        # the feature sink which contains the processed features, but some
        # algorithms may return multiple feature sinks, calculated numeric
        # statistics, etc. These should all be included in the returned
        # dictionary, with keys matching the feature corresponding parameter
        # or output names.
        return {self.OUTPUT: dest_id}
示例#48
0
def exportJSONLayer(layer, eachPopup, precision, tmpFileName, exp_crs,
                    layerFileName, safeLayerName, minify, canvas,
                    restrictToExtent, iface, extent):
    cleanedLayer = writeTmpLayer(layer, eachPopup, restrictToExtent, iface,
                                 extent)
    if is25d(layer, canvas, restrictToExtent, extent):
        provider = cleanedLayer.dataProvider()
        provider.addAttributes([
            QgsField("height", QVariant.Double),
            QgsField("wallColor", QVariant.String),
            QgsField("roofColor", QVariant.String)
        ])
        cleanedLayer.updateFields()
        fields = cleanedLayer.pendingFields()
        renderer = layer.rendererV2()
        renderContext = QgsRenderContext.fromMapSettings(canvas.mapSettings())
        feats = layer.getFeatures()
        context = QgsExpressionContext()
        context.appendScope(QgsExpressionContextUtils.layerScope(layer))
        expression = QgsExpression('eval(@qgis_25d_height)')
        heightField = fields.indexFromName("height")
        wallField = fields.indexFromName("wallColor")
        roofField = fields.indexFromName("roofColor")
        renderer.startRender(renderContext, fields)
        cleanedLayer.startEditing()
        for feat in feats:
            context.setFeature(feat)
            height = expression.evaluate(context)
            if isinstance(renderer, QgsCategorizedSymbolRendererV2):
                classAttribute = renderer.classAttribute()
                attrValue = feat.attribute(classAttribute)
                catIndex = renderer.categoryIndexForValue(attrValue)
                categories = renderer.categories()
                symbol = categories[catIndex].symbol()
            elif isinstance(renderer, QgsGraduatedSymbolRendererV2):
                classAttribute = renderer.classAttribute()
                attrValue = feat.attribute(classAttribute)
                ranges = renderer.ranges()
                for range in ranges:
                    if (attrValue >= range.lowerValue()
                            and attrValue <= range.upperValue()):
                        symbol = range.symbol().clone()
            else:
                symbol = renderer.symbolForFeature2(feat, renderContext)
            wallColor = symbol.symbolLayer(1).subSymbol().color().name()
            roofColor = symbol.symbolLayer(2).subSymbol().color().name()
            cleanedLayer.changeAttributeValue(feat.id() + 1, heightField,
                                              height)
            cleanedLayer.changeAttributeValue(feat.id() + 1, wallField,
                                              wallColor)
            cleanedLayer.changeAttributeValue(feat.id() + 1, roofField,
                                              roofColor)
        cleanedLayer.commitChanges()
        renderer.stopRender(renderContext)

    writer = QgsVectorFileWriter
    options = []
    if precision != "maintain":
        options.append("COORDINATE_PRECISION=" + unicode(precision))
    writer.writeAsVectorFormat(cleanedLayer,
                               tmpFileName,
                               'utf-8',
                               exp_crs,
                               'GeoJson',
                               0,
                               layerOptions=options)

    with open(layerFileName, "w") as f2:
        f2.write("var json_" + unicode(safeLayerName) + "=")
        with open(tmpFileName, "r") as tmpFile:
            for line in tmpFile:
                if minify:
                    line = line.strip("\n\t ")
                    line = removeSpaces(line)
                f2.write(line)
        os.remove(tmpFileName)

    fields = layer.pendingFields()
    for field in fields:
        exportImages(layer, field.name(), layerFileName)
示例#49
0
    def processAlgorithm(self, parameters, context, feedback):
        layer = self.getParameterValue(self.INPUT_LAYER)
        mapping = self.getParameterValue(self.FIELDS_MAPPING)
        output = self.getOutputFromName(self.OUTPUT_LAYER)

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

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

        exp_context = layer.createExpressionContext()

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

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

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

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

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

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

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

                writer.addFeature(outFeat)

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

        del writer

        if error_exp is not None:
            raise GeoAlgorithmExecutionException(
                self.tr(u'Evaluation error in expression "{}": {}').format(
                    str(error_exp.expression()),
                    str(error_exp.parserErrorString())))
示例#50
0
class VectorLayer:
    def __init__(self, settings, layer, materialManager, modelManager):
        """layer: Layer object"""
        self.settings = settings
        self.renderContext = QgsRenderContext.fromMapSettings(
            settings.mapSettings)

        self.mapLayer = layer.mapLayer
        self.name = self.mapLayer.name() if self.mapLayer else "no title"
        self.properties = layer.properties

        self.expressionContext = QgsExpressionContext()
        self.expressionContext.appendScope(
            QgsExpressionContextUtils.layerScope(self.mapLayer))

        self.objectType = ObjectType.typeByName(
            self.properties.get("comboBox_ObjectType"),
            self.mapLayer.geometryType())

        self.materialManager = materialManager
        self.modelManager = modelManager
        self.colorNames = []  # for random color

        self.transform = QgsCoordinateTransform(self.mapLayer.crs(),
                                                settings.crs,
                                                QgsProject.instance())
        self.geomType = self.mapLayer.geometryType()

        # attributes
        self.writeAttrs = self.properties.get("checkBox_ExportAttrs", False)
        self.labelAttrIndex = self.properties.get("comboBox_Label", None)
        self.fieldIndices = []
        self.fieldNames = []

        if self.writeAttrs:
            for index, field in enumerate(self.mapLayer.fields()):
                if field.editorWidgetSetup().type() != "Hidden":
                    self.fieldIndices.append(index)
                    self.fieldNames.append(field.displayName())

        # expressions
        self._exprs = {}
        self.exprAlt = QgsExpression(
            self.properties.get("fieldExpressionWidget_altitude") or "0")
        self.exprLabel = QgsExpression(
            self.properties.get("labelHeightWidget", {}).get("editText")
            or "0")

    def features(self, request=None):
        mapTo3d = self.settings.mapTo3d()
        baseExtent = self.settings.baseExtent
        baseExtentGeom = baseExtent.geometry()
        rotation = baseExtent.rotation()
        fields = self.mapLayer.fields()

        # initialize symbol rendering, and then get features (geometry, attributes, color, etc.)
        self.renderer = self.mapLayer.renderer().clone()
        self.renderer.startRender(self.renderContext, self.mapLayer.fields())

        for f in self.mapLayer.getFeatures(request or QgsFeatureRequest()):
            geometry = f.geometry()
            if geometry is None:
                logMessage("null geometry skipped")
                continue

            # coordinate transformation - layer crs to project crs
            geom = QgsGeometry(geometry)
            if geom.transform(self.transform) != 0:
                logMessage("Failed to transform geometry")
                continue

            # check if geometry intersects with the base extent (rotated rect)
            if rotation and not baseExtentGeom.intersects(geom):
                continue

            # set feature to expression context
            self.expressionContext.setFeature(f)

            # evaluate expression
            altitude = float(
                self.exprAlt.evaluate(self.expressionContext) or 0)
            swVals = self.styleWidgetValues(f)

            attrs = labelHeight = None
            if self.writeAttrs:
                attrs = [
                    fields[i].displayString(f.attribute(i))
                    for i in self.fieldIndices
                ]

                if self.hasLabel():
                    labelHeight = float(
                        self.exprLabel.evaluate(self.expressionContext)
                        or 0) * mapTo3d.multiplierZ

            # create a feature object
            yield Feature(self, geom, altitude, swVals, attrs, labelHeight)

        self.renderer.stopRender(self.renderContext)

    def evaluateExpression(self, expr_str, f):
        if expr_str not in self._exprs:
            self._exprs[expr_str] = QgsExpression(expr_str)

        self.expressionContext.setFeature(f)
        return self._exprs[expr_str].evaluate(self.expressionContext)

    def readFillColor(self, vals, f):
        return self._readColor(vals, f)

    def readBorderColor(self, vals, f):
        return self._readColor(vals, f, isBorder=True)

    # read color from COLOR or OPTIONAL_COLOR widget
    def _readColor(self, widgetValues, f, isBorder=False):
        mode = widgetValues["comboData"]
        if mode == OptionalColorWidgetFunc.NONE:
            return None

        if mode == ColorWidgetFunc.EXPRESSION:
            val = self.evaluateExpression(widgetValues["editText"], f)
            try:
                if isinstance(val, str):
                    a = val.split(",")
                    if len(a) >= 3:
                        a = [max(0, min(int(c), 255)) for c in a[:3]]
                        return "0x{:02x}{:02x}{:02x}".format(a[0], a[1], a[2])
                    return val.replace("#", "0x")

                raise
            except:
                logMessage("Wrong color value: {}".format(val))
                return "0"

        if mode == ColorWidgetFunc.RANDOM or f is None:
            self.colorNames = self.colorNames or QColor.colorNames()
            color = random.choice(self.colorNames)
            self.colorNames.remove(color)
            return QColor(color).name().replace("#", "0x")

        # feature color
        symbols = self.renderer.symbolsForFeature(f, self.renderContext)
        if not symbols:
            logMessage(
                "Symbol for feature not found. Please use a simple renderer for {0}."
                .format(self.name))
            return "0"

        symbol = symbols[0]
        if isBorder:
            sl = symbol.symbolLayer(0)
            if sl:
                return sl.strokeColor().name().replace("#", "0x")

        return symbol.color().name().replace("#", "0x")

    def readOpacity(self, widgetValues, f):
        vals = widgetValues

        if vals["comboData"] == OpacityWidgetFunc.EXPRESSION:
            try:
                val = self.evaluateExpression(widgetValues["editText"], f)
                return min(max(0, val), 100) / 100
            except:
                logMessage("Wrong opacity value: {}".format(val))
                return 1

        symbols = self.renderer.symbolsForFeature(f, self.renderContext)
        if not symbols:
            logMessage(
                "Symbol for feature not found. Please use a simple renderer for {0}."
                .format(self.name))
            return 1

        symbol = symbols[0]
        return self.mapLayer.opacity() * symbol.opacity()

    @classmethod
    def toFloat(cls, val):
        try:
            return float(val)
        except Exception as e:
            logMessage('{0} (value: {1})'.format(e.message, str(val)))
            return 0

    # functions to read values from height widget (z coordinate)
    def useZ(self):
        return self.properties.get("radioButton_zValue", False)

    def useM(self):
        return self.properties.get("radioButton_mValue", False)

    def isHeightRelativeToDEM(self):
        return self.properties.get("comboBox_altitudeMode") is not None

    def hasLabel(self):
        return bool(self.labelAttrIndex is not None)

    # read values from style widgets
    def styleWidgetValues(self, f):
        vals = []
        for i in range(16):  # big number for style count
            widgetValues = self.properties.get("styleWidget" + str(i))
            if not widgetValues:
                break

            widgetType = widgetValues["type"]
            comboData = widgetValues.get("comboData")
            if widgetType == StyleWidget.COLOR:
                vals.append(self.readFillColor(widgetValues, f))

            elif widgetType == StyleWidget.OPACITY:
                vals.append(self.readOpacity(widgetValues, f))

            elif widgetType in (StyleWidget.EXPRESSION,
                                StyleWidget.LABEL_HEIGHT):
                expr = widgetValues["editText"]
                val = self.evaluateExpression(expr, f)
                if val:
                    vals.append(val)
                else:
                    if val is None:
                        logMessage(
                            "Failed to evaluate expression: {} ({})".format(
                                expr, self.name))
                    else:  # if val.isNull():
                        logMessage("NULL was treated as zero. ({})".format(
                            self.name))
                    vals.append(0)

            elif widgetType == StyleWidget.OPTIONAL_COLOR:
                vals.append(self.readBorderColor(widgetValues, f))

            elif widgetType == StyleWidget.CHECKBOX:
                vals.append(widgetValues["checkBox"])

            elif widgetType == StyleWidget.COMBOBOX:
                vals.append(widgetValues["comboData"])

            elif widgetType == StyleWidget.FILEPATH:
                expr = widgetValues["editText"]
                val = self.evaluateExpression(expr, f)
                if val is None:
                    logMessage("Failed to evaluate expression: " + expr)
                vals.append(val or "")

            elif widgetType == StyleWidget.COLOR_TEXTURE:
                if comboData == ColorTextureWidgetFunc.MAP_CANVAS:
                    vals.append(comboData)
                elif comboData == ColorTextureWidgetFunc.LAYER:
                    vals.append(widgetValues.get("layerIds", []))
                else:
                    vals.append(self.readFillColor(widgetValues, f))

            else:
                logMessage("Widget type {} not found.".format(widgetType))
                vals.append(None)

        return vals
示例#51
0
    def processAlgorithm(self, parameters, context, feedback):
        if DEBUG_MODE:
            logMessage("processAlgorithm(): {}".format(self.__class__.__name__), False)

        clayer = self.parameterAsLayer(parameters, self.INPUT, context)
        title_field = self.parameterAsString(parameters, self.TITLE_FIELD, context)
        cf_filter = self.parameterAsBool(parameters, self.CF_FILTER, context)
        fixed_scale = self.parameterAsEnum(parameters, self.SCALE, context)   # == 1
        buf = self.parameterAsDouble(parameters, self.BUFFER, context)
        tex_width = self.parameterAsInt(parameters, self.TEX_WIDTH, context)
        orig_tex_height = self.parameterAsInt(parameters, self.TEX_HEIGHT, context)

        header_exp = QgsExpression(self.parameterAsExpression(parameters, self.HEADER, context))
        footer_exp = QgsExpression(self.parameterAsExpression(parameters, self.FOOTER, context))

        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.layerScope(clayer))

        out_dir = self.parameterAsString(parameters, self.OUTPUT, context)
        if not QDir(out_dir).exists():
            QDir().mkpath(out_dir)

        if DEBUG_MODE:
            openDirectory(out_dir)

        mapSettings = self.settings.mapSettings
        baseExtent = self.settings.baseExtent
        rotation = mapSettings.rotation()
        orig_size = mapSettings.outputSize()

        if cf_filter:
            cf_layer = QgsMemoryProviderUtils.createMemoryLayer("current feature",
                                                                clayer.fields(),
                                                                clayer.wkbType(),
                                                                clayer.crs())
            layers = [cf_layer if lyr == clayer else lyr for lyr in mapSettings.layers()]
            mapSettings.setLayers(layers)

            doc = QDomDocument("qgis")
            clayer.exportNamedStyle(doc)
            cf_layer.importNamedStyle(doc)

        total = clayer.featureCount()
        for current, feature in enumerate(clayer.getFeatures()):
            if feedback.isCanceled():
                break

            if cf_filter:
                cf_layer.startEditing()
                cf_layer.deleteFeatures([f.id() for f in cf_layer.getFeatures()])
                cf_layer.addFeature(feature)
                cf_layer.commitChanges()

            title = feature.attribute(title_field)
            feedback.setProgressText("({}/{}) Exporting {}...".format(current + 1, total, title))
            logMessage("Exporting {}...".format(title), False)

            # extent
            geometry = QgsGeometry(feature.geometry())
            geometry.transform(self.transform)
            center = geometry.centroid().asPoint()

            if fixed_scale or geometry.type() == QgsWkbTypes.PointGeometry:
                tex_height = orig_tex_height or int(tex_width * orig_size.height() / orig_size.width())
                rect = RotatedRect(center, baseExtent.width(), baseExtent.width() * tex_height / tex_width, rotation).scale(1 + buf / 100)
            else:
                geometry.rotate(rotation, center)
                rect = geometry.boundingBox().scaled(1 + buf / 100)
                center = RotatedRect.rotatePoint(rect.center(), rotation, center)
                if orig_tex_height:
                    tex_height = orig_tex_height
                    tex_ratio = tex_width / tex_height
                    rect_ratio = rect.width() / rect.height()
                    if tex_ratio > rect_ratio:
                        rect = RotatedRect(center, rect.height() * tex_ratio, rect.height(), rotation)
                    else:
                        rect = RotatedRect(center, rect.width(), rect.width() / tex_ratio, rotation)
                else:
                    # fit to buffered geometry bounding box
                    rect = RotatedRect(center, rect.width(), rect.height(), rotation)
                    tex_height = tex_width * rect.height() / rect.width()

            rect.toMapSettings(mapSettings)
            mapSettings.setOutputSize(QSize(tex_width, tex_height))

            self.settings.setMapSettings(mapSettings)

            # labels
            exp_context.setFeature(feature)
            self.settings.setHeaderLabel(header_exp.evaluate(exp_context))
            self.settings.setFooterLabel(footer_exp.evaluate(exp_context))

            self.export(title, out_dir, feedback)

            feedback.setProgress(int(current / total * 100))

        if P_OPEN_DIRECTORY and not DEBUG_MODE:
            openDirectory(out_dir)

        return {}
示例#52
0
def exportLayers(iface, layers, folder, precision, optimize, popupField, json,
                 restrictToExtent, extent, feedback):
    canvas = iface.mapCanvas()
    epsg4326 = QgsCoordinateReferenceSystem("EPSG:4326")
    layersFolder = os.path.join(folder, "layers")
    QDir().mkpath(layersFolder)
    for count, (layer, encode2json,
                popup) in enumerate(zip(layers, json, popupField)):
        if (layer.type() == layer.VectorLayer
                and (layer.providerType() != "WFS" or encode2json)):
            feedback.showFeedback("Exporting %s to JSON..." % layer.name())
            cleanLayer = writeTmpLayer(layer, popup, restrictToExtent, iface,
                                       extent)
            fields = layer.pendingFields()
            for field in fields:
                exportImages(layer, field.name(), layersFolder + "/tmp.tmp")
            if is25d(layer, canvas, restrictToExtent, extent):
                provider = cleanLayer.dataProvider()
                provider.addAttributes([
                    QgsField("height", QVariant.Double),
                    QgsField("wallColor", QVariant.String),
                    QgsField("roofColor", QVariant.String)
                ])
                cleanLayer.updateFields()
                fields = cleanLayer.pendingFields()
                renderer = layer.rendererV2()
                renderContext = QgsRenderContext.fromMapSettings(
                    canvas.mapSettings())
                feats = layer.getFeatures()
                context = QgsExpressionContext()
                context.appendScope(
                    QgsExpressionContextUtils.layerScope(layer))
                expression = QgsExpression('eval(@qgis_25d_height)')
                heightField = fields.indexFromName("height")
                wallField = fields.indexFromName("wallColor")
                roofField = fields.indexFromName("roofColor")
                renderer.startRender(renderContext, fields)
                cleanLayer.startEditing()
                for feat in feats:
                    context.setFeature(feat)
                    height = expression.evaluate(context)
                    if isinstance(renderer, QgsCategorizedSymbolRendererV2):
                        classAttribute = renderer.classAttribute()
                        attrValue = feat.attribute(classAttribute)
                        catIndex = renderer.categoryIndexForValue(attrValue)
                        categories = renderer.categories()
                        symbol = categories[catIndex].symbol()
                    elif isinstance(renderer, QgsGraduatedSymbolRendererV2):
                        classAttribute = renderer.classAttribute()
                        attrValue = feat.attribute(classAttribute)
                        ranges = renderer.ranges()
                        for range in ranges:
                            if (attrValue >= range.lowerValue()
                                    and attrValue <= range.upperValue()):
                                symbol = range.symbol().clone()
                    else:
                        symbol = renderer.symbolForFeature2(
                            feat, renderContext)
                    sl1 = symbol.symbolLayer(1)
                    sl2 = symbol.symbolLayer(2)
                    wallColor = sl1.subSymbol().color().name()
                    roofColor = sl2.subSymbol().color().name()
                    provider.changeAttributeValues({
                        feat.id() + 1: {
                            heightField: height,
                            wallField: wallColor,
                            roofField: roofColor
                        }
                    })
                cleanLayer.commitChanges()
                renderer.stopRender(renderContext)

            sln = safeName(cleanLayer.name()) + unicode(count)
            tmpPath = os.path.join(layersFolder, sln + ".json")
            path = os.path.join(layersFolder, sln + ".js")
            options = []
            if precision != "maintain":
                options.append("COORDINATE_PRECISION=" + unicode(precision))
            QgsVectorFileWriter.writeAsVectorFormat(cleanLayer,
                                                    tmpPath,
                                                    "utf-8",
                                                    epsg4326,
                                                    'GeoJson',
                                                    0,
                                                    layerOptions=options)
            with open(path, "w") as f:
                f.write("var %s = " % ("geojson_" + sln))
                with open(tmpPath, "r") as f2:
                    for line in f2:
                        if optimize:
                            line = line.strip("\n\t ")
                            line = removeSpaces(line)
                        f.write(line)
            os.remove(tmpPath)

        elif (layer.type() == layer.RasterLayer
              and layer.providerType() != "wms"):

            feedback.showFeedback("Exporting %s to PNG..." % layer.name())
            name_ts = (safeName(layer.name()) + unicode(count) +
                       unicode(int(time.time())))

            # We need to create a new file to export style
            piped_file = os.path.join(tempfile.gettempdir(),
                                      name_ts + '_piped.tif')

            piped_extent = layer.extent()
            piped_width = layer.height()
            piped_height = layer.width()
            piped_crs = layer.crs()
            piped_renderer = layer.renderer()
            piped_provider = layer.dataProvider()

            pipe = QgsRasterPipe()
            pipe.set(piped_provider.clone())
            pipe.set(piped_renderer.clone())

            file_writer = QgsRasterFileWriter(piped_file)

            file_writer.writeRaster(pipe, piped_width, piped_height,
                                    piped_extent, piped_crs)

            # Extent of the layer in EPSG:3857
            crsSrc = layer.crs()
            crsDest = QgsCoordinateReferenceSystem(3857)
            xform = QgsCoordinateTransform(crsSrc, crsDest)
            extentRep = xform.transform(layer.extent())

            extentRepNew = ','.join([
                unicode(extentRep.xMinimum()),
                unicode(extentRep.xMaximum()),
                unicode(extentRep.yMinimum()),
                unicode(extentRep.yMaximum())
            ])

            # Reproject in 3857
            piped_3857 = os.path.join(tempfile.gettempdir(),
                                      name_ts + '_piped_3857.tif')
            # Export layer as PNG
            out_raster = os.path.join(
                layersFolder,
                safeName(layer.name()) + unicode(count) + ".png")

            qgis_version = QGis.QGIS_VERSION

            if int(qgis_version.split('.')[1]) < 15:
                processing.runalg("gdalogr:warpreproject", piped_file,
                                  layer.crs().authid(), "EPSG:3857", "", 0, 1,
                                  0, -1, 75, 6, 1, False, 0, False, "",
                                  piped_3857)
                processing.runalg("gdalogr:translate", piped_3857, 100, True,
                                  "", 0, "", extentRepNew, False, 0, 0, 75, 6,
                                  1, False, 0, False, "", out_raster)
            else:
                try:
                    warpArgs = {
                        "INPUT": piped_file,
                        "SOURCE_SRS": layer.crs().authid(),
                        "DEST_SRS": "EPSG:3857",
                        "NO_DATA": "",
                        "TR": 0,
                        "METHOD": 2,
                        "RAST_EXT": extentRepNew,
                        "EXT_CRS": "EPSG:3857",
                        "RTYPE": 0,
                        "COMPRESS": 4,
                        "JPEGCOMPRESSION": 75,
                        "ZLEVEL": 6,
                        "PREDICTOR": 1,
                        "TILED": False,
                        "BIGTIFF": 0,
                        "TFW": False,
                        "EXTRA": "",
                        "OUTPUT": piped_3857
                    }
                    procRtn = processing.runalg("gdalogr:warpreproject",
                                                warpArgs)
                    # force exception on algorithm fail
                    for val in procRtn:
                        pass
                except:
                    try:
                        warpArgs = {
                            "INPUT": piped_file,
                            "SOURCE_SRS": layer.crs().authid(),
                            "DEST_SRS": "EPSG:3857",
                            "NO_DATA": "",
                            "TR": 0,
                            "METHOD": 2,
                            "RAST_EXT": extentRepNew,
                            "RTYPE": 0,
                            "COMPRESS": 4,
                            "JPEGCOMPRESSION": 75,
                            "ZLEVEL": 6,
                            "PREDICTOR": 1,
                            "TILED": False,
                            "BIGTIFF": 0,
                            "TFW": False,
                            "EXTRA": "",
                            "OUTPUT": piped_3857
                        }
                        procRtn = processing.runalg("gdalogr:warpreproject",
                                                    warpArgs)
                        # force exception on algorithm fail
                        for val in procRtn:
                            pass
                    except:
                        try:
                            warpArgs = {
                                "INPUT": piped_file,
                                "SOURCE_SRS": layer.crs().authid(),
                                "DEST_SRS": "EPSG:3857",
                                "NO_DATA": "",
                                "TR": 0,
                                "METHOD": 2,
                                "RTYPE": 0,
                                "COMPRESS": 4,
                                "JPEGCOMPRESSION": 75,
                                "ZLEVEL": 6,
                                "PREDICTOR": 1,
                                "TILED": False,
                                "BIGTIFF": 0,
                                "TFW": False,
                                "EXTRA": "",
                                "OUTPUT": piped_3857
                            }
                            procRtn = processing.runalg(
                                "gdalogr:warpreproject", warpArgs)
                            # force exception on algorithm fail
                            for val in procRtn:
                                pass
                        except:
                            shutil.copyfile(piped_file, piped_3857)

                try:
                    processing.runalg("gdalogr:translate", piped_3857, 100,
                                      True, "", 0, "", extentRepNew, False, 5,
                                      4, 75, 6, 1, False, 0, False, "",
                                      out_raster)
                except:
                    shutil.copyfile(piped_3857, out_raster)
    feedback.completeStep()
示例#53
0
 def testCanEvaluateFunction(self):
     QgsExpression.registerFunction(self.testfun)
     exp = QgsExpression('testfun(1)')
     result = exp.evaluate()
     self.assertEqual('Testing_1', result)