def populateByExpression(self, adding=False): """ Populates the panel using an expression """ context = dataobjects.createContext() expression_context = context.expressionContext() # use the first row parameter values as a preview during expression creation params = self.panel.parametersForRow(0, warnOnInvalid=False) alg_scope = QgsExpressionContextUtils.processingAlgorithmScope(self.panel.alg, params, context) # create explicit variables corresponding to every parameter for k, v in params.items(): alg_scope.setVariable(k, v, True) expression_context.appendScope(alg_scope) # mark the parameter variables as highlighted for discoverability highlighted_vars = expression_context.highlightedVariables() highlighted_vars.extend(list(params.keys())) expression_context.setHighlightedVariables(highlighted_vars) dlg = QgsExpressionBuilderDialog(layer=None, context=context.expressionContext()) if adding: dlg.setExpectedOutputFormat(self.tr('An array of values corresponding to each new row to add')) if not dlg.exec_(): return if adding: exp = QgsExpression(dlg.expressionText()) res = exp.evaluate(expression_context) if type(res) is not list: res = [res] first_row = self.panel.batchRowCount() if self.panel.batchRowCount() > 1 else 0 for row, value in enumerate(res): self.setRowValue(row + first_row, value, context) else: for row in range(self.panel.batchRowCount()): params = self.panel.parametersForRow(row, warnOnInvalid=False) # remove previous algorithm scope -- we need to rebuild this completely, using the # other parameter values from the current row expression_context.popScope() alg_scope = QgsExpressionContextUtils.processingAlgorithmScope(self.panel.alg, params, context) for k, v in params.items(): alg_scope.setVariable(k, v, True) expression_context.appendScope(alg_scope) # rebuild a new expression every time -- we don't want the expression compiler to replace # variables with precompiled values exp = QgsExpression(dlg.expressionText()) value = exp.evaluate(expression_context) self.setRowValue(row, value, context)
def 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)
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
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 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)
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
def getValue(self): fileName = unicode(self.leText.text()) context = self.expressionContext() exp = QgsExpression(fileName) if not exp.hasParserError(): result = exp.evaluate(context) if not exp.hasEvalError(): fileName = result if fileName.startswith("[") and fileName.endswith("]"): fileName = fileName[1:-1] if fileName.strip() in ["", self.SAVE_TO_TEMP_FILE, self.SAVE_TO_TEMP_LAYER]: if isinstance(self.output, OutputVector) and self.alg.provider.supportsNonFileBasedOutput(): # use memory layers for temporary files if supported value = "memory:" else: value = None elif fileName.startswith("memory:"): value = fileName elif fileName.startswith("postgis:"): value = fileName elif fileName.startswith("spatialite:"): value = fileName elif not os.path.isabs(fileName): value = ProcessingConfig.getSetting(ProcessingConfig.OUTPUT_FOLDER) + os.sep + fileName else: value = fileName return value
def getValue(self): fileName = unicode(self.leText.text()) context = self.expressionContext() exp = QgsExpression(fileName) if not exp.hasParserError(): result = exp.evaluate(context) if not exp.hasEvalError(): fileName = result if fileName.startswith("[") and fileName.endswith("]"): fileName = fileName[1:-1] if fileName.strip() in ['', self.SAVE_TO_TEMP_FILE]: value = None elif fileName.startswith('memory:'): value = fileName elif fileName.startswith('postgis:'): value = fileName elif fileName.startswith('spatialite:'): value = fileName elif not os.path.isabs(fileName): value = ProcessingConfig.getSetting( ProcessingConfig.OUTPUT_FOLDER) + os.sep + fileName else: value = fileName return value
def 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 )
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
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
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}
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT_LAYER)) geometry_type = self.getParameterValue(self.OUTPUT_GEOMETRY) wkb_type = None if geometry_type == 0: wkb_type = QgsWkbTypes.Polygon elif geometry_type == 1: wkb_type = QgsWkbTypes.LineString else: wkb_type = QgsWkbTypes.Point if self.getParameterValue(self.WITH_Z): wkb_type = QgsWkbTypes.addZ(wkb_type) if self.getParameterValue(self.WITH_M): wkb_type = QgsWkbTypes.addM(wkb_type) writer = self.getOutputFromName( self.OUTPUT_LAYER).getVectorWriter( layer.fields(), wkb_type, layer.crs()) expression = QgsExpression(self.getParameterValue(self.EXPRESSION)) if expression.hasParserError(): raise GeoAlgorithmExecutionException(expression.parserErrorString()) exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope(QgsExpressionContextUtils.projectScope()) exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer)) if not expression.prepare(exp_context): raise GeoAlgorithmExecutionException( self.tr('Evaluation error: %s' % expression.evalErrorString())) features = vector.features(layer) total = 100.0 / len(features) for current, input_feature in enumerate(features): output_feature = input_feature exp_context.setFeature(input_feature) value = expression.evaluate(exp_context) if expression.hasEvalError(): raise GeoAlgorithmExecutionException( self.tr('Evaluation error: %s' % expression.evalErrorString())) if not value: output_feature.setGeometry(QgsGeometry()) else: if not isinstance(value, QgsGeometry): raise GeoAlgorithmExecutionException( self.tr('{} is not a geometry').format(value)) output_feature.setGeometry(value) writer.addFeature(output_feature) progress.setPercentage(int(current * total)) del writer
def __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
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))
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
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
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')
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
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()
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)
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)
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
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)
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)
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()
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
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)
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
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)
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()
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
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
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)
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}
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)
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()
class GeometryByExpression(QgisFeatureBasedAlgorithm): OUTPUT_GEOMETRY = 'OUTPUT_GEOMETRY' WITH_Z = 'WITH_Z' WITH_M = 'WITH_M' EXPRESSION = 'EXPRESSION' def group(self): return self.tr('Vector geometry') def groupId(self): return 'vectorgeometry' def flags(self): return super().flags() & ~QgsProcessingAlgorithm.FlagSupportsInPlaceEdits def __init__(self): super().__init__() self.geometry_types = [self.tr('Polygon'), 'Line', 'Point'] def initParameters(self, config=None): self.addParameter(QgsProcessingParameterEnum( self.OUTPUT_GEOMETRY, self.tr('Output geometry type'), options=self.geometry_types, defaultValue=0)) self.addParameter(QgsProcessingParameterBoolean(self.WITH_Z, self.tr('Output geometry has z dimension'), defaultValue=False)) self.addParameter(QgsProcessingParameterBoolean(self.WITH_M, self.tr('Output geometry has m values'), defaultValue=False)) self.addParameter(QgsProcessingParameterExpression(self.EXPRESSION, self.tr("Geometry expression"), defaultValue='$geometry', parentLayerParameterName='INPUT')) def name(self): return 'geometrybyexpression' def displayName(self): return self.tr('Geometry by expression') def outputName(self): return self.tr('Modified geometry') def prepareAlgorithm(self, parameters, context, feedback): self.geometry_type = self.parameterAsEnum(parameters, self.OUTPUT_GEOMETRY, context) self.wkb_type = None if self.geometry_type == 0: self.wkb_type = QgsWkbTypes.Polygon elif self.geometry_type == 1: self.wkb_type = QgsWkbTypes.LineString else: self.wkb_type = QgsWkbTypes.Point if self.parameterAsBool(parameters, self.WITH_Z, context): self.wkb_type = QgsWkbTypes.addZ(self.wkb_type) if self.parameterAsBool(parameters, self.WITH_M, context): self.wkb_type = QgsWkbTypes.addM(self.wkb_type) self.expression = QgsExpression(self.parameterAsString(parameters, self.EXPRESSION, context)) if self.expression.hasParserError(): feedback.reportError(self.expression.parserErrorString()) return False self.expression_context = self.createExpressionContext(parameters, context) self.expression.prepare(self.expression_context) return True def outputWkbType(self, input_wkb_type): return self.wkb_type def inputLayerTypes(self): return [QgsProcessing.TypeVector] def sourceFlags(self): return QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks def processFeature(self, feature, context, feedback): self.expression_context.setFeature(feature) value = self.expression.evaluate(self.expression_context) if self.expression.hasEvalError(): raise QgsProcessingException( self.tr('Evaluation error: {0}').format(self.expression.evalErrorString())) if not value: feature.setGeometry(QgsGeometry()) else: if not isinstance(value, QgsGeometry): raise QgsProcessingException( self.tr('{} is not a geometry').format(value)) feature.setGeometry(value) return [feature]
def processAlgorithm(self, parameters, context, feedback): 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))
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}
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)
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))
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}
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}
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)
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())))
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
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 {}
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()
def testCanEvaluateFunction(self): QgsExpression.registerFunction(self.testfun) exp = QgsExpression('testfun(1)') result = exp.evaluate() self.assertEqual('Testing_1', result)