def addFieldKeepType(original, stat): """ Adds a field to the output, keeping the same data type as the original """ field = QgsField(original) field.setName(field.name() + '_' + stat) fields_to_join.append(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(name): """ Adds a field to the output, keeping the same data type as the value_field """ field = QgsField(value_field) field.setName(name) fields.append(field)
def copy_fields(layer, fields_to_copy): """Copy fields inside an attribute table. :param layer: The vector layer. :type layer: QgsVectorLayer :param fields_to_copy: Dictionary of fields to copy. :type fields_to_copy: dict """ for field in fields_to_copy: index = layer.fields().lookupField(field) if index != -1: layer.startEditing() source_field = layer.fields().at(index) new_field = QgsField(source_field) new_field.setName(fields_to_copy[field]) layer.addAttribute(new_field) new_index = layer.fields().lookupField(fields_to_copy[field]) for feature in layer.getFeatures(): attributes = feature.attributes() source_value = attributes[index] layer.changeAttributeValue( feature.id(), new_index, source_value) layer.commitChanges() layer.updateFields() # Avoid crash #4729
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 _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 processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) group_field_name = self.parameterAsString(parameters, self.GROUP_FIELD, context) order_field_name = self.parameterAsString(parameters, self.ORDER_FIELD, context) date_format = self.parameterAsString(parameters, self.DATE_FORMAT, context) text_dir = self.parameterAsString(parameters, self.OUTPUT_TEXT_DIR, context) group_field_index = source.fields().lookupField(group_field_name) order_field_index = source.fields().lookupField(order_field_name) if group_field_index >= 0: group_field_def = source.fields().at(group_field_index) else: group_field_def = None order_field_def = source.fields().at(order_field_index) fields = QgsFields() if group_field_def is not None: fields.append(group_field_def) begin_field = QgsField(order_field_def) begin_field.setName('begin') fields.append(begin_field) end_field = QgsField(order_field_def) end_field.setName('end') fields.append(end_field) output_wkb = QgsWkbTypes.LineString if QgsWkbTypes.hasM(source.wkbType()): output_wkb = QgsWkbTypes.addM(output_wkb) if QgsWkbTypes.hasZ(source.wkbType()): output_wkb = QgsWkbTypes.addZ(output_wkb) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, output_wkb, source.sourceCrs()) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) points = dict() features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([group_field_index, order_field_index]), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break if not f.hasGeometry(): continue point = f.geometry().constGet().clone() if group_field_index >= 0: group = f.attributes()[group_field_index] else: group = 1 order = f.attributes()[order_field_index] if date_format != '': order = datetime.strptime(str(order), date_format) if group in points: points[group].append((order, point)) else: points[group] = [(order, point)] feedback.setProgress(int(current * total)) feedback.setProgress(0) da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs(), context.transformContext()) da.setEllipsoid(context.project().ellipsoid()) current = 0 total = 100.0 / len(points) if points else 1 for group, vertices in list(points.items()): if feedback.isCanceled(): break vertices.sort(key=lambda x: (x[0] is None, x[0])) f = QgsFeature() attributes = [] if group_field_index >= 0: attributes.append(group) attributes.extend([vertices[0][0], vertices[-1][0]]) f.setAttributes(attributes) line = [node[1] for node in vertices] if text_dir: fileName = os.path.join(text_dir, '%s.txt' % group) with open(fileName, 'w') as fl: fl.write('angle=Azimuth\n') fl.write('heading=Coordinate_System\n') fl.write('dist_units=Default\n') for i in range(len(line)): if i == 0: fl.write('startAt=%f;%f;90\n' % (line[i].x(), line[i].y())) fl.write('survey=Polygonal\n') fl.write('[data]\n') else: angle = line[i - 1].azimuth(line[i]) distance = da.measureLine(QgsPointXY(line[i - 1]), QgsPointXY(line[i])) fl.write('%f;%f;90\n' % (angle, distance)) f.setGeometry(QgsGeometry(QgsLineString(line))) sink.addFeature(f, QgsFeatureSink.FastInsert) current += 1 feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
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 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 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, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) group_field_name = self.parameterAsString(parameters, self.GROUP_FIELD, context) order_field_name = self.parameterAsString(parameters, self.ORDER_FIELD, context) date_format = self.parameterAsString(parameters, self.DATE_FORMAT, context) text_dir = self.parameterAsString(parameters, self.OUTPUT_TEXT_DIR, context) group_field_index = source.fields().lookupField(group_field_name) order_field_index = source.fields().lookupField(order_field_name) if group_field_index >= 0: group_field_def = source.fields().at(group_field_index) else: group_field_def = None order_field_def = source.fields().at(order_field_index) fields = QgsFields() if group_field_def is not None: fields.append(group_field_def) begin_field = QgsField(order_field_def) begin_field.setName('begin') fields.append(begin_field) end_field = QgsField(order_field_def) end_field.setName('end') fields.append(end_field) output_wkb = QgsWkbTypes.LineString if QgsWkbTypes.hasM(source.wkbType()): output_wkb = QgsWkbTypes.addM(output_wkb) if QgsWkbTypes.hasZ(source.wkbType()): output_wkb = QgsWkbTypes.addZ(output_wkb) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, output_wkb, source.sourceCrs()) points = dict() features = source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes( [group_field_index, order_field_index])) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break if not f.hasGeometry(): continue point = f.geometry().constGet().clone() if group_field_index >= 0: group = f.attributes()[group_field_index] else: group = 1 order = f.attributes()[order_field_index] if date_format != '': order = datetime.strptime(str(order), date_format) if group in points: points[group].append((order, point)) else: points[group] = [(order, point)] feedback.setProgress(int(current * total)) feedback.setProgress(0) da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs(), context.transformContext()) da.setEllipsoid(context.project().ellipsoid()) current = 0 total = 100.0 / len(points) if points else 1 for group, vertices in list(points.items()): if feedback.isCanceled(): break vertices.sort() f = QgsFeature() attributes = [] if group_field_index >= 0: attributes.append(group) attributes.extend([vertices[0][0], vertices[-1][0]]) f.setAttributes(attributes) line = [node[1] for node in vertices] if text_dir: fileName = os.path.join(text_dir, '%s.txt' % group) with open(fileName, 'w') as fl: fl.write('angle=Azimuth\n') fl.write('heading=Coordinate_System\n') fl.write('dist_units=Default\n') for i in range(len(line)): if i == 0: fl.write('startAt=%f;%f;90\n' % (line[i].x(), line[i].y())) fl.write('survey=Polygonal\n') fl.write('[data]\n') else: angle = line[i - 1].azimuth(line[i]) distance = da.measureLine(QgsPointXY(line[i - 1]), QgsPointXY(line[i])) fl.write('%f;%f;90\n' % (angle, distance)) f.setGeometry(QgsGeometry(QgsLineString(line))) sink.addFeature(f, QgsFeatureSink.FastInsert) current += 1 feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
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 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 run(self): """Specific stuff at tool activating.""" cur_carhab_lyr = CarhabLayerRegistry.instance().getCurrentCarhabLayer() if not cur_carhab_lyr: no_carhab_lyr_msg() return csv_dir = QFileDialog.getExistingDirectory(None, "Select a folder:", None, QFileDialog.ShowDirsOnly) if csv_dir: now = time.strftime("%Y-%m-%d-%H%M%S") directory = os.path.join(csv_dir, cur_carhab_lyr.getName() + "_" + now) if not os.path.exists(directory): os.makedirs(directory) for tbl_name, desc in Config.DB_STRUCTURE: file_name = desc.get("std_name") tbl_fields = desc.get("fields") if file_name: if not desc.get("spatial"): csv_name = file_name if file_name.endswith(".csv") else file_name + ".csv" csv_path = os.path.join(directory, csv_name) field_names = [row[1].get("std_name") for row in tbl_fields if row[1].get("std_name")] db = DbManager(cur_carhab_lyr.dbPath) r = Recorder(db, tbl_name) tbl_rows = r.select_all() csv_rows = [] for tbl_row in tbl_rows: csv_row = {} for dbf, value in tbl_row.items(): for field in desc.get("fields"): if dbf == field[0] and field[1].get("std_name"): csv_row[encode(field[1].get("std_name"))] = encode(value) break csv_rows.append(csv_row) with open(csv_path, "wb") as csv_file: writer = csv.DictWriter(csv_file, field_names) writer.writeheader() writer.writerows(csv_rows) else: for vlyr in cur_carhab_lyr.getQgisLayers(): vlyr_tbl = QgsDataSourceURI(vlyr.dataProvider().dataSourceUri()).table() if tbl_name == vlyr_tbl: shp_name = file_name if file_name.endswith(".shp") else file_name + ".shp" shp_path = os.path.join(directory, shp_name) QgsVectorFileWriter.writeAsVectorFormat(vlyr, shp_path, "utf-8", None) shp_lyr = QgsVectorLayer(shp_path, "", "ogr") shapefile = shp_lyr.dataProvider() features = shapefile.getFeatures() attrs_to_del = [] for attr, attr_desc in tbl_fields: std_attr = attr_desc.get("std_name") if not std_attr == attr: if std_attr: cur_field = shapefile.fields().field(attr) new_field = QgsField(cur_field) new_field.setName(std_attr) shapefile.addAttributes([new_field]) for feat in features: idx = shapefile.fields().indexFromName(std_attr) update_map = {feat.id(): {idx: feat[attr]}} shapefile.changeAttributeValues(update_map) attrs_to_del.append(shapefile.fields().indexFromName(attr)) shapefile.deleteAttributes(attrs_to_del) popup("Export effectué")