def create_field_from_definition(field_definition, name=None, sub_name=None): """Helper to create a field from definition. :param field_definition: The definition of the field (see: safe.definitions.fields). :type field_definition: dict :param name: The name is required if the field name is dynamic and need a string formatting. :type name: basestring :param sub_name: The name is required if the field name is dynamic and need a string formatting. :type sub_name: basestring :return: The new field. :rtype: QgsField """ field = QgsField() if name and not sub_name: field.setName(field_definition['field_name'] % name) elif name and sub_name: field.setName(field_definition['field_name'] % (name, sub_name)) else: field.setName(field_definition['field_name']) if isinstance(field_definition['type'], list): # Use the first element in the list of type field.setType(field_definition['type'][0]) else: field.setType(field_definition['type']) field.setLength(field_definition['length']) field.setPrecision(field_definition['precision']) return field
def create_field_from_definition(field_definition, name=None): """Helper to create a field from definition. :param field_definition: The definition of the field. :type field_definition: safe.definitions.fields :param name: The name is required if the field name is dynamic and need a string formatting. :type name: basestring :return: The new field. :rtype: QgsField """ field = QgsField() if isinstance(name, QPyNullVariant): name = 'NULL' if name: field.setName(field_definition['field_name'] % name) else: field.setName(field_definition['field_name']) if isinstance(field_definition['type'], list): # Use the first element in the list of type field.setType(field_definition['type'][0]) else: field.setType(field_definition['type']) field.setLength(field_definition['length']) field.setPrecision(field_definition['precision']) return field
def addField(original, stat, type): """ Adds a field to the output, with a specified type """ field = QgsField(original) field.setName(field.name() + '_' + stat) field.setType(type) if type == QVariant.Double: field.setLength(20) field.setPrecision(6) fields_to_join.append(field)
def create_field(definition): """ Création d'un champ dans un table attributaire :param definition: Définition de nom, type, taille et précision d'un champ :type definition: definition """ field = QgsField() field.setName(definition['name']) field.setType(definition['type']) field.setPrecision(definition['precision']) field.setLength(definition['length']) return field
def createQgsField(self): qgsField = None if self.type.attributeType == GeoCsvAttributeType.integer: qgsField = QgsField(self.name, QVariant.Int) elif self.type.attributeType == GeoCsvAttributeType.easting or self.type.attributeType == GeoCsvAttributeType.northing or self.type.attributeType == GeoCsvAttributeType.real: qgsField = QgsField(self.name, QVariant.Double) else: qgsField = QgsField(self.name, QVariant.String) if not self.type.length == 0: qgsField.setLength(self.type.length) if not self.type.precision == 0: qgsField.setPrecision(self.type.precision) return qgsField
def _add_id_column(layer): """Add an ID column if it's not present in the attribute table. :param layer: The vector layer. :type layer: QgsVectorLayer """ layer_purpose = layer.keywords['layer_purpose'] mapping = { layer_purpose_exposure['key']: exposure_id_field, layer_purpose_hazard['key']: hazard_id_field, layer_purpose_aggregation['key']: aggregation_id_field } has_id_column = False for layer_type, field in mapping.iteritems(): if layer_purpose == layer_type: safe_id = field if layer.keywords.get(field['key']): has_id_column = True break if not has_id_column: LOGGER.info( 'We add an ID column in {purpose}'.format(purpose=layer_purpose)) layer.startEditing() id_field = QgsField() id_field.setName(safe_id['field_name']) if isinstance(safe_id['type'], list): # Use the first element in the list of type id_field.setType(safe_id['type'][0]) else: id_field.setType(safe_id['type'][0]) id_field.setPrecision(safe_id['precision']) id_field.setLength(safe_id['length']) layer.addAttribute(id_field) new_index = layer.fieldNameIndex(id_field.name()) for feature in layer.getFeatures(): layer.changeAttributeValue( feature.id(), new_index, feature.id()) layer.commitChanges() layer.keywords['inasafe_fields'][safe_id['key']] = ( safe_id['field_name'])
def _add_id_column(layer): """Add an ID column if it's not present in the attribute table. :param layer: The vector layer. :type layer: QgsVectorLayer """ layer_purpose = layer.keywords['layer_purpose'] mapping = { layer_purpose_exposure['key']: exposure_id_field, layer_purpose_hazard['key']: hazard_id_field, layer_purpose_aggregation['key']: aggregation_id_field } has_id_column = False for layer_type, field in mapping.iteritems(): if layer_purpose == layer_type: safe_id = field if layer.keywords['inasafe_fields'].get(field['key']): has_id_column = True break if not has_id_column: LOGGER.info( 'We add an ID column in {purpose}'.format(purpose=layer_purpose)) layer.startEditing() id_field = QgsField() id_field.setName(safe_id['field_name']) if isinstance(safe_id['type'], list): # Use the first element in the list of type id_field.setType(safe_id['type'][0]) else: id_field.setType(safe_id['type'][0]) id_field.setPrecision(safe_id['precision']) id_field.setLength(safe_id['length']) layer.addAttribute(id_field) new_index = layer.fieldNameIndex(id_field.name()) for feature in layer.getFeatures(): layer.changeAttributeValue( feature.id(), new_index, feature.id()) layer.commitChanges() layer.keywords['inasafe_fields'][safe_id['key']] = ( safe_id['field_name'])
def create_fields(self, layer, record): """Create the attributes for the gbif response table.""" layer.startEditing() id_field = QgsField() id_field.setName('id') id_field.setType(QVariant.Int) id_field.setPrecision(0) id_field.setLength(10) layer.addAttribute(id_field) # A dict to store the field offeset for each property field_lookups = [] for key in record.keys(): new_field = QgsField() new_field.setName(key) new_field.setType(QVariant.String) new_field.setLength(255) layer.addAttribute(new_field) field_lookups.append(key) layer.commitChanges() return field_lookups
def processAlgorithm(self, parameters, context, feedback): layer = self.parameterAsMeshLayer(parameters, self.INPUT_LAYER, context) levels, precision = self._parse_levels(parameters, context) datasets = parameters[self.INPUT_DATASETS] timestep = parameters[self.INPUT_TIMESTEP] fields_line = QgsFields() fields_line.append(QgsField("group", QVariant.String)) fields_line.append(QgsField("time", QVariant.Double)) valueField = QgsField("value", QVariant.Double) valueField.setPrecision(precision) fields_line.append(valueField) (sink_line, dest_id_line) = self.parameterAsSink(parameters, self.OUTPUT_LINE, context, fields_line, QgsWkbTypes.MultiLineString, layer.crs()) if sink_line is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT_LINE)) fields_poly = QgsFields() fields_poly.append(QgsField("group", QVariant.String)) fields_poly.append(QgsField("time", QVariant.Double)) minValueField = QgsField("min_value", QVariant.Double) minValueField.setPrecision(precision) fields_poly.append(minValueField) maxValueField = QgsField("max_value", QVariant.Double) maxValueField.setPrecision(precision) fields_poly.append(maxValueField) (sink_poly, dest_id_poly) = self.parameterAsSink(parameters, self.OUTPUT_POLY, context, fields_poly, QgsWkbTypes.MultiPolygon, layer.crs()) if sink_poly is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT_POLY)) total = 2 * len(datasets) * len(levels) runner = QgsMeshContours(layer) dp = layer.dataProvider() i = self._export_lines(levels, runner, dp, datasets, timestep, 1, total, sink_line, feedback) self._export_polys(levels, runner, dp, datasets, timestep, i, total, sink_poly, feedback) feedback.setProgress(100) return {self.OUTPUT_LINE: dest_id_line, self.OUTPUT_POLY: dest_id_poly}
def saveAutoField( self ): """ Do some validation and then call AutoFieldManager """ # Check layers if not self.tblLayers.selectedItems(): self.msg.show( QApplication.translate( "AutoFieldsDockWidgetPy", "[Warning] Please first select a layer." ), 'warning' ) return # Check expression expression = u'' if self.optXCoord.isChecked(): expression = u'$x' elif self.optYCoord.isChecked(): expression = u'$y' elif self.optLength.isChecked(): expression = u'$length' elif self.optPerimeter.isChecked(): expression = u'$perimeter' elif self.optArea.isChecked(): expression = u'$area' elif self.optDate.isChecked(): expression = u'now()' elif self.optCustomExpression.isChecked(): if self.expressionDlg: expression = self.expressionDlg.expression if not self.expressionDlg or not expression: self.msg.show( QApplication.translate( "AutoFieldsDockWidgetPy", "[Warning] Please first set a valid custom expression." ), 'warning' ) return else: # optSpatialValue pass # Check fields fieldName = '' if self.optNewField.isChecked(): if self.txtFieldName.text(): fieldName = self.txtFieldName.text().strip() newField = QgsField( fieldName, self.cboFieldType.itemData( self.cboFieldType.currentIndex(), Qt.UserRole) ) length = self.txtFieldLength.value() precision = self.txtFieldPrecision.value() # Ensure length and precision are valid values when dealing with Real numbers if self.fieldTypesDict[self.cboFieldType.currentIndex()] == 'Real': if precision > length: precision = length newField.setLength( length ) newField.setPrecision( precision ) for item in self.tblLayers.selectedItems(): if item.column() == 1: # It's the layer name item layer = QgsMapLayerRegistry.instance().mapLayer( item.data( Qt.UserRole ) ) if layer.fieldNameIndex( fieldName ) != -1: self.msg.show( QApplication.translate( "AutoFieldsDockWidgetPy", "[Error] The field " ) + fieldName + \ QApplication.translate( "AutoFieldsDockWidgetPy", " already exists in layer " ) + layer.name() + ". " + \ QApplication.translate( "AutoFieldsDockWidgetPy", " If you want to create an AutoField on it, you need to choose it from 'Existing Field' list." ), 'warning' ) else: res = layer.dataProvider().addAttributes( [ newField ] ) if res: layer.updateFields() # Check if fieldName is preserved by the provider after field creation. if layer.fieldNameIndex( fieldName ) == -1: self.msg.show( QApplication.translate( "AutoFieldsDockWidgetPy", "[Error] The field " ) + fieldName + \ QApplication.translate( "AutoFieldsDockWidgetPy", " was probably created with another name by the layer (" ) + \ layer.name() + \ QApplication.translate( "AutoFieldsDockWidgetPy", ") provider. " ) + \ QApplication.translate( "AutoFieldsDockWidgetPy", " If you want to create an AutoField on it, you need to choose it from 'Existing Field' list." ), 'warning' ) else: self.doSaveAutoField( layer, fieldName, expression ) else: self.msg.show( QApplication.translate( "AutoFieldsDockWidgetPy", "[Error] Couldn't create " ) + newField.name() + \ QApplication.translate( "AutoFieldsDockWidgetPy", " field in " ) + layer.name() + \ QApplication.translate( "AutoFieldsDockWidgetPy", " layer." ), 'warning' ) # Some fields might have been created, update the field list once self.updateFieldList() else: self.msg.show( QApplication.translate( "AutoFieldsDockWidgetPy", "[Warning] Please first set a name for the new field." ), 'warning' ) return else: fieldName = self.cboField.currentText() for item in self.tblLayers.selectedItems(): if item.column() == 1: # It's the layer name item layer = QgsMapLayerRegistry.instance().mapLayer( item.data( Qt.UserRole ) ) self.doSaveAutoField( layer, fieldName, expression )
def reclassify(layer, exposure_key=None): """Reclassify a continuous vector layer. This function will modify the input. For instance if you want to reclassify like this table : Original Value | Class - ∞ < val <= 0 | 1 0 < val <= 0.5 | 2 0.5 < val <= 5 | 3 5 < val < + ∞ | 6 You need a dictionary : ranges = OrderedDict() ranges[1] = [None, 0] ranges[2] = [0.0, 0.5] ranges[3] = [0.5, 5] ranges[6] = [5, None] :param layer: The raster layer. :type layer: QgsRasterLayer :param exposure_key: The exposure key. :type exposure_key: str :return: The classified vector layer. :rtype: QgsVectorLayer .. versionadded:: 4.0 """ output_layer_name = reclassify_vector_steps['output_layer_name'] output_layer_name = output_layer_name % layer.keywords['title'] # This layer should have this keyword, or it's a mistake from the dev. inasafe_fields = layer.keywords['inasafe_fields'] continuous_column = inasafe_fields[hazard_value_field['key']] if exposure_key: classification_key = active_classification( layer.keywords, exposure_key) thresholds = active_thresholds_value_maps(layer.keywords, exposure_key) layer.keywords['thresholds'] = thresholds layer.keywords['classification'] = classification_key else: classification_key = layer.keywords.get('classification') thresholds = layer.keywords.get('thresholds') if not thresholds: raise InvalidKeywordsForProcessingAlgorithm( 'thresholds are missing from the layer %s' % layer.keywords['layer_purpose']) continuous_index = layer.fields().lookupField(continuous_column) classified_field = QgsField() classified_field.setType(hazard_class_field['type']) classified_field.setName(hazard_class_field['field_name']) classified_field.setLength(hazard_class_field['length']) classified_field.setPrecision(hazard_class_field['precision']) layer.startEditing() layer.addAttribute(classified_field) classified_field_index = layer.fields(). \ lookupField(classified_field.name()) for feature in layer.getFeatures(): attributes = feature.attributes() source_value = attributes[continuous_index] classified_value = reclassify_value(source_value, thresholds) if (classified_value is None or (hasattr(classified_value, 'isNull') and classified_value.isNull())): layer.deleteFeature(feature.id()) else: layer.changeAttributeValue( feature.id(), classified_field_index, classified_value) layer.commitChanges() layer.updateFields() # We transfer keywords to the output. inasafe_fields[hazard_class_field['key']] = ( hazard_class_field['field_name']) value_map = {} hazard_classes = definition(classification_key)['classes'] for hazard_class in reversed(hazard_classes): value_map[hazard_class['key']] = [hazard_class['value']] layer.keywords['value_map'] = value_map layer.keywords['title'] = output_layer_name check_layer(layer) return layer
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) fieldName = self.parameterAsString(parameters, self.FIELD, context) useField = bool(fieldName) field_index = None f = QgsField('value', QVariant.String, '', 255) if useField: field_index = source.fields().lookupField(fieldName) fType = source.fields()[field_index].type() if fType in [ QVariant.Int, QVariant.UInt, QVariant.LongLong, QVariant.ULongLong ]: f.setType(fType) f.setLength(20) elif fType == QVariant.Double: f.setType(QVariant.Double) f.setLength(20) f.setPrecision(6) else: f.setType(QVariant.String) f.setLength(255) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 20)) fields.append(f) fields.append(QgsField('area', QVariant.Double, '', 20, 6)) fields.append(QgsField('perim', QVariant.Double, '', 20, 6)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Polygon, source.sourceCrs()) outFeat = QgsFeature() outGeom = QgsGeometry() fid = 0 val = None if useField: unique = source.uniqueValues(field_index) current = 0 total = 100.0 / (source.featureCount() * len(unique)) if source.featureCount() else 1 for i in unique: if feedback.isCanceled(): break first = True hull = [] features = source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes([field_index])) for f in features: if feedback.isCanceled(): break idVar = f.attributes()[field_index] if str(idVar).strip() == str(i).strip(): if first: val = idVar first = False inGeom = f.geometry() points = vector.extractPoints(inGeom) hull.extend(points) current += 1 feedback.setProgress(int(current * total)) if len(hull) >= 3: tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull)) try: outGeom = tmpGeom.convexHull() if outGeom: area = outGeom.geometry().area() perim = outGeom.geometry().perimeter() else: area = NULL perim = NULL outFeat.setGeometry(outGeom) outFeat.setAttributes([fid, val, area, perim]) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: raise QgsProcessingException( self.tr('Exception while computing convex hull')) fid += 1 else: hull = [] total = 100.0 / source.featureCount() if source.featureCount( ) else 1 features = source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes([])) for current, f in enumerate(features): if feedback.isCanceled(): break inGeom = f.geometry() points = vector.extractPoints(inGeom) hull.extend(points) feedback.setProgress(int(current * total)) tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull)) try: outGeom = tmpGeom.convexHull() if outGeom: area = outGeom.geometry().area() perim = outGeom.geometry().perimeter() else: area = NULL perim = NULL outFeat.setGeometry(outGeom) outFeat.setAttributes([0, 'all', area, perim]) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: raise QgsProcessingException( self.tr('Exception while computing convex hull')) return {self.OUTPUT: dest_id}
def reclassify(layer, exposure_key=None, callback=None): """Reclassify a continuous vector layer. This function will modify the input. For instance if you want to reclassify like this table : Original Value | Class - ∞ < val <= 0 | 1 0 < val <= 0.5 | 2 0.5 < val <= 5 | 3 5 < val < + ∞ | 6 You need a dictionary : ranges = OrderedDict() ranges[1] = [None, 0] ranges[2] = [0.0, 0.5] ranges[3] = [0.5, 5] ranges[6] = [5, None] :param layer: The raster layer. :type layer: QgsRasterLayer :param exposure_key: The exposure key. :type exposure_key: str :param callback: A function to all to indicate progress. The function should accept params 'current' (int), 'maximum' (int) and 'step' (str). Defaults to None. :type callback: function :return: The classified vector layer. :rtype: QgsVectorLayer .. versionadded:: 4.0 """ output_layer_name = reclassify_vector_steps['output_layer_name'] output_layer_name = output_layer_name % layer.keywords['title'] processing_step = reclassify_vector_steps['step_name'] # This layer should have this keyword, or it's a mistake from the dev. inasafe_fields = layer.keywords['inasafe_fields'] continuous_column = inasafe_fields[hazard_value_field['key']] if exposure_key: classification_key = active_classification(layer.keywords, exposure_key) thresholds = active_thresholds_value_maps(layer.keywords, exposure_key) layer.keywords['thresholds'] = thresholds layer.keywords['classification'] = classification_key else: classification_key = layer.keywords.get('classification') thresholds = layer.keywords.get('thresholds') if not thresholds: raise InvalidKeywordsForProcessingAlgorithm( 'thresholds are missing from the layer %s' % layer.keywords['layer_purpose']) continuous_index = layer.fieldNameIndex(continuous_column) classified_field = QgsField() classified_field.setType(hazard_class_field['type']) classified_field.setName(hazard_class_field['field_name']) classified_field.setLength(hazard_class_field['length']) classified_field.setPrecision(hazard_class_field['precision']) layer.startEditing() layer.addAttribute(classified_field) classified_field_index = layer.fieldNameIndex(classified_field.name()) for feature in layer.getFeatures(): attributes = feature.attributes() source_value = attributes[continuous_index] classified_value = _classified_value(source_value, thresholds) if not classified_value: layer.deleteFeature(feature.id()) else: layer.changeAttributeValue(feature.id(), classified_field_index, classified_value) layer.commitChanges() layer.updateFields() # We transfer keywords to the output. inasafe_fields[hazard_class_field['key']] = ( hazard_class_field['field_name']) value_map = {} hazard_classes = definition(classification_key)['classes'] for hazard_class in reversed(hazard_classes): value_map[hazard_class['key']] = [hazard_class['value']] layer.keywords['value_map'] = value_map layer.keywords['title'] = output_layer_name check_layer(layer) return layer
def on_btnRun_clicked(self): #Check for combo and list box selections if self.ui.cmbBaseLayer.count() < 1 or self.ui.cmbProcessLayer.count() < 1: QMessageBox.critical(self, 'Vector Geoprocessor', 'Invalid layer selection.') return if len(self.ui.listFields.selectedItems()) < 1: QMessageBox.critical(self, 'Vector Geoprocessor', 'Invalid field selection.') return #Initializations self.ui.ProgressBar.setValue(0) self.setCursor(Qt.WaitCursor) data = [] #Add new attributes to base layer bprovider = self.blayer.dataProvider() pprovider = self.player.dataProvider() pfields = pprovider.fields() for item in self.ui.listFields.selectedItems(): fname = item.text() for fld in pfields.toList(): if fname == fld.name(): newfield = QgsField() newfield.setName(fld.name()) newfield.setType(fld.type()) newfield.setTypeName(fld.typeName()) newfield.setLength(fld.length()) newfield.setPrecision(fld.precision()) newfield.setComment(fld.comment()) bprovider.addAttributes([newfield]) #Create a spatial index for faster processing spindex = QgsSpatialIndex() for pfeat in pprovider.getFeatures(): spindex.insertFeature(pfeat) #Find the intersection of process layer features with base layer #To increase speed, intersect with a bounding box rectangle first #Then further process within the geometric shape #Add requested processed information to base layer featreq = QgsFeatureRequest() bfields = bprovider.fields() ddic = {} len1 = len(self.ui.listFields.selectedItems()) len2 = len(bfields) b1 = 0 b2 = bprovider.featureCount() attr={} for bfeat in bprovider.getFeatures(): b1+=1 attr.clear() bgeom = bfeat.geometry() intersect = spindex.intersects(bgeom.boundingBox()) data[:] = [] for fid in intersect: pfeat = self.player.getFeatures(featreq.setFilterFid(fid)).next() if pfeat.geometry().intersects(bgeom) == False: data.append(fid) for fid in data: intersect.pop(intersect.index(fid)) count = 0 for item in self.ui.listFields.selectedItems(): pfindx = pprovider.fieldNameIndex(item.text()) if pfindx < 0: self.setCursor(Qt.ArrowCursor) QMessageBox.critical(self, 'Vector Geoprocessor', 'Processing error.') return data[:] = [] for fid in intersect: pfeat = self.player.getFeatures(featreq.setFilterFid(fid)).next() if self.oindex in [0,1,2,3,4]: data.append(float(pfeat.attribute(item.text()))) elif self.oindex in [5,6]: data.append(str(pfeat.attribute(item.text()))) if len(data) == 0: value = None elif self.oindex == 0: #Find mean value of points within polygons value = sum(data)/float(len(data)) elif self.oindex == 1: #Find median value of points within polygons data = sorted(data) lendata = len(data) if lendata % 2: value = data[(lendata+1)/2-1] else: d1 = data[lendata/2-1] d2 = data[lendata/2] value = (d1 + d2)/2.0 elif self.oindex == 2: #Find maximum value of points within polygons value = max(data) elif self.oindex == 3: #Find minimum value of points within polygons value = min(data) elif self.oindex == 4: #Find mean value (area-weighted) of polygons within polygons value = 0.0 totalarea = 0.0 for fid in intersect: pfeat = self.player.getFeatures(featreq.setFilterFid(fid)).next() pgeom = pfeat.geometry() isect = bgeom.intersection(pgeom) parea = isect.area() value+=(float(pfeat.attribute(item.text())*parea)) totalarea+=parea value = value / totalarea elif self.oindex == 5: #Find largest area polygon within polygons data = list(set(data)) #Get unique items in data ddic.clear() for i in data: ddic.update({i : 0.0}) for fid in intersect: pfeat = self.player.getFeatures(featreq.setFilterFid(fid)).next() pgeom = pfeat.geometry() isect = bgeom.intersection(pgeom) parea = isect.area() key = str(pfeat.attribute(item.text())) parea = parea + ddic[key] ddic.update({key : parea}) parea = -1 for key in ddic.keys(): if ddic[key] > parea: parea = ddic[key] value = key elif self.oindex == 6: #Add polygon attribute to points if len(data) != 1: QMessageBox.warning(self, 'Vector Geoprocessor', 'Point intersects more than one polygon.') value = data[0] attr.update({(len2-len1+count):value}) count+=1 result = bprovider.changeAttributeValues({bfeat.id():attr}) if not result: QMessageBox.critical(self, 'Vector Geoprocessor', 'Could not change attribute value.') return self.ui.ProgressBar.setValue(float(b1)/float(b2) * 100.0) QApplication.processEvents() self.setCursor(Qt.ArrowCursor)
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT)) useField = self.getParameterValue(self.METHOD) == 1 fieldName = self.getParameterValue(self.FIELD) f = QgsField("value", QVariant.String, "", 255) if useField: index = layer.fields().lookupField(fieldName) fType = layer.fields()[index].type() if fType in [QVariant.Int, QVariant.UInt, QVariant.LongLong, QVariant.ULongLong]: f.setType(fType) f.setLength(20) elif fType == QVariant.Double: f.setType(QVariant.Double) f.setLength(20) f.setPrecision(6) else: f.setType(QVariant.String) f.setLength(255) fields = [ QgsField("id", QVariant.Int, "", 20), f, QgsField("area", QVariant.Double, "", 20, 6), QgsField("perim", QVariant.Double, "", 20, 6), ] writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, QgsWkbTypes.Polygon, layer.crs()) outFeat = QgsFeature() inGeom = QgsGeometry() outGeom = QgsGeometry() fid = 0 val = None features = vector.features(layer) if useField: unique = layer.uniqueValues(index) current = 0 total = 100.0 / (len(features) * len(unique)) for i in unique: first = True hull = [] features = vector.features(layer) for f in features: idVar = f[fieldName] if str(idVar).strip() == str(i).strip(): if first: val = idVar first = False inGeom = f.geometry() points = vector.extractPoints(inGeom) hull.extend(points) current += 1 progress.setPercentage(int(current * total)) if len(hull) >= 3: tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull)) try: outGeom = tmpGeom.convexHull() (area, perim) = vector.simpleMeasure(outGeom) outFeat.setGeometry(outGeom) outFeat.setAttributes([fid, val, area, perim]) writer.addFeature(outFeat) except: raise GeoAlgorithmExecutionException(self.tr("Exception while computing convex hull")) fid += 1 else: hull = [] total = 100.0 / layer.featureCount() features = vector.features(layer) for current, f in enumerate(features): inGeom = f.geometry() points = vector.extractPoints(inGeom) hull.extend(points) progress.setPercentage(int(current * total)) tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull)) try: outGeom = tmpGeom.convexHull() (area, perim) = vector.simpleMeasure(outGeom) outFeat.setGeometry(outGeom) outFeat.setAttributes([0, "all", area, perim]) writer.addFeature(outFeat) except: raise GeoAlgorithmExecutionException(self.tr("Exception while computing convex hull")) del writer
def CheckControlFile(self): #Open control file if not os.path.exists(self.cfilename): QMessageBox.critical(self, 'Simulation Controller', 'Control file does not exist.') return 1 else: self.cfile = ControlFile.ControlFile() ret = self.cfile.ReadFile(self.cfilename) if ret: QMessageBox.critical(self, 'Simulation Controller', 'Error reading control file.') return 1 #Set working directory if not os.path.exists(self.cfile.ModelDirectory): QMessageBox.critical(self, 'Simulation Controller', 'Model directory does not exist.') return 1 else: os.chdir(self.cfile.ModelDirectory) #Get base layer count = 0 for i in self.layers: if i.name() == self.cfile.BaseLayer: self.blayer = i self.bprovider = self.blayer.dataProvider() count += 1 if not count: #Count==0 QMessageBox.critical(self, 'Simulation Controller', 'Base layer not found.') return 1 if count > 1: QMessageBox.critical( self, 'Simulation Controller', 'Found more than one layer with base layer name.') return 1 #Check template files for key in sorted(self.cfile.TemplateInput.keys()): if not os.path.exists(self.cfile.TemplateInput[key][0]): QMessageBox.critical( self, 'Simulation Controller', 'File does not exist: %s' % self.cfile.TemplateInput[key][0]) return 1 else: f = open(self.cfile.TemplateInput[key][0], 'r') lines = f.readlines() f.close() if lines[0][ 0:41] != 'Geospatial Simulation Template (GST) File': QMessageBox.critical(self, 'Simulation Controller', 'Check template file.') return 1 #Check for input attributes in base layer for key in sorted(self.cfile.AttributeCode.keys()): bfindx = self.bprovider.fieldNameIndex( self.cfile.AttributeCode[key][0]) if bfindx < 0: QMessageBox.critical( self, 'Simulation Controller', 'Missing attribute in base layer: %s' % self.cfile.AttributeCode[key][0]) return 1 #Check instruction files for key in sorted(self.cfile.InstructionOutput.keys()): if not os.path.exists(self.cfile.InstructionOutput[key][0]): QMessageBox.critical( self, 'Simulation Controller', 'File does not exist: %s' % self.cfile.InstructionOutput[key][0]) return 1 else: f = open(self.cfile.InstructionOutput[key][0], 'r') lines = f.readlines() f.close() if lines[0][ 0:44] != 'Geospatial Simulation Instruction (GSI) File': QMessageBox.critical(self, 'Simulation Controller', 'Check instruction file.') return 1 for line in lines[1:]: line = line.split(',') if len(line) < 2: continue found = 0 for key in sorted(self.cfile.AttributeType.keys()): if self.cfile.AttributeType[key][0] == line[0]: found = 1 break if not found: QMessageBox.critical( self, 'Simulation Controller', 'Check control file for missing output attribute: ' + line[0]) return 1 #Check for output attributes in base layer. Add if missing. for key in sorted(self.cfile.AttributeType.keys()): typename = self.cfile.AttributeType[key][1].split('(')[0] length = self.cfile.AttributeType[key][1].split('(')[1] bfindx = self.bprovider.fieldNameIndex( self.cfile.AttributeType[key][0]) if bfindx < 0: #Field not found, must add it newfield = QgsField() newfield.setName(self.cfile.AttributeType[key][0]) if typename in ['String', 'string', 'STRING']: newfield.setType(QVariant.String) newfield.setTypeName('String') newfield.setLength(int(length.split(')')[0])) elif typename in ['Integer', 'integer', 'INTEGER']: newfield.setType(QVariant.Int) newfield.setTypeName('Integer') newfield.setLength(int(length.split(')')[0])) elif typename in ['Real', 'real', 'REAL']: newfield.setType(QVariant.Double) newfield.setTypeName('Real') newfield.setLength(int(length.split('.')[0])) newfield.setPrecision( int(length.split('.')[1].split(')')[0])) self.bprovider.addAttributes([newfield]) #Enable Run button self.ui.btnRun.setEnabled(True) return 0
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT)) useField = self.getParameterValue(self.METHOD) == 1 fieldName = self.getParameterValue(self.FIELD) f = QgsField('value', QVariant.String, '', 255) if useField: index = layer.fields().lookupField(fieldName) fType = layer.fields()[index].type() if fType in [QVariant.Int, QVariant.UInt, QVariant.LongLong, QVariant.ULongLong]: f.setType(fType) f.setLength(20) elif fType == QVariant.Double: f.setType(QVariant.Double) f.setLength(20) f.setPrecision(6) else: f.setType(QVariant.String) f.setLength(255) fields = [QgsField('id', QVariant.Int, '', 20), f, QgsField('area', QVariant.Double, '', 20, 6), QgsField('perim', QVariant.Double, '', 20, 6) ] writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, QgsWkbTypes.Polygon, layer.crs()) outFeat = QgsFeature() inGeom = QgsGeometry() outGeom = QgsGeometry() fid = 0 val = None features = vector.features(layer) if useField: unique = layer.uniqueValues(index) current = 0 total = 100.0 / (len(features) * len(unique)) for i in unique: first = True hull = [] features = vector.features(layer) for f in features: idVar = f[fieldName] if str(idVar).strip() == str(i).strip(): if first: val = idVar first = False inGeom = f.geometry() points = vector.extractPoints(inGeom) hull.extend(points) current += 1 progress.setPercentage(int(current * total)) if len(hull) >= 3: tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull)) try: outGeom = tmpGeom.convexHull() (area, perim) = vector.simpleMeasure(outGeom) outFeat.setGeometry(outGeom) outFeat.setAttributes([fid, val, area, perim]) writer.addFeature(outFeat) except: raise GeoAlgorithmExecutionException( self.tr('Exception while computing convex hull')) fid += 1 else: hull = [] total = 100.0 / layer.featureCount() features = vector.features(layer) for current, f in enumerate(features): inGeom = f.geometry() points = vector.extractPoints(inGeom) hull.extend(points) progress.setPercentage(int(current * total)) tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull)) try: outGeom = tmpGeom.convexHull() (area, perim) = vector.simpleMeasure(outGeom) outFeat.setGeometry(outGeom) outFeat.setAttributes([0, 'all', area, perim]) writer.addFeature(outFeat) except: raise GeoAlgorithmExecutionException( self.tr('Exception while computing convex hull')) del writer
def update_value_map(layer, exposure_key=None, callback=None): """Assign inasafe values according to definitions for a vector layer. :param layer: The vector layer. :type layer: QgsVectorLayer :param exposure_key: The exposure key. :type exposure_key: str :param callback: A function to all to indicate progress. The function should accept params 'current' (int), 'maximum' (int) and 'step' (str). Defaults to None. :type callback: function :return: The classified vector layer. :rtype: QgsVectorLayer .. versionadded:: 4.0 """ output_layer_name = assign_inasafe_values_steps['output_layer_name'] processing_step = assign_inasafe_values_steps['step_name'] output_layer_name = output_layer_name % layer.keywords['layer_purpose'] keywords = layer.keywords inasafe_fields = keywords['inasafe_fields'] classification = None if keywords['layer_purpose'] == layer_purpose_hazard['key']: if not inasafe_fields.get(hazard_value_field['key']): raise InvalidKeywordsForProcessingAlgorithm old_field = hazard_value_field new_field = hazard_class_field classification = active_classification(layer.keywords, exposure_key) elif keywords['layer_purpose'] == layer_purpose_exposure['key']: if not inasafe_fields.get(exposure_type_field['key']): raise InvalidKeywordsForProcessingAlgorithm old_field = exposure_type_field new_field = exposure_class_field else: raise InvalidKeywordsForProcessingAlgorithm # It's a hazard layer if exposure_key: if not active_thresholds_value_maps(keywords, exposure_key): raise InvalidKeywordsForProcessingAlgorithm value_map = active_thresholds_value_maps(keywords, exposure_key) # It's exposure layer else: if not keywords.get('value_map'): raise InvalidKeywordsForProcessingAlgorithm value_map = keywords.get('value_map') unclassified_column = inasafe_fields[old_field['key']] unclassified_index = layer.fieldNameIndex(unclassified_column) reversed_value_map = {} for inasafe_class, values in value_map.iteritems(): for val in values: reversed_value_map[val] = inasafe_class classified_field = QgsField() classified_field.setType(new_field['type']) classified_field.setName(new_field['field_name']) classified_field.setLength(new_field['length']) classified_field.setPrecision(new_field['precision']) layer.startEditing() layer.addAttribute(classified_field) classified_field_index = layer.fieldNameIndex(classified_field.name()) for feature in layer.getFeatures(): attributes = feature.attributes() source_value = attributes[unclassified_index] classified_value = reversed_value_map.get(source_value) if not classified_value: classified_value = '' layer.changeAttributeValue( feature.id(), classified_field_index, classified_value) layer.commitChanges() remove_fields(layer, [unclassified_column]) # We transfer keywords to the output. # We add new class field inasafe_fields[new_field['key']] = new_field['field_name'] # and we remove hazard value field inasafe_fields.pop(old_field['key']) layer.keywords = keywords layer.keywords['inasafe_fields'] = inasafe_fields if exposure_key: value_map_key = 'value_maps' else: value_map_key = 'value_map' if value_map_key in layer.keywords.keys(): layer.keywords.pop(value_map_key) layer.keywords['title'] = output_layer_name if classification: layer.keywords['classification'] = classification check_layer(layer) return layer
def processAlgorithm(self, parameters, context, feedback): layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context) useField = self.getParameterValue(self.METHOD) == 1 fieldName = self.getParameterValue(self.FIELD) f = QgsField('value', QVariant.String, '', 255) if useField: index = layer.fields().lookupField(fieldName) fType = layer.fields()[index].type() if fType in [QVariant.Int, QVariant.UInt, QVariant.LongLong, QVariant.ULongLong]: f.setType(fType) f.setLength(20) elif fType == QVariant.Double: f.setType(QVariant.Double) f.setLength(20) f.setPrecision(6) else: f.setType(QVariant.String) f.setLength(255) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 20)) fields.append(f) fields.append(QgsField('area', QVariant.Double, '', 20, 6)) fields.append(QgsField('perim', QVariant.Double, '', 20, 6)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, QgsWkbTypes.Polygon, layer.crs(), context) outFeat = QgsFeature() inGeom = QgsGeometry() outGeom = QgsGeometry() fid = 0 val = None features = QgsProcessingUtils.getFeatures(layer, context) if useField: unique = layer.uniqueValues(index) current = 0 total = 100.0 / (layer.featureCount() * len(unique)) if layer.featureCount() else 1 for i in unique: first = True hull = [] features = QgsProcessingUtils.getFeatures(layer, context) for f in features: idVar = f[fieldName] if str(idVar).strip() == str(i).strip(): if first: val = idVar first = False inGeom = f.geometry() points = vector.extractPoints(inGeom) hull.extend(points) current += 1 feedback.setProgress(int(current * total)) if len(hull) >= 3: tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull)) try: outGeom = tmpGeom.convexHull() (area, perim) = vector.simpleMeasure(outGeom) outFeat.setGeometry(outGeom) outFeat.setAttributes([fid, val, area, perim]) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) except: raise GeoAlgorithmExecutionException( self.tr('Exception while computing convex hull')) fid += 1 else: hull = [] total = 100.0 / layer.featureCount() if layer.featureCount() else 1 features = QgsProcessingUtils.getFeatures(layer, context) for current, f in enumerate(features): inGeom = f.geometry() points = vector.extractPoints(inGeom) hull.extend(points) feedback.setProgress(int(current * total)) tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull)) try: outGeom = tmpGeom.convexHull() (area, perim) = vector.simpleMeasure(outGeom) outFeat.setGeometry(outGeom) outFeat.setAttributes([0, 'all', area, perim]) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) except: raise GeoAlgorithmExecutionException( self.tr('Exception while computing convex hull')) del writer
def on_btnRun_clicked(self): #Check for combo and list box selections if self.ui.cmbBaseLayer.count() < 1 or self.ui.cmbProcessLayer.count( ) < 1: QMessageBox.critical(self, 'Vector Geoprocessor', 'Invalid layer selection.') return if len(self.ui.listFields.selectedItems()) < 1: QMessageBox.critical(self, 'Vector Geoprocessor', 'Invalid field selection.') return #Initializations self.ui.ProgressBar.setValue(0) self.setCursor(Qt.WaitCursor) data = [] #Add new attributes to base layer bprovider = self.blayer.dataProvider() pprovider = self.player.dataProvider() pfields = pprovider.fields() for item in self.ui.listFields.selectedItems(): fname = item.text() for fld in pfields.toList(): if fname == fld.name(): newfield = QgsField() newfield.setName(fld.name()) newfield.setType(fld.type()) newfield.setTypeName(fld.typeName()) newfield.setLength(fld.length()) newfield.setPrecision(fld.precision()) newfield.setComment(fld.comment()) bprovider.addAttributes([newfield]) #Create a spatial index for faster processing spindex = QgsSpatialIndex() for pfeat in pprovider.getFeatures(): spindex.insertFeature(pfeat) #Find the intersection of process layer features with base layer #To increase speed, intersect with a bounding box rectangle first #Then further process within the geometric shape #Add requested processed information to base layer featreq = QgsFeatureRequest() bfields = bprovider.fields() ddic = {} len1 = len(self.ui.listFields.selectedItems()) len2 = len(bfields) b1 = 0 b2 = bprovider.featureCount() attr = {} for bfeat in bprovider.getFeatures(): b1 += 1 attr.clear() bgeom = bfeat.geometry() intersect = spindex.intersects(bgeom.boundingBox()) data[:] = [] for fid in intersect: pfeat = next(self.player.getFeatures( featreq.setFilterFid(fid))) if pfeat.geometry().intersects(bgeom) == False: data.append(fid) for fid in data: intersect.pop(intersect.index(fid)) count = 0 for item in self.ui.listFields.selectedItems(): pfindx = pprovider.fieldNameIndex(item.text()) if pfindx < 0: self.setCursor(Qt.ArrowCursor) QMessageBox.critical(self, 'Vector Geoprocessor', 'Processing error.') return data[:] = [] for fid in intersect: pfeat = next( self.player.getFeatures(featreq.setFilterFid(fid))) if self.oindex in [0, 1, 2, 3, 4]: data.append(float(pfeat.attribute(item.text()))) elif self.oindex in [5, 6]: data.append(str(pfeat.attribute(item.text()))) if len(data) == 0: value = None elif self.oindex == 0: #Find mean value of points within polygons value = sum(data) / float(len(data)) elif self.oindex == 1: #Find median value of points within polygons data = sorted(data) lendata = len(data) if lendata % 2: value = data[(lendata + 1) / 2 - 1] else: d1 = data[lendata / 2 - 1] d2 = data[lendata / 2] value = (d1 + d2) / 2.0 elif self.oindex == 2: #Find maximum value of points within polygons value = max(data) elif self.oindex == 3: #Find minimum value of points within polygons value = min(data) elif self.oindex == 4: #Find mean value (area-weighted) of polygons within polygons value = 0.0 totalarea = 0.0 for fid in intersect: pfeat = next( self.player.getFeatures(featreq.setFilterFid(fid))) pgeom = pfeat.geometry() isect = bgeom.intersection(pgeom) parea = isect.area() value += (float(pfeat.attribute(item.text()) * parea)) totalarea += parea value = value / totalarea elif self.oindex == 5: #Find largest area polygon within polygons data = list(set(data)) #Get unique items in data ddic.clear() for i in data: ddic.update({i: 0.0}) for fid in intersect: pfeat = next( self.player.getFeatures(featreq.setFilterFid(fid))) pgeom = pfeat.geometry() isect = bgeom.intersection(pgeom) parea = isect.area() key = str(pfeat.attribute(item.text())) parea = parea + ddic[key] ddic.update({key: parea}) parea = -1 for key in list(ddic.keys()): if ddic[key] > parea: parea = ddic[key] value = key elif self.oindex == 6: #Add polygon attribute to points if len(data) != 1: QMessageBox.warning( self, 'Vector Geoprocessor', 'Point intersects more than one polygon.') value = data[0] attr.update({(len2 - len1 + count): value}) count += 1 result = bprovider.changeAttributeValues({bfeat.id(): attr}) if not result: QMessageBox.critical(self, 'Vector Geoprocessor', 'Could not change attribute value.') return self.ui.ProgressBar.setValue(float(b1) / float(b2) * 100.0) QApplication.processEvents() self.setCursor(Qt.ArrowCursor)
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ # 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. source = self.parameterAsSource( parameters, self.INPUT, context ) # 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 source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) fields_to_transform = self.parameterAsFields( parameters, self.FIELDS_TO_TRANSFORM, context) source_fields = source.fields() if not fields_to_transform: # no fields selected, use all numeric ones fields_to_transform = [source_fields.at(i).name() for i in range(len(source_fields)) if source_fields.at(i).isNumeric()] self.transformed_fields = QgsFields() transformation_name = self.name() fields_to_transform_idxs = [] for f in fields_to_transform: idx = source.fields().lookupField(f) if idx >= 0: fields_to_transform_idxs.append(idx) field_to_transform = source.fields().at(idx) if field_to_transform.isNumeric(): transformed_field = QgsField(field_to_transform) transformed_field.setName( "%s_%s" % (field_to_transform.name(), transformation_name)) transformed_field.setType(QVariant.Double) transformed_field.setLength(20) transformed_field.setPrecision(6) self.transformed_fields.append(transformed_field) out_fields = QgsProcessingUtils.combineFields( source_fields, self.transformed_fields) (sink, self.dest_id) = self.parameterAsSink( parameters, self.OUTPUT, context, out_fields, source.wkbType(), source.sourceCrs() ) # Send some information to the user feedback.pushInfo('CRS is {}'.format(source.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)) total = 100.0 / len(fields_to_transform) transformed_values = {} for current, fieldname_to_transform in enumerate(fields_to_transform): original_values = vector.values( source, fieldname_to_transform)[fieldname_to_transform] transformed_values[fieldname_to_transform] = self.transform_values( original_values, parameters, context) feedback.setProgress(int(current * total)) feedback.setProgress(0) # Compute the number of steps to display within the progress bar and # get features from source total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, source_feature in enumerate(source.getFeatures()): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): break sink_feature = QgsFeature(out_fields) # copy original fields for field in source.fields(): sink_feature[field.name()] = source_feature[field.name()] for original_fieldname, transformed_field in zip( fields_to_transform, self.transformed_fields): sink_feature[transformed_field.name()] = \ transformed_values[original_fieldname][current] sink_feature.setGeometry(source_feature.geometry()) # Add a feature in the sink sink.addFeature(sink_feature, QgsFeatureSink.FastInsert) # Update the progress bar feedback.setProgress(int(current * total)) # 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: self.dest_id}
def addResultToLayer(self, newOutputLayer): ''' prepare results to be integrated in gis context ''' try: # start editing newOutputLayer.startEditing() # read the out file and for each line update relative record in the result with open(self.algOutputFileName, 'r') as algOutputFile: # read all lines managedHeader = False fieldNameIndexMap = {} fieldNames = None for line in algOutputFile: line = line.strip() # manage header if not managedHeader: managedHeader = True # add columns to the output layer fieldNames = line.split('\t') fieldNames = [x.split('(')[0] for x in fieldNames] for fieldName in fieldNames: # check if field is already available if newOutputLayer.fieldNameIndex(fieldName) >= 0: continue # add the new field newField = QgsField(fieldName, QtCore.QVariant.Double) newField.setLength(7) newField.setPrecision(5) added = newOutputLayer.addAttribute(newField) if not added: raise Exception( self. tr('Can not add fieldname {} to the output vector' .format(fieldName))) newOutputLayer.updateFields() # add the fieldName in fieldNames for fieldName in fieldNames: fieldNameIndexMap[ fieldName] = newOutputLayer.fieldNameIndex( fieldName) # jump to the next line = values continue # map values with fieldnames values = line.split('\t') fieldValueMap = zip(fieldNames, values) # update record id = None for columnIndex, (fieldName, fieldValue) in enumerate(fieldValueMap): if columnIndex == 0: id = int(fieldValue) continue fieldValue = float(fieldValue) newOutputLayer.changeAttributeValue( id - 1, fieldNameIndexMap[fieldName], fieldValue) except Exception as ex: # rollback newOutputLayer.rollBack() traceback.print_exc() QgsMessageLog.logMessage(str(ex), 'QTraffic', QgsMessageLog.CRITICAL) iface.messageBar().pushCritical( 'QTraffic', self.tr("Error formatting alg result in the output layer")) else: if not newOutputLayer.commitChanges(): raise Exception( self.tr('Error committing changes in the result layer'))
def saveAutoField(self): """ Do some validation and then call AutoFieldManager """ # Check layers if not self.tblLayers.selectedItems(): self.msg.show( QApplication.translate( "AutoFieldsDockWidgetPy", "[Warning] Please first select a layer."), 'warning') return # Check expression expression = u'' if self.optXCoord.isChecked(): expression = u'$x' elif self.optYCoord.isChecked(): expression = u'$y' elif self.optLength.isChecked(): expression = u'$length' elif self.optPerimeter.isChecked(): expression = u'$perimeter' elif self.optArea.isChecked(): expression = u'$area' elif self.optDate.isChecked(): expression = u'now()' elif self.optCustomExpression.isChecked(): if self.expressionDlg: expression = self.expressionDlg.expression if not self.expressionDlg or not expression: self.msg.show( QApplication.translate( "AutoFieldsDockWidgetPy", "[Warning] Please first set a valid custom expression." ), 'warning') return else: # optSpatialValue pass # Check fields fieldName = '' if self.optNewField.isChecked(): if self.txtFieldName.text(): fieldName = self.txtFieldName.text().strip() newField = QgsField( fieldName, self.cboFieldType.itemData( self.cboFieldType.currentIndex(), Qt.UserRole)) length = self.txtFieldLength.value() precision = self.txtFieldPrecision.value() # Ensure length and precision are valid values when dealing with Real numbers if self.fieldTypesDict[ self.cboFieldType.currentIndex()] == 'Real': if precision > length: precision = length newField.setLength(length) newField.setPrecision(precision) for item in self.tblLayers.selectedItems(): if item.column() == 1: # It's the layer name item layer = QgsMapLayerRegistry.instance().mapLayer( item.data(Qt.UserRole)) if layer.fieldNameIndex(fieldName) != -1: self.msg.show( QApplication.translate( "AutoFieldsDockWidgetPy", "[Error] The field " ) + fieldName + \ QApplication.translate( "AutoFieldsDockWidgetPy", " already exists in layer " ) + layer.name() + ". " + \ QApplication.translate( "AutoFieldsDockWidgetPy", " If you want to create an AutoField on it, you need to choose it from 'Existing Field' list." ), 'warning' ) else: res = layer.dataProvider().addAttributes( [newField]) if res: layer.updateFields() # Check if fieldName is preserved by the provider after field creation. if layer.fieldNameIndex(fieldName) == -1: self.msg.show( QApplication.translate( "AutoFieldsDockWidgetPy", "[Error] The field " ) + fieldName + \ QApplication.translate( "AutoFieldsDockWidgetPy", " was probably created with another name by the layer (" ) + \ layer.name() + \ QApplication.translate( "AutoFieldsDockWidgetPy", ") provider. " ) + \ QApplication.translate( "AutoFieldsDockWidgetPy", " If you want to create an AutoField on it, you need to choose it from 'Existing Field' list." ), 'warning' ) else: self.doSaveAutoField( layer, fieldName, expression) else: self.msg.show( QApplication.translate( "AutoFieldsDockWidgetPy", "[Error] Couldn't create " ) + newField.name() + \ QApplication.translate( "AutoFieldsDockWidgetPy", " field in " ) + layer.name() + \ QApplication.translate( "AutoFieldsDockWidgetPy", " layer." ), 'warning' ) # Some fields might have been created, update the field list once self.updateFieldList() else: self.msg.show( QApplication.translate( "AutoFieldsDockWidgetPy", "[Warning] Please first set a name for the new field." ), 'warning') return else: fieldName = self.cboField.currentText() for item in self.tblLayers.selectedItems(): if item.column() == 1: # It's the layer name item layer = QgsMapLayerRegistry.instance().mapLayer( item.data(Qt.UserRole)) self.doSaveAutoField(layer, fieldName, expression)
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT)) useField = self.getParameterValue(self.METHOD) == 1 fieldName = self.getParameterValue(self.FIELD) f = QgsField('value', QVariant.String, '', 255) if useField: index = layer.fieldNameIndex(fieldName) fType = layer.pendingFields()[index].type() if fType == QVariant.Int: f.setType(QVariant.Int) f.setLength(20) elif fType == QVariant.Double: f.setType(QVariant.Double) f.setLength(20) f.setPrecision(6) else: f.setType(QVariant.String) f.setLength(255) fields = [QgsField('id', QVariant.Int, '', 20), f, QgsField('area', QVariant.Double, '', 20, 6), QgsField('perim', QVariant.Double, '', 20, 6) ] writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, QGis.WKBPolygon, layer.dataProvider().crs()) outFeat = QgsFeature() inGeom = QgsGeometry() outGeom = QgsGeometry() current = 0 fid = 0 val = None features = vector.features(layer) if useField: unique = layer.uniqueValues(index) total = 100.0 / (len(features) * len(unique)) for i in unique: first = True hull = [] features = vector.features(layer) for f in features: idVar = f[fieldName] if unicode(idVar).strip() == unicode(i).strip(): if first: val = idVar first = False inGeom = QgsGeometry(f.geometry()) points = vector.extractPoints(inGeom) hull.extend(points) current += 1 progress.setPercentage(int(current * total)) if len(hull) >= 3: tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull)) try: outGeom = tmpGeom.convexHull() (area, perim) = vector.simpleMeasure(outGeom) outFeat.setGeometry(outGeom) outFeat.setAttributes([fid, val, area, perim]) writer.addFeature(outFeat) except: raise GeoAlgorithmExecutionException( self.tr('Exception while computing convex hull')) fid += 1 else: hull = [] total = 100.0 / float(layer.featureCount()) features = vector.features(layer) for f in features: inGeom = QgsGeometry(f.geometry()) points = vector.extractPoints(inGeom) hull.extend(points) current += 1 progress.setPercentage(int(current * total)) tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull)) try: outGeom = tmpGeom.convexHull() (area, perim) = vector.simpleMeasure(outGeom) outFeat.setGeometry(outGeom) outFeat.setAttributes([0, 'all', area, perim]) writer.addFeature(outFeat) except: raise GeoAlgorithmExecutionException( self.tr('Exception while computing convex hull')) del writer
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) fieldName = self.parameterAsString(parameters, self.FIELD, context) useField = bool(fieldName) field_index = None f = QgsField('value', QVariant.String, '', 255) if useField: field_index = source.fields().lookupField(fieldName) fType = source.fields()[field_index].type() if fType in [QVariant.Int, QVariant.UInt, QVariant.LongLong, QVariant.ULongLong]: f.setType(fType) f.setLength(20) elif fType == QVariant.Double: f.setType(QVariant.Double) f.setLength(20) f.setPrecision(6) else: f.setType(QVariant.String) f.setLength(255) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 20)) fields.append(f) fields.append(QgsField('area', QVariant.Double, '', 20, 6)) fields.append(QgsField('perim', QVariant.Double, '', 20, 6)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Polygon, source.sourceCrs()) outFeat = QgsFeature() outGeom = QgsGeometry() fid = 0 val = None if useField: unique = source.uniqueValues(field_index) current = 0 total = 100.0 / (source.featureCount() * len(unique)) if source.featureCount() else 1 for i in unique: if feedback.isCanceled(): break first = True hull = [] features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([field_index])) for f in features: if feedback.isCanceled(): break idVar = f.attributes()[field_index] if str(idVar).strip() == str(i).strip(): if first: val = idVar first = False inGeom = f.geometry() points = vector.extractPoints(inGeom) hull.extend(points) current += 1 feedback.setProgress(int(current * total)) if len(hull) >= 3: tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull)) try: outGeom = tmpGeom.convexHull() if outGeom: area = outGeom.geometry().area() perim = outGeom.geometry().perimeter() else: area = NULL perim = NULL outFeat.setGeometry(outGeom) outFeat.setAttributes([fid, val, area, perim]) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: raise QgsProcessingException( self.tr('Exception while computing convex hull')) fid += 1 else: hull = [] total = 100.0 / source.featureCount() if source.featureCount() else 1 features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([])) for current, f in enumerate(features): if feedback.isCanceled(): break inGeom = f.geometry() points = vector.extractPoints(inGeom) hull.extend(points) feedback.setProgress(int(current * total)) tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull)) try: outGeom = tmpGeom.convexHull() if outGeom: area = outGeom.geometry().area() perim = outGeom.geometry().perimeter() else: area = NULL perim = NULL outFeat.setGeometry(outGeom) outFeat.setAttributes([0, 'all', area, perim]) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: raise QgsProcessingException( self.tr('Exception while computing convex hull')) return {self.OUTPUT: dest_id}
def update_value_map(layer, exposure_key=None): """Assign inasafe values according to definitions for a vector layer. :param layer: The vector layer. :type layer: QgsVectorLayer :param exposure_key: The exposure key. :type exposure_key: str :return: The classified vector layer. :rtype: QgsVectorLayer .. versionadded:: 4.0 """ output_layer_name = assign_inasafe_values_steps['output_layer_name'] output_layer_name = output_layer_name % layer.keywords['layer_purpose'] keywords = layer.keywords inasafe_fields = keywords['inasafe_fields'] classification = None if keywords['layer_purpose'] == layer_purpose_hazard['key']: if not inasafe_fields.get(hazard_value_field['key']): raise InvalidKeywordsForProcessingAlgorithm old_field = hazard_value_field new_field = hazard_class_field classification = active_classification(layer.keywords, exposure_key) elif keywords['layer_purpose'] == layer_purpose_exposure['key']: if not inasafe_fields.get(exposure_type_field['key']): raise InvalidKeywordsForProcessingAlgorithm old_field = exposure_type_field new_field = exposure_class_field else: raise InvalidKeywordsForProcessingAlgorithm # It's a hazard layer if exposure_key: if not active_thresholds_value_maps(keywords, exposure_key): raise InvalidKeywordsForProcessingAlgorithm value_map = active_thresholds_value_maps(keywords, exposure_key) # It's exposure layer else: if not keywords.get('value_map'): raise InvalidKeywordsForProcessingAlgorithm value_map = keywords.get('value_map') unclassified_column = inasafe_fields[old_field['key']] unclassified_index = layer.fields().lookupField(unclassified_column) reversed_value_map = {} for inasafe_class, values in list(value_map.items()): for val in values: reversed_value_map[val] = inasafe_class classified_field = QgsField() classified_field.setType(new_field['type']) classified_field.setName(new_field['field_name']) classified_field.setLength(new_field['length']) classified_field.setPrecision(new_field['precision']) layer.startEditing() layer.addAttribute(classified_field) classified_field_index = layer.fields(). \ lookupField(classified_field.name()) for feature in layer.getFeatures(): attributes = feature.attributes() source_value = attributes[unclassified_index] classified_value = reversed_value_map.get(source_value) if not classified_value: classified_value = '' layer.changeAttributeValue(feature.id(), classified_field_index, classified_value) layer.commitChanges() remove_fields(layer, [unclassified_column]) # We transfer keywords to the output. # We add new class field inasafe_fields[new_field['key']] = new_field['field_name'] # and we remove hazard value field inasafe_fields.pop(old_field['key']) layer.keywords = keywords layer.keywords['inasafe_fields'] = inasafe_fields if exposure_key: value_map_key = 'value_maps' else: value_map_key = 'value_map' if value_map_key in list(layer.keywords.keys()): layer.keywords.pop(value_map_key) layer.keywords['title'] = output_layer_name if classification: layer.keywords['classification'] = classification check_layer(layer) return layer
def addResultToLayer(self, newOutputLayer): ''' prepare results to be integrated in gis context ''' try: # start editing newOutputLayer.startEditing() # read the out file and for each line update relative record in the result with open(self.algOutputFileName, 'r') as algOutputFile: # read all lines managedHeader = False fieldNameIndexMap = {} fieldNames = None for line in algOutputFile: line = line.strip() # manage header if not managedHeader: managedHeader = True # add columns to the output layer fieldNames = line.split('\t') fieldNames = [x.split('(')[0] for x in fieldNames] for fieldName in fieldNames: # check if field is already available if newOutputLayer.fieldNameIndex(fieldName) >= 0: continue # add the new field newField = QgsField(fieldName, QtCore.QVariant.Double) newField.setLength(7) newField.setPrecision(5) added = newOutputLayer.addAttribute(newField) if not added: raise Exception(self.tr('Can not add fieldname {} to the output vector'.format(fieldName))) newOutputLayer.updateFields() # add the fieldName in fieldNames for fieldName in fieldNames: fieldNameIndexMap[ fieldName ] = newOutputLayer.fieldNameIndex(fieldName) # jump to the next line = values continue # map values with fieldnames values = line.split('\t') fieldValueMap = zip(fieldNames, values) # update record id = None for columnIndex, (fieldName, fieldValue) in enumerate(fieldValueMap): if columnIndex == 0: id = int(fieldValue) continue fieldValue = float(fieldValue) newOutputLayer.changeAttributeValue(id-1, fieldNameIndexMap[fieldName], fieldValue) except Exception as ex: # rollback newOutputLayer.rollBack() traceback.print_exc() QgsMessageLog.logMessage(str(ex), 'QTraffic', QgsMessageLog.CRITICAL) iface.messageBar().pushCritical('QTraffic', self.tr("Error formatting alg result in the output layer")) else: if not newOutputLayer.commitChanges(): raise Exception(self.tr('Error committing changes in the result layer'))