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(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 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 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 test04_EditShapefile1(self): """Load a file, edit and overwrite. edits: add a field, set values to the field, and then remove the field""" self._testAvailable() or self.skipTest("Not available") fieldName = u'\u6587\u5b57\u52172' c0 = ord(u'\u30a2') infile = self.testDataPath(self.layerName) for ignore in [True, False]: setSettingValue("/qgis/ignoreShapeEncoding", ignore) # copy a set of shapefile layerName = u"{}_edit{}".format(self.layerName, 1 if ignore else 2) workfile = self.testDataPath(layerName, output=True) copyFileSet(infile, workfile, [".shp", ".shx", ".dbf", ".prj", ".cpg"]) # load the copy layer = self._testLayer(workfile + ".shp", output=True) # add a field layer.startEditing() f = QgsField(fieldName, QVariant.String, len=20) assert layer.addAttribute(f), "failed to add a field" fldIdx = layer.fieldNameIndex(fieldName) # set strings with Japanese characters to the field c = c0 for f in layer.getFeatures(): val = "".join([unichr(c + i) for i in range(5)]) assert layer.changeAttributeValue(f.id(), fldIdx, val), "failed to change attribute value" c += 5 # save and reload the shapefile assert layer.commitChanges(), "failed to commit changes" del layer layer = self._testLayer(workfile + ".shp", output=True) # check the values of the field c = c0 for f in layer.getFeatures(): val = "".join([unichr(c + i) for i in range(5)]) self.assertEqual(f.attribute(fieldName), val) c += 5 # remove the added field layer.startEditing() layer.deleteAttribute(fldIdx) assert layer.commitChanges(), "failed to commit changes" # compare the file set with source c = compareFileSet(infile, workfile, [".shp", ".shx", ".dbf", ".prj", ".cpg"]) self.assertEqual(c, [], "input and output do not match: {}".format(str(c))) print 'with "ignore..." option = {}...success'.format(ignore)
def getFields(): atts = [ { 'name': 'id_add', 'type': QVariant.Int }, { 'name': 'total_imgs', 'type':QVariant.Int }, { 'name': 'images', 'type': QVariant.String, 'len': 254 }, { 'name': 'user', 'type': QVariant.String, 'len': 20 }, { 'name': 'date_add', 'type': QVariant.String, 'len': 20 }, { 'name': 'crs_map', 'type': QVariant.String, 'len': 50 }, { 'name': 'extent_map', 'type': QVariant.String, 'len': 200 }, { 'name': 'annotation', 'type': QVariant.String, 'len': 100 } ] fields = QgsFields() for att in atts: f = QgsField( att['name'], att['type'] ) if 'len' in att: f.setLength( att['len']) fields.append( f ) return fields
def combineVectorFields(layerA, layerB): """Create single field map from two input field maps. """ fields = [] fieldsA = layerA.pendingFields() fields.extend(fieldsA) namesA = [unicode(f.name()).lower() for f in fieldsA] fieldsB = layerB.pendingFields() for field in fieldsB: name = unicode(field.name()).lower() if name in namesA: idx = 2 newName = name + '_' + unicode(idx) while newName in namesA: idx += 1 newName = name + '_' + unicode(idx) field = QgsField(newName, field.type(), field.typeName()) fields.append(field) return fields
def combineFields(fieldsA, fieldsB): """Create single field map from two input field maps. """ fields = [] fields.extend(fieldsA) namesA = [str(f.name()).lower() for f in fieldsA] for field in fieldsB: name = str(field.name()).lower() if name in namesA: idx = 2 newName = name + '_' + str(idx) while newName in namesA: idx += 1 newName = name + '_' + str(idx) field = QgsField(newName, field.type(), field.typeName()) fields.append(field) real_fields = QgsFields() for f in fields: real_fields.append(f) return real_fields
def testFieldTooltip(self): f = QgsField('my_string', QVariant.String, 'string') self.assertEqual(QgsFieldModel.fieldToolTip(f), '<b>my_string</b><p>string</p>') f.setAlias('my alias') self.assertEqual(QgsFieldModel.fieldToolTip(f), '<b>my alias</b> (my_string)<p>string</p>') f.setLength(20) self.assertEqual(QgsFieldModel.fieldToolTip(f), '<b>my alias</b> (my_string)<p>string (20)</p>') f = QgsField('my_real', QVariant.Double, 'real', 8, 3) self.assertEqual(QgsFieldModel.fieldToolTip(f), '<b>my_real</b><p>real (8, 3)</p>')
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 test_find_attribute_id(self): field_names = ['first', 'second'] field_one = QgsField(field_names[0], QVariant.String) field_one.setTypeName(STRING_FIELD_TYPE_NAME) field_two = QgsField(field_names[1], QVariant.Int) field_two.setTypeName(INT_FIELD_TYPE_NAME) attributes = [field_one, field_two] ProcessLayer(self.layer).add_attributes(attributes) added_field_names = [field.name() for field in self.dp.fields()] # Double-check that add_attributes is working properly assert added_field_names == field_names # Check that both attributes are correctly found for attr_name in field_names: try: ProcessLayer(self.layer).find_attribute_id(attr_name) except AttributeError: print "We would expect both attributes to be found!" raise # Check that an inexistent field doesn't get found and that the # AttributeError exception is correctly raised with self.assertRaises(AttributeError): ProcessLayer(self.layer).add_attributes('dummy')
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 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 processAlgorithm(self, context, feedback): layer = dataobjects.getLayerFromString( self.getParameterValue(self.VECTOR)) fieldName = self.getParameterValue(self.FIELD) minDistance = float(self.getParameterValue(self.MIN_DISTANCE)) strategy = self.getParameterValue(self.STRATEGY) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, QgsWkbTypes.Point, layer.crs(), context) da = QgsDistanceArea() features = QgsProcessingUtils.getFeatures(layer, context) for current, f in enumerate(features): fGeom = f.geometry() bbox = fGeom.boundingBox() if strategy == 0: pointCount = int(f[fieldName]) else: pointCount = int(round(f[fieldName] * da.measureArea(fGeom))) if pointCount == 0: feedback.pushInfo("Skip feature {} as number of points for it is 0.") continue index = QgsSpatialIndex() points = dict() nPoints = 0 nIterations = 0 maxIterations = pointCount * 200 total = 100.0 / pointCount random.seed() while nIterations < maxIterations and nPoints < pointCount: rx = bbox.xMinimum() + bbox.width() * random.random() ry = bbox.yMinimum() + bbox.height() * random.random() pnt = QgsPoint(rx, ry) geom = QgsGeometry.fromPoint(pnt) if geom.within(fGeom) and \ vector.checkMinDistance(pnt, index, minDistance, points): f = QgsFeature(nPoints) f.initAttributes(1) f.setFields(fields) f.setAttribute('id', nPoints) f.setGeometry(geom) writer.addFeature(f) index.insertFeature(f) points[nPoints] = pnt nPoints += 1 feedback.setProgress(int(nPoints * total)) nIterations += 1 if nPoints < pointCount: QgsMessageLog.logMessage(self.tr('Can not generate requested number of random ' 'points. Maximum number of attempts exceeded.'), self.tr('Processing'), QgsMessageLog.INFO) feedback.setProgress(0) del writer
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) layer = self.parameterAsVectorLayer(parameters, self.INPUT, context) field_name = self.parameterAsString(parameters, self.FIELD_NAME, context) field_type = self.TYPES[self.parameterAsEnum(parameters, self.FIELD_TYPE, context)] width = self.parameterAsInt(parameters, self.FIELD_LENGTH, context) precision = self.parameterAsInt(parameters, self.FIELD_PRECISION, context) new_field = self.parameterAsBool(parameters, self.NEW_FIELD, context) formula = self.parameterAsString(parameters, self.FORMULA, context) expression = QgsExpression(formula) da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs(), context.transformContext()) da.setEllipsoid(context.project().ellipsoid()) expression.setGeomCalculator(da) expression.setDistanceUnits(context.project().distanceUnits()) expression.setAreaUnits(context.project().areaUnits()) fields = source.fields() field_index = fields.lookupField(field_name) if new_field or field_index < 0: fields.append( QgsField(field_name, field_type, '', width, precision)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, source.wkbType(), source.sourceCrs()) exp_context = self.createExpressionContext(parameters, context) if layer is not None: exp_context.appendScope( QgsExpressionContextUtils.layerScope(layer)) expression.prepare(exp_context) features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break rownum = current + 1 exp_context.setFeature(f) exp_context.lastScope().setVariable("row_number", rownum) value = expression.evaluate(exp_context) if expression.hasEvalError(): feedback.reportError(expression.evalErrorString()) else: attrs = f.attributes() if new_field or field_index < 0: attrs.append(value) else: attrs[field_index] = value f.setAttributes(attrs) sink.addFeature(f, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def testModel(self): """Test the mapping model""" model = QgsFieldMappingModel(self.source_fields, self.destination_fields) self.assertEqual(model.rowCount(QModelIndex()), 3) self.assertIsNone(model.data(model.index(9999, 0), Qt.DisplayRole)) # We now have this default mapping: # source exp | destination fld # ------------------------------------------- # source_field2 | destination_field1 # source_field1 | destination_field2 # NOT SET (NULL) | destination_field3 self.assertEqual(model.data(model.index(0, 0), Qt.DisplayRole), '"source_field2"') self.assertEqual(model.data(model.index(0, 1), Qt.DisplayRole), 'destination_field1') self.assertEqual(model.data(model.index(0, 3), Qt.DisplayRole), 10) self.assertEqual(model.data(model.index(0, 4), Qt.DisplayRole), 8) self.assertEqual(model.data(model.index(1, 0), Qt.DisplayRole), '"source_field1"') self.assertEqual(model.data(model.index(1, 1), Qt.DisplayRole), 'destination_field2') self.assertEqual(model.data(model.index(2, 0), Qt.DisplayRole), QVariant()) self.assertEqual(model.data(model.index(2, 1), Qt.DisplayRole), 'destination_field3') # Test expression scope ctx = model.contextGenerator().createExpressionContext() self.assertTrue('source_field1' in ctx.fields().names()) # Test add fields model.appendField(QgsField('destination_field4', QVariant.String)) self.assertEqual(model.rowCount(QModelIndex()), 4) self.assertEqual(model.data(model.index(3, 1), Qt.DisplayRole), 'destination_field4') # Test remove field model.removeField(model.index(3, 0)) self.assertEqual(model.rowCount(QModelIndex()), 3) self.assertEqual(model.data(model.index(2, 1), Qt.DisplayRole), 'destination_field3') # Test edit fields mapping = model.mapping() self.assertEqual(mapping[0].field.name(), 'destination_field1') self.assertEqual(mapping[1].field.name(), 'destination_field2') self.assertEqual(mapping[2].field.name(), 'destination_field3') self.assertEqual(mapping[0].originalName, 'destination_field1') self.assertEqual(mapping[1].originalName, 'destination_field2') self.assertEqual(mapping[2].originalName, 'destination_field3') # Test move up or down self.assertFalse(model.moveUp(model.index(0, 0))) self.assertFalse(model.moveUp(model.index(100, 0))) self.assertFalse(model.moveDown(model.index(2, 0))) self.assertFalse(model.moveDown(model.index(100, 0))) self.assertTrue(model.moveDown(model.index(0, 0))) mapping = model.mapping() self.assertEqual(mapping[1].field.name(), 'destination_field1') self.assertEqual(mapping[0].field.name(), 'destination_field2') self.assertEqual(mapping[2].field.name(), 'destination_field3') self.assertEqual(mapping[1].originalName, 'destination_field1') self.assertEqual(mapping[0].originalName, 'destination_field2') self.assertEqual(mapping[2].originalName, 'destination_field3') self.assertTrue(model.moveUp(model.index(1, 0))) mapping = model.mapping() self.assertEqual(mapping[0].field.name(), 'destination_field1') self.assertEqual(mapping[1].field.name(), 'destination_field2') self.assertEqual(mapping[2].field.name(), 'destination_field3') self.assertEqual(mapping[0].originalName, 'destination_field1') self.assertEqual(mapping[1].originalName, 'destination_field2') self.assertEqual(mapping[2].originalName, 'destination_field3') self.assertTrue(model.moveUp(model.index(2, 0))) mapping = model.mapping() self.assertEqual(mapping[0].field.name(), 'destination_field1') self.assertEqual(mapping[2].field.name(), 'destination_field2') self.assertEqual(mapping[1].field.name(), 'destination_field3') self.assertEqual(mapping[0].originalName, 'destination_field1') self.assertEqual(mapping[2].originalName, 'destination_field2') self.assertEqual(mapping[1].originalName, 'destination_field3')
def calculate_svi( iface, current_layer, project_definition, indicators_operator=None, themes_operator=None, reuse_field=False ): """ add an SVI attribute to the current layer """ # set default if indicators_operator is None: indicators_operator = DEFAULT_COMBINATION if themes_operator is None: themes_operator = DEFAULT_COMBINATION themes = project_definition["children"][1]["children"] if reuse_field and "svi_field" in project_definition: svi_attr_name = project_definition["svi_field"] if DEBUG: print "Reusing %s" % svi_attr_name else: svi_attr_name = "SVI" svi_field = QgsField(svi_attr_name, QVariant.Double) svi_field.setTypeName(DOUBLE_FIELD_TYPE_NAME) attr_names = ProcessLayer(current_layer).add_attributes([svi_field]) svi_attr_name = attr_names[svi_attr_name] # get the id of the new attribute svi_attr_id = ProcessLayer(current_layer).find_attribute_id(svi_attr_name) discarded_feats_ids = [] try: with LayerEditingManager(current_layer, "Add SVI", DEBUG): for feat in current_layer.getFeatures(): # If a feature contains any NULL value, discard_feat will # be set to True and the corresponding SVI will be set to # NULL discard_feat = False feat_id = feat.id() # init svi_value to the correct value depending on # themes_operator if themes_operator in SUM_BASED_COMBINATIONS: svi_value = 0 elif themes_operator in MUL_BASED_COMBINATIONS: svi_value = 1 # iterate all themes of SVI for theme in themes: indicators = theme["children"] # init theme_result to the correct value depending on # indicators_operator if indicators_operator in SUM_BASED_COMBINATIONS: theme_result = 0 elif indicators_operator in MUL_BASED_COMBINATIONS: theme_result = 1 # iterate all indicators of a theme for indicator in indicators: if feat[indicator["field"]] == QPyNullVariant(float): discard_feat = True discarded_feats_ids.append(feat_id) break # For "Average (equal weights)" it's equivalent to use # equal weights, or to sum the indicators # (all weights 1) # and divide by the number of indicators (we use # the latter solution) if indicators_operator in ( "Sum (simple)", "Average (equal weights)", "Multiplication (simple)", ): indicator_weighted = feat[indicator["field"]] else: indicator_weighted = feat[indicator["field"]] * indicator["weight"] if indicators_operator in SUM_BASED_COMBINATIONS: theme_result += indicator_weighted elif indicators_operator in MUL_BASED_COMBINATIONS: theme_result *= indicator_weighted else: error_message = "invalid indicators_operator: %s" % indicators_operator raise RuntimeError(error_message) if discard_feat: break if indicators_operator == "Average (equal weights)": theme_result /= len(indicators) # combine the indicators of each theme # For "Average (equal weights)" it's equivalent to use # equal weights, or to sum the themes (all weights 1) # and divide by the number of themes (we use # the latter solution) if themes_operator in ("Sum (simple)", "Average (equal weights)", "Multiplication (simple)"): theme_weighted = theme_result else: theme_weighted = theme_result * theme["weight"] if themes_operator in SUM_BASED_COMBINATIONS: svi_value += theme_weighted elif themes_operator in MUL_BASED_COMBINATIONS: svi_value *= theme_weighted if discard_feat: svi_value = QPyNullVariant(float) else: if themes_operator == "Average (equal weights)": svi_value /= len(themes) current_layer.changeAttributeValue(feat_id, svi_attr_id, svi_value) msg = ( "The SVI has been calculated for fields containing " "non-NULL values and it was added to the layer as " "a new attribute called %s" ) % svi_attr_name iface.messageBar().pushMessage(tr("Info"), tr(msg), level=QgsMessageBar.INFO) if discarded_feats_ids: widget = toggle_select_features_widget( tr("Warning"), tr("Invalid indicators were found in some features while " "calculating SVI"), tr("Select invalid features"), current_layer, discarded_feats_ids, current_layer.selectedFeaturesIds(), ) iface.messageBar().pushWidget(widget, QgsMessageBar.WARNING) project_definition["indicators_operator"] = indicators_operator project_definition["themes_operator"] = themes_operator project_definition["svi_field"] = svi_attr_name return svi_attr_id, discarded_feats_ids except TypeError as e: current_layer.dataProvider().deleteAttributes([svi_attr_id]) msg = "Could not calculate SVI due to data problems: %s" % e iface.messageBar().pushMessage(tr("Error"), tr(msg), level=QgsMessageBar.CRITICAL)
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 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 doCheck(self, method, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT_LAYER, context) (valid_output_sink, valid_output_dest_id) = self.parameterAsSink(parameters, self.VALID_OUTPUT, context, source.fields(), source.wkbType(), source.sourceCrs()) valid_count = 0 invalid_fields = source.fields() invalid_fields.append( QgsField('_errors', QVariant.String, 'string', 255)) (invalid_output_sink, invalid_output_dest_id) = self.parameterAsSink( parameters, self.INVALID_OUTPUT, context, invalid_fields, source.wkbType(), source.sourceCrs()) invalid_count = 0 error_fields = QgsFields() error_fields.append(QgsField('message', QVariant.String, 'string', 255)) (error_output_sink, error_output_dest_id) = self.parameterAsSink( parameters, self.ERROR_OUTPUT, context, error_fields, QgsWkbTypes.Point, source.sourceCrs()) error_count = 0 features = source.getFeatures( QgsFeatureRequest(), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, inFeat in enumerate(features): if feedback.isCanceled(): break geom = inFeat.geometry() attrs = inFeat.attributes() valid = True if not geom.isNull() and not geom.isEmpty(): errors = list(geom.validateGeometry(method)) if errors: # QGIS method return a summary at the end if method == 1: errors.pop() valid = False reasons = [] for error in errors: errFeat = QgsFeature() error_geom = QgsGeometry.fromPointXY(error.where()) errFeat.setGeometry(error_geom) errFeat.setAttributes([error.what()]) if error_output_sink: error_output_sink.addFeature( errFeat, QgsFeatureSink.FastInsert) error_count += 1 reasons.append(error.what()) reason = "\n".join(reasons) if len(reason) > 255: reason = reason[:252] + '…' attrs.append(reason) outFeat = QgsFeature() outFeat.setGeometry(geom) outFeat.setAttributes(attrs) if valid: if valid_output_sink: valid_output_sink.addFeature(outFeat, QgsFeatureSink.FastInsert) valid_count += 1 else: if invalid_output_sink: invalid_output_sink.addFeature(outFeat, QgsFeatureSink.FastInsert) invalid_count += 1 feedback.setProgress(int(current * total)) results = { self.VALID_COUNT: valid_count, self.INVALID_COUNT: invalid_count, self.ERROR_COUNT: error_count } if valid_output_sink: results[self.VALID_OUTPUT] = valid_output_dest_id if invalid_output_sink: results[self.INVALID_OUTPUT] = invalid_output_dest_id if error_output_sink: results[self.ERROR_OUTPUT] = error_output_dest_id return results
def testCreateMemoryLayer(self): """ Test QgsMemoryProviderUtils.createMemoryLayer() """ # no fields layer = QgsMemoryProviderUtils.createMemoryLayer( 'my name', QgsFields()) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'my name') self.assertTrue(layer.fields().isEmpty()) # similar layers should have unique sources layer2 = QgsMemoryProviderUtils.createMemoryLayer( 'my name', QgsFields()) self.assertNotEqual(layer.source(), layer2.source()) # geometry type layer = QgsMemoryProviderUtils.createMemoryLayer( 'my name', QgsFields(), QgsWkbTypes.Point) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.Point) layer = QgsMemoryProviderUtils.createMemoryLayer( 'my name', QgsFields(), QgsWkbTypes.PolygonZM) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.PolygonZM) # crs layer = QgsMemoryProviderUtils.createMemoryLayer( 'my name', QgsFields(), QgsWkbTypes.PolygonZM, QgsCoordinateReferenceSystem.fromEpsgId(3111)) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.PolygonZM) self.assertTrue(layer.crs().isValid()) self.assertEqual(layer.crs().authid(), 'EPSG:3111') # fields fields = QgsFields() fields.append(QgsField("string", QVariant.String)) fields.append(QgsField("long", QVariant.LongLong)) fields.append(QgsField("double", QVariant.Double)) fields.append(QgsField("integer", QVariant.Int)) fields.append(QgsField("date", QVariant.Date)) fields.append(QgsField("datetime", QVariant.DateTime)) fields.append(QgsField("time", QVariant.Time)) layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields) self.assertTrue(layer.isValid()) self.assertFalse(layer.fields().isEmpty()) self.assertEqual(len(layer.fields()), len(fields)) for i in range(len(fields)): self.assertEqual(layer.fields()[i].name(), fields[i].name()) self.assertEqual(layer.fields()[i].type(), fields[i].type()) # unsupported field type fields = QgsFields() fields.append(QgsField("rect", QVariant.RectF)) layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields) self.assertTrue(layer.isValid()) self.assertFalse(layer.fields().isEmpty()) self.assertEqual(layer.fields()[0].name(), 'rect') self.assertEqual(layer.fields()[0].type(), QVariant.String) # should be mapped to string
def processAlgorithm(self, parameters, context, feedback): if parameters[self.INPUT] == parameters[self.HUBS]: raise QgsProcessingException( self.tr('Same layer given for both hubs and spokes')) point_source = self.parameterAsSource(parameters, self.INPUT, context) if point_source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) hub_source = self.parameterAsSource(parameters, self.HUBS, context) if hub_source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.HUBS)) fieldName = self.parameterAsString(parameters, self.FIELD, context) units = self.UNITS[self.parameterAsEnum(parameters, self.UNIT, context)] fields = point_source.fields() fields.append(QgsField('HubName', QVariant.String)) fields.append(QgsField('HubDist', QVariant.Double)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Point, point_source.sourceCrs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) index = QgsSpatialIndex( hub_source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes( []).setDestinationCrs(point_source.sourceCrs(), context.transformContext()))) distance = QgsDistanceArea() distance.setSourceCrs(point_source.sourceCrs(), context.transformContext()) distance.setEllipsoid(context.project().ellipsoid()) # Scan source points, find nearest hub, and write to output file features = point_source.getFeatures() total = 100.0 / point_source.featureCount( ) if point_source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break if not f.hasGeometry(): sink.addFeature(f, QgsFeatureSink.FastInsert) continue src = f.geometry().boundingBox().center() neighbors = index.nearestNeighbor(src, 1) ft = next( hub_source.getFeatures(QgsFeatureRequest().setFilterFid( neighbors[0]).setSubsetOfAttributes( [fieldName], hub_source.fields()).setDestinationCrs( point_source.sourceCrs(), context.transformContext()))) closest = ft.geometry().boundingBox().center() hubDist = distance.measureLine(src, closest) if units != self.LAYER_UNITS: hub_dist_in_desired_units = distance.convertLengthMeasurement( hubDist, units) else: hub_dist_in_desired_units = hubDist attributes = f.attributes() attributes.append(ft[fieldName]) attributes.append(hub_dist_in_desired_units) feat = QgsFeature() feat.setAttributes(attributes) feat.setGeometry(QgsGeometry.fromPointXY(src)) sink.addFeature(feat, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT_VECTOR, context) if source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT_VECTOR)) raster_layer = self.parameterAsRasterLayer(parameters, self.INPUT_RASTER, context) rasterPath = raster_layer.source() rasterDS = gdal.Open(rasterPath, gdal.GA_ReadOnly) geoTransform = rasterDS.GetGeoTransform() fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) fields.append(QgsField('poly_id', QVariant.Int, '', 10, 0)) fields.append(QgsField('point_id', QVariant.Int, '', 10, 0)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Point, raster_layer.crs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) outFeature = QgsFeature() outFeature.setFields(fields) fid = 0 polyId = 0 pointId = 0 features = source.getFeatures(QgsFeatureRequest().setDestinationCrs( raster_layer.crs(), context.transformContext())) 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 geom = f.geometry() bbox = geom.boundingBox() xMin = bbox.xMinimum() xMax = bbox.xMaximum() yMin = bbox.yMinimum() yMax = bbox.yMaximum() (startRow, startColumn) = raster.mapToPixel(xMin, yMax, geoTransform) (endRow, endColumn) = raster.mapToPixel(xMax, yMin, geoTransform) # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(geom.constGet()) engine.prepareGeometry() for row in range(startRow, endRow + 1): for col in range(startColumn, endColumn + 1): if feedback.isCanceled(): break (x, y) = raster.pixelToMap(row, col, geoTransform) point = QgsPoint(x, y) if engine.contains(point): outFeature.setGeometry(QgsGeometry(point)) outFeature['id'] = fid outFeature['poly_id'] = polyId outFeature['point_id'] = pointId fid += 1 pointId += 1 sink.addFeature(outFeature, QgsFeatureSink.FastInsert) pointId = 0 polyId += 1 feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) field_name = self.parameterAsString(parameters, self.FIELD, context) type = self.parameterAsEnum(parameters, self.TYPE, context) use_field = bool(field_name) field_index = -1 fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 20)) if use_field: # keep original field type, name and parameters field_index = source.fields().lookupField(field_name) if field_index >= 0: fields.append(source.fields()[field_index]) if type == 0: # envelope fields.append(QgsField('width', QVariant.Double, '', 20, 6)) fields.append(QgsField('height', QVariant.Double, '', 20, 6)) fields.append(QgsField('area', QVariant.Double, '', 20, 6)) fields.append(QgsField('perimeter', QVariant.Double, '', 20, 6)) elif type == 1: # oriented rect fields.append(QgsField('width', QVariant.Double, '', 20, 6)) fields.append(QgsField('height', QVariant.Double, '', 20, 6)) fields.append(QgsField('angle', QVariant.Double, '', 20, 6)) fields.append(QgsField('area', QVariant.Double, '', 20, 6)) fields.append(QgsField('perimeter', QVariant.Double, '', 20, 6)) elif type == 2: # circle fields.append(QgsField('radius', QVariant.Double, '', 20, 6)) fields.append(QgsField('area', QVariant.Double, '', 20, 6)) elif type == 3: # convex hull fields.append(QgsField('area', QVariant.Double, '', 20, 6)) fields.append(QgsField('perimeter', QVariant.Double, '', 20, 6)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Polygon, source.sourceCrs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) if field_index >= 0: geometry_dict = {} bounds_dict = {} total = 50.0 / source.featureCount() if source.featureCount( ) else 1 features = source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes([field_index])) for current, f in enumerate(features): if feedback.isCanceled(): break if not f.hasGeometry(): continue if type == 0: # bounding boxes - calculate on the fly for efficiency if not f.attributes()[field_index] in bounds_dict: bounds_dict[f.attributes()[field_index]] = f.geometry( ).boundingBox() else: bounds_dict[f.attributes() [field_index]].combineExtentWith( f.geometry().boundingBox()) else: if not f.attributes()[field_index] in geometry_dict: geometry_dict[f.attributes()[field_index]] = [ f.geometry() ] else: geometry_dict[f.attributes()[field_index]].append( f.geometry()) feedback.setProgress(int(current * total)) if type == 0: # bounding boxes current = 0 total = 50.0 / len(bounds_dict) if bounds_dict else 1 for group, rect in bounds_dict.items(): if feedback.isCanceled(): break # envelope feature = QgsFeature() feature.setGeometry(QgsGeometry.fromRect(rect)) feature.setAttributes([ current, group, rect.width(), rect.height(), rect.area(), rect.perimeter() ]) sink.addFeature(feature, QgsFeatureSink.FastInsert) geometry_dict[group] = None feedback.setProgress(50 + int(current * total)) current += 1 else: current = 0 total = 50.0 / len(geometry_dict) if geometry_dict else 1 for group, geometries in geometry_dict.items(): if feedback.isCanceled(): break feature = self.createFeature(feedback, current, type, geometries, group) sink.addFeature(feature, QgsFeatureSink.FastInsert) geometry_dict[group] = None feedback.setProgress(50 + int(current * total)) current += 1 else: total = 80.0 / source.featureCount() if source.featureCount( ) else 1 features = source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes([])) geometry_queue = [] bounds = QgsRectangle() for current, f in enumerate(features): if feedback.isCanceled(): break if not f.hasGeometry(): continue if type == 0: # bounding boxes, calculate on the fly for efficiency bounds.combineExtentWith(f.geometry().boundingBox()) else: geometry_queue.append(f.geometry()) feedback.setProgress(int(current * total)) if not feedback.isCanceled(): if type == 0: feature = QgsFeature() feature.setGeometry(QgsGeometry.fromRect(bounds)) feature.setAttributes([ 0, bounds.width(), bounds.height(), bounds.area(), bounds.perimeter() ]) else: feature = self.createFeature(feedback, 0, type, geometry_queue) sink.addFeature(feature, QgsFeatureSink.FastInsert) return {self.OUTPUT: dest_id}
def transform_attribute( self, input_attr_name, algorithm_name, variant="", inverse=False, new_attr_name=None, simulate=False): """ Use one of the available transformation algorithms to transform an attribute of the layer, and add a new attribute with the transformed data """ # get the id of the attribute named input_attr_name input_attr_id = self.find_attribute_id(input_attr_name) # build the name of the output transformed attribute # WARNING! Shape files support max 10 chars for attribute names if not new_attr_name: if variant: new_attr_name = algorithm_name[:5] + '_' + variant[:4] else: new_attr_name = algorithm_name[:10] else: new_attr_name = new_attr_name[:10] new_attr_name = new_attr_name.replace(' ', '_') field = QgsField(new_attr_name, QVariant.Double) field.setTypeName(DOUBLE_FIELD_TYPE_NAME) if simulate: attr_names_dict = self.add_attributes([field], simulate=simulate) # get the name actually assigned to the new attribute actual_new_attr_name = attr_names_dict[new_attr_name] return actual_new_attr_name # a dict will contain all the values for the chosen input attribute, # keeping as key, for each value, the id of the corresponding feature initial_dict = dict() for feat in self.layer.getFeatures(): initial_dict[feat.id()] = feat[input_attr_id] # get the transformation algorithm from the register algorithm = TRANSFORMATION_ALGS[algorithm_name] # transform the values in the dictionary with the chosen algorithm try: transformed_dict = transform( initial_dict, algorithm, variant, inverse) except ValueError: raise except NotImplementedError: raise attr_names_dict = self.add_attributes([field], simulate=simulate) # get the name actually assigned to the new attribute actual_new_attr_name = attr_names_dict[new_attr_name] # get the id of the new attribute new_attr_id = self.find_attribute_id(actual_new_attr_name) with LayerEditingManager( self.layer, 'Write transformed values', DEBUG): for feat in self.layer.getFeatures(): feat_id = feat.id() value = transformed_dict[feat_id] if type(value) not in (QPyNullVariant, NoneType): value = float(value) self.layer.changeAttributeValue(feat_id, new_attr_id, value) return actual_new_attr_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)) value_field_name = self.parameterAsString(parameters, self.VALUES_FIELD_NAME, context) category_field_names = self.parameterAsFields( parameters, self.CATEGORIES_FIELD_NAME, context) value_field_index = source.fields().lookupField(value_field_name) if value_field_index >= 0: value_field = source.fields().at(value_field_index) else: value_field = None category_field_indexes = [ source.fields().lookupField(n) for n in category_field_names ] # generate output fields fields = QgsFields() for c in category_field_indexes: fields.append(source.fields().at(c)) 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) if value_field is None: field_type = 'none' fields.append(QgsField('count', QVariant.Int)) elif value_field.isNumeric(): field_type = 'numeric' fields.append(QgsField('count', QVariant.Int)) fields.append(QgsField('unique', QVariant.Int)) fields.append(QgsField('min', QVariant.Double)) fields.append(QgsField('max', QVariant.Double)) fields.append(QgsField('range', QVariant.Double)) fields.append(QgsField('sum', QVariant.Double)) fields.append(QgsField('mean', QVariant.Double)) fields.append(QgsField('median', QVariant.Double)) fields.append(QgsField('stddev', QVariant.Double)) fields.append(QgsField('minority', QVariant.Double)) fields.append(QgsField('majority', QVariant.Double)) fields.append(QgsField('q1', QVariant.Double)) fields.append(QgsField('q3', QVariant.Double)) fields.append(QgsField('iqr', QVariant.Double)) elif value_field.type() in (QVariant.Date, QVariant.Time, QVariant.DateTime): field_type = 'datetime' fields.append(QgsField('count', QVariant.Int)) fields.append(QgsField('unique', QVariant.Int)) fields.append(QgsField('empty', QVariant.Int)) fields.append(QgsField('filled', QVariant.Int)) # keep same data type for these fields addField('min') addField('max') else: field_type = 'string' fields.append(QgsField('count', QVariant.Int)) fields.append(QgsField('unique', QVariant.Int)) fields.append(QgsField('empty', QVariant.Int)) fields.append(QgsField('filled', QVariant.Int)) # keep same data type for these fields addField('min') addField('max') fields.append(QgsField('min_length', QVariant.Int)) fields.append(QgsField('max_length', QVariant.Int)) fields.append(QgsField('mean_length', QVariant.Double)) request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry) if value_field is not None: attrs = [value_field_index] else: attrs = [] attrs.extend(category_field_indexes) request.setSubsetOfAttributes(attrs) features = source.getFeatures( request, QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks) total = 50.0 / source.featureCount() if source.featureCount() else 0 if field_type == 'none': values = defaultdict(lambda: 0) else: values = defaultdict(list) for current, feat in enumerate(features): if feedback.isCanceled(): break feedback.setProgress(int(current * total)) attrs = feat.attributes() cat = tuple([attrs[c] for c in category_field_indexes]) if field_type == 'none': values[cat] += 1 continue if field_type == 'numeric': if attrs[value_field_index] == NULL: continue else: value = float(attrs[value_field_index]) elif field_type == 'string': if attrs[value_field_index] == NULL: value = '' else: value = str(attrs[value_field_index]) elif attrs[value_field_index] == NULL: value = NULL else: value = attrs[value_field_index] values[cat].append(value) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) if field_type == 'none': self.saveCounts(values, sink, feedback) elif field_type == 'numeric': self.calcNumericStats(values, sink, feedback) elif field_type == 'datetime': self.calcDateTimeStats(values, sink, feedback) else: self.calcStringStats(values, sink, feedback) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT_VECTOR, context) if source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT_VECTOR)) raster_layer = self.parameterAsRasterLayer(parameters, self.INPUT_RASTER, context) rasterPath = raster_layer.source() rasterDS = gdal.Open(rasterPath, gdal.GA_ReadOnly) geoTransform = rasterDS.GetGeoTransform() rasterDS = None fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) fields.append(QgsField('line_id', QVariant.Int, '', 10, 0)) fields.append(QgsField('point_id', QVariant.Int, '', 10, 0)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Point, raster_layer.crs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) outFeature = QgsFeature() outFeature.setFields(fields) self.fid = 0 self.lineId = 0 self.pointId = 0 features = source.getFeatures(QgsFeatureRequest().setDestinationCrs( raster_layer.crs(), context.transformContext())) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break geom = f.geometry() if geom.isMultipart(): lines = geom.asMultiPolyline() for line in lines: for i in range(len(line) - 1): p1 = line[i] p2 = line[i + 1] (x1, y1) = raster.mapToPixel(p1.x(), p1.y(), geoTransform) (x2, y2) = raster.mapToPixel(p2.x(), p2.y(), geoTransform) self.buildLine(x1, y1, x2, y2, geoTransform, sink, outFeature) else: points = geom.asPolyline() for i in range(len(points) - 1): p1 = points[i] p2 = points[i + 1] (x1, y1) = raster.mapToPixel(p1.x(), p1.y(), geoTransform) (x2, y2) = raster.mapToPixel(p2.x(), p2.y(), geoTransform) self.buildLine(x1, y1, x2, y2, geoTransform, sink, outFeature) self.pointId = 0 self.lineId += 1 feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def testQgsFieldRepr(self): f = QgsField('field_name', QVariant.Double, 'double') self.assertEqual(f.__repr__(), "<QgsField: field_name (double)>")
def processAlgorithm(self, progress): polyLayer = dataobjects.getObjectFromUri( self.getParameterValue(self.POLYGONS)) pointLayer = dataobjects.getObjectFromUri( self.getParameterValue(self.POINTS)) fieldName = self.getParameterValue(self.FIELD) fieldIdx = pointLayer.fields().lookupField( self.getParameterValue(self.WEIGHT)) fields = polyLayer.fields() fields.append(QgsField(fieldName, QVariant.Int)) (idxCount, fieldList) = vector.findOrCreateField(polyLayer, polyLayer.fields(), fieldName) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields.toList(), polyLayer.wkbType(), polyLayer.crs()) spatialIndex = vector.spatialindex(pointLayer) ftPoint = QgsFeature() outFeat = QgsFeature() geom = QgsGeometry() features = vector.features(polyLayer) total = 100.0 / len(features) for current, ftPoly in enumerate(features): geom = ftPoly.geometry() engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() attrs = ftPoly.attributes() count = 0 points = spatialIndex.intersects(geom.boundingBox()) if len(points) > 0: progress.setText(str(len(points))) request = QgsFeatureRequest().setFilterFids( points).setSubsetOfAttributes([fieldIdx]) fit = pointLayer.getFeatures(request) ftPoint = QgsFeature() while fit.nextFeature(ftPoint): tmpGeom = QgsGeometry(ftPoint.geometry()) if engine.contains(tmpGeom.geometry()): weight = str(ftPoint.attributes()[fieldIdx]) try: count += float(weight) except: # Ignore fields with non-numeric values pass outFeat.setGeometry(geom) if idxCount == len(attrs): attrs.append(count) else: attrs[idxCount] = count outFeat.setAttributes(attrs) writer.addFeature(outFeat) progress.setPercentage(int(current * total)) del writer
def test_add_attributes(self): field_one = QgsField('first', QVariant.String) field_one.setTypeName(STRING_FIELD_TYPE_NAME) field_two = QgsField('second', QVariant.Int) field_two.setTypeName(INT_FIELD_TYPE_NAME) attributes = [field_one, field_two] added_attributes = ProcessLayer(self.layer).add_attributes(attributes) expected_dict = {'first': 'first', 'second': 'second'} assert added_attributes == expected_dict # Let's add 2 other fields with the same names of the previous ones # ==> Since the names are already taken, we expect to add fields with # the same names plus '_1' field_three = QgsField('first', QVariant.String) field_three.setTypeName(STRING_FIELD_TYPE_NAME) field_four = QgsField('second', QVariant.Int) field_four.setTypeName(INT_FIELD_TYPE_NAME) attributes = [field_three, field_four] added_attributes = ProcessLayer(self.layer).add_attributes(attributes) expected_dict = {'first': 'first_1', 'second': 'second_1'} assert added_attributes == expected_dict # Let's add 2 other fields with the same names of the previous ones # ==> Since the names are already taken, as well as the corresponding # '_1' versions, we expect to add fields with the same names plus '_2' field_five = QgsField('first', QVariant.String) field_five.setTypeName(STRING_FIELD_TYPE_NAME) field_six = QgsField('second', QVariant.Int) field_six.setTypeName(INT_FIELD_TYPE_NAME) attributes = [field_five, field_six] added_attributes = ProcessLayer(self.layer).add_attributes(attributes) expected_dict = {'first': 'first_2', 'second': 'second_2'} assert added_attributes == expected_dict
def makefield(name, type, length): field = QgsField(name, type) field.setLength(length) return field
def test1(self): d = QgsVirtualLayerDefinition() self.assertEqual(d.toString(), "") d.setFilePath("/file") self.assertEqual(d.toString(), "file:///file") self.assertEqual( QgsVirtualLayerDefinition.fromUrl(d.toUrl()).filePath(), "/file") self.assertEqual( QgsVirtualLayerDefinition.fromUrl(strToUrl( d.toString())).filePath(), "/file") d.setFilePath(os.path.join('C:/', 'file')) self.assertEqual(d.toString(), "file:///C:/file") # self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).filePath(), os.path.join('C:/', 'file')) d.setQuery("SELECT * FROM mytable") self.assertEqual( QgsVirtualLayerDefinition.fromUrl(d.toUrl()).query(), "SELECT * FROM mytable") self.assertEqual( QgsVirtualLayerDefinition.fromUrl(strToUrl(d.toString())).query(), "SELECT * FROM mytable") q = "SELECT * FROM tableéé /*:int*/" d.setQuery(q) self.assertEqual( QgsVirtualLayerDefinition.fromUrl(d.toUrl()).query(), q) self.assertEqual( QgsVirtualLayerDefinition.fromUrl(strToUrl(d.toString())).query(), q) s1 = "file://foo&bar=okié" d.addSource("name", s1, "provider", "utf8") self.assertEqual( QgsVirtualLayerDefinition.fromUrl( d.toUrl()).sourceLayers()[0].source(), s1) self.assertEqual( QgsVirtualLayerDefinition.fromUrl(strToUrl( d.toString())).sourceLayers()[0].source(), s1) n1 = "éé ok" d.addSource(n1, s1, "provider") self.assertEqual( QgsVirtualLayerDefinition.fromUrl( d.toUrl()).sourceLayers()[1].name(), n1) self.assertEqual( QgsVirtualLayerDefinition.fromUrl(strToUrl( d.toString())).sourceLayers()[1].name(), n1) d.addSource("ref1", "id0001") self.assertEqual( QgsVirtualLayerDefinition.fromUrl( d.toUrl()).sourceLayers()[2].reference(), "id0001") self.assertEqual( QgsVirtualLayerDefinition.fromUrl(strToUrl( d.toString())).sourceLayers()[2].reference(), "id0001") s = "dbname='C:\\tt' table=\"test\" (geometry) sql=" d.addSource("nn", s, "spatialite") self.assertEqual( QgsVirtualLayerDefinition.fromUrl( d.toUrl()).sourceLayers()[3].source(), s) self.assertEqual( QgsVirtualLayerDefinition.fromUrl(strToUrl( d.toString())).sourceLayers()[3].source(), s) d.setGeometryField("geom") self.assertEqual( QgsVirtualLayerDefinition.fromUrl(d.toUrl()).geometryField(), "geom") self.assertEqual( QgsVirtualLayerDefinition.fromUrl(strToUrl( d.toString())).geometryField(), "geom") d.setGeometryWkbType(QgsWkbTypes.Point) self.assertEqual( QgsVirtualLayerDefinition.fromUrl(d.toUrl()).geometryWkbType(), QgsWkbTypes.Point) self.assertEqual( QgsVirtualLayerDefinition.fromUrl(strToUrl( d.toString())).geometryWkbType(), QgsWkbTypes.Point) f = QgsFields() f.append(QgsField("a", QVariant.Int)) f.append(QgsField("f", QVariant.Double)) f.append(QgsField("s", QVariant.String)) d.setFields(f) f2 = QgsVirtualLayerDefinition.fromUrl(d.toUrl()).fields() self.assertEqual(f[0].name(), f2[0].name()) self.assertEqual(f[0].type(), f2[0].type()) self.assertEqual(f[1].name(), f2[1].name()) self.assertEqual(f[1].type(), f2[1].type()) self.assertEqual(f[2].name(), f2[2].name()) self.assertEqual(f[2].type(), f2[2].type())
def testUpdateMode(self): """ Test that on-the-fly re-opening in update/read-only mode works """ tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) srcpath = os.path.join(TEST_DATA_DIR, 'provider') for file in glob.glob(os.path.join(srcpath, 'shapefile.*')): shutil.copy(os.path.join(srcpath, file), tmpdir) datasource = os.path.join(tmpdir, 'shapefile.shp') vl = QgsVectorLayer(u'{}|layerid=0'.format(datasource), u'test', u'ogr') caps = vl.dataProvider().capabilities() self.assertTrue(caps & QgsVectorDataProvider.AddFeatures) self.assertTrue(caps & QgsVectorDataProvider.DeleteFeatures) self.assertTrue(caps & QgsVectorDataProvider.ChangeAttributeValues) self.assertTrue(caps & QgsVectorDataProvider.AddAttributes) self.assertTrue(caps & QgsVectorDataProvider.DeleteAttributes) self.assertTrue(caps & QgsVectorDataProvider.CreateSpatialIndex) self.assertTrue(caps & QgsVectorDataProvider.SelectAtId) self.assertTrue(caps & QgsVectorDataProvider.ChangeGeometries) #self.assertTrue(caps & QgsVectorDataProvider.ChangeFeatures) # We should be really opened in read-only mode even if write capabilities are declared self.assertEquals(vl.dataProvider().property("_debug_open_mode"), "read-only") # Unbalanced call to leaveUpdateMode() self.assertFalse(vl.dataProvider().leaveUpdateMode()) # Test that startEditing() / commitChanges() plays with enterUpdateMode() / leaveUpdateMode() self.assertTrue(vl.startEditing()) self.assertEquals(vl.dataProvider().property("_debug_open_mode"), "read-write") self.assertTrue(vl.dataProvider().isValid()) self.assertTrue(vl.commitChanges()) self.assertEquals(vl.dataProvider().property("_debug_open_mode"), "read-only") self.assertTrue(vl.dataProvider().isValid()) # Manual enterUpdateMode() / leaveUpdateMode() with 2 depths self.assertTrue(vl.dataProvider().enterUpdateMode()) self.assertEquals(vl.dataProvider().property("_debug_open_mode"), "read-write") caps = vl.dataProvider().capabilities() self.assertTrue(caps & QgsVectorDataProvider.AddFeatures) f = QgsFeature() f.setAttributes([200]) f.setGeometry(QgsGeometry.fromWkt('Point (2 49)')) (ret, feature_list) = vl.dataProvider().addFeatures([f]) self.assertTrue(ret) fid = feature_list[0].id() features = [ f_iter for f_iter in vl.getFeatures(QgsFeatureRequest().setFilterFid(fid)) ] values = [f_iter['pk'] for f_iter in features] self.assertEquals(values, [200]) got_geom = [f_iter.geometry() for f_iter in features][0].geometry() self.assertEquals((got_geom.x(), got_geom.y()), (2.0, 49.0)) self.assertTrue(vl.dataProvider().changeGeometryValues( {fid: QgsGeometry.fromWkt('Point (3 50)')})) self.assertTrue(vl.dataProvider().changeAttributeValues( {fid: { 0: 100 }})) features = [ f_iter for f_iter in vl.getFeatures(QgsFeatureRequest().setFilterFid(fid)) ] values = [f_iter['pk'] for f_iter in features] got_geom = [f_iter.geometry() for f_iter in features][0].geometry() self.assertEquals((got_geom.x(), got_geom.y()), (3.0, 50.0)) self.assertTrue(vl.dataProvider().deleteFeatures([fid])) # Check that it has really disappeared osgeo.gdal.PushErrorHandler('CPLQuietErrorHandler') features = [ f_iter for f_iter in vl.getFeatures(QgsFeatureRequest().setFilterFid(fid)) ] osgeo.gdal.PopErrorHandler() self.assertEquals(features, []) self.assertTrue(vl.dataProvider().addAttributes( [QgsField("new_field", QVariant.Int, "integer")])) self.assertTrue(vl.dataProvider().deleteAttributes( [len(vl.dataProvider().fields()) - 1])) self.assertTrue(vl.startEditing()) self.assertEquals(vl.dataProvider().property("_debug_open_mode"), "read-write") self.assertTrue(vl.commitChanges()) self.assertEquals(vl.dataProvider().property("_debug_open_mode"), "read-write") self.assertTrue(vl.dataProvider().enterUpdateMode()) self.assertEquals(vl.dataProvider().property("_debug_open_mode"), "read-write") self.assertTrue(vl.dataProvider().leaveUpdateMode()) self.assertEquals(vl.dataProvider().property("_debug_open_mode"), "read-write") self.assertTrue(vl.dataProvider().leaveUpdateMode()) self.assertEquals(vl.dataProvider().property("_debug_open_mode"), "read-only") # Test that update mode will be implictly enabled if doing an action # that requires update mode (ret, _) = vl.dataProvider().addFeatures([QgsFeature()]) self.assertTrue(ret) self.assertEquals(vl.dataProvider().property("_debug_open_mode"), "read-write")
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é")
def regularMatrix(self, parameters, context, source, inField, target_source, targetField, nPoints, feedback): distArea = QgsDistanceArea() distArea.setSourceCrs(source.sourceCrs(), context.transformContext()) distArea.setEllipsoid(context.project().ellipsoid()) inIdx = source.fields().lookupField(inField) targetIdx = target_source.fields().lookupField(targetField) index = QgsSpatialIndex( target_source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes( []).setDestinationCrs(source.sourceCrs(), context.transformContext())), feedback) first = True sink = None dest_id = None features = source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes([inIdx])) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, inFeat in enumerate(features): if feedback.isCanceled(): break inGeom = inFeat.geometry() if first: featList = index.nearestNeighbor(inGeom.asPoint(), nPoints) first = False fields = QgsFields() input_id_field = source.fields()[inIdx] input_id_field.setName('ID') fields.append(input_id_field) for f in target_source.getFeatures( QgsFeatureRequest().setFilterFids( featList).setSubsetOfAttributes([ targetIdx ]).setDestinationCrs(source.sourceCrs(), context.transformContext())): fields.append( QgsField(str(f[targetField]), QVariant.Double)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, source.wkbType(), source.sourceCrs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) data = [inFeat[inField]] for target in target_source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes( []).setFilterFids(featList).setDestinationCrs( source.sourceCrs(), context.transformContext())): if feedback.isCanceled(): break outGeom = target.geometry() dist = distArea.measureLine(inGeom.asPoint(), outGeom.asPoint()) data.append(dist) out_feature = QgsFeature() out_feature.setGeometry(inGeom) out_feature.setAttributes(data) sink.addFeature(out_feature, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
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 linearMatrix(self, parameters, context, source, inField, target_source, targetField, same_source_and_target, matType, nPoints, feedback): if same_source_and_target: # need to fetch an extra point from the index, since the closest match will always be the same # as the input feature nPoints += 1 inIdx = source.fields().lookupField(inField) outIdx = target_source.fields().lookupField(targetField) fields = QgsFields() input_id_field = source.fields()[inIdx] input_id_field.setName('InputID') fields.append(input_id_field) if matType == 0: target_id_field = target_source.fields()[outIdx] target_id_field.setName('TargetID') fields.append(target_id_field) fields.append(QgsField('Distance', QVariant.Double)) else: fields.append(QgsField('MEAN', QVariant.Double)) fields.append(QgsField('STDDEV', QVariant.Double)) fields.append(QgsField('MIN', QVariant.Double)) fields.append(QgsField('MAX', QVariant.Double)) out_wkb = QgsWkbTypes.multiType(source.wkbType()) if matType == 0 else source.wkbType() (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, out_wkb, source.sourceCrs()) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) index = QgsSpatialIndex(target_source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(source.sourceCrs(), context.transformContext())), feedback) distArea = QgsDistanceArea() distArea.setSourceCrs(source.sourceCrs(), context.transformContext()) distArea.setEllipsoid(context.project().ellipsoid()) features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([inIdx])) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, inFeat in enumerate(features): if feedback.isCanceled(): break inGeom = inFeat.geometry() inID = str(inFeat.attributes()[inIdx]) featList = index.nearestNeighbor(inGeom.asPoint(), nPoints) distList = [] vari = 0.0 request = QgsFeatureRequest().setFilterFids(featList).setSubsetOfAttributes([outIdx]).setDestinationCrs(source.sourceCrs(), context.transformContext()) for outFeat in target_source.getFeatures(request): if feedback.isCanceled(): break if same_source_and_target and inFeat.id() == outFeat.id(): continue outID = outFeat.attributes()[outIdx] outGeom = outFeat.geometry() dist = distArea.measureLine(inGeom.asPoint(), outGeom.asPoint()) if matType == 0: out_feature = QgsFeature() out_geom = QgsGeometry.unaryUnion([inFeat.geometry(), outFeat.geometry()]) out_feature.setGeometry(out_geom) out_feature.setAttributes([inID, outID, dist]) sink.addFeature(out_feature, QgsFeatureSink.FastInsert) else: distList.append(float(dist)) if matType != 0: mean = sum(distList) / len(distList) for i in distList: vari += (i - mean) * (i - mean) vari = math.sqrt(vari / len(distList)) out_feature = QgsFeature() out_feature.setGeometry(inFeat.geometry()) out_feature.setAttributes([inID, mean, vari, min(distList), max(distList)]) sink.addFeature(out_feature, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
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 exportLayers(iface, layers, folder, precision, optimize, popupField, json, restrictToExtent, extent, feedback): canvas = iface.mapCanvas() epsg4326 = QgsCoordinateReferenceSystem("EPSG:4326") layersFolder = os.path.join(folder, "layers") QDir().mkpath(layersFolder) for count, (layer, encode2json, popup) in enumerate(zip(layers, json, popupField)): if (layer.type() == layer.VectorLayer and (layer.providerType() != "WFS" or encode2json)): feedback.showFeedback("Exporting %s to JSON..." % layer.name()) cleanLayer = writeTmpLayer(layer, popup, restrictToExtent, iface, extent) fields = layer.pendingFields() for field in fields: exportImages(layer, field.name(), layersFolder + "/tmp.tmp") if is25d(layer, canvas, restrictToExtent, extent): provider = cleanLayer.dataProvider() provider.addAttributes([ QgsField("height", QVariant.Double), QgsField("wallColor", QVariant.String), QgsField("roofColor", QVariant.String) ]) cleanLayer.updateFields() fields = cleanLayer.pendingFields() renderer = layer.rendererV2() renderContext = QgsRenderContext.fromMapSettings( canvas.mapSettings()) feats = layer.getFeatures() context = QgsExpressionContext() context.appendScope( QgsExpressionContextUtils.layerScope(layer)) expression = QgsExpression('eval(@qgis_25d_height)') heightField = fields.indexFromName("height") wallField = fields.indexFromName("wallColor") roofField = fields.indexFromName("roofColor") renderer.startRender(renderContext, fields) cleanLayer.startEditing() for feat in feats: context.setFeature(feat) height = expression.evaluate(context) if isinstance(renderer, QgsCategorizedSymbolRendererV2): classAttribute = renderer.classAttribute() attrValue = feat.attribute(classAttribute) catIndex = renderer.categoryIndexForValue(attrValue) categories = renderer.categories() symbol = categories[catIndex].symbol() elif isinstance(renderer, QgsGraduatedSymbolRendererV2): classAttribute = renderer.classAttribute() attrValue = feat.attribute(classAttribute) ranges = renderer.ranges() for range in ranges: if (attrValue >= range.lowerValue() and attrValue <= range.upperValue()): symbol = range.symbol().clone() else: symbol = renderer.symbolForFeature2( feat, renderContext) sl1 = symbol.symbolLayer(1) sl2 = symbol.symbolLayer(2) wallColor = sl1.subSymbol().color().name() roofColor = sl2.subSymbol().color().name() provider.changeAttributeValues({ feat.id() + 1: { heightField: height, wallField: wallColor, roofField: roofColor } }) cleanLayer.commitChanges() renderer.stopRender(renderContext) sln = safeName(cleanLayer.name()) + unicode(count) tmpPath = os.path.join(layersFolder, sln + ".json") path = os.path.join(layersFolder, sln + ".js") options = [] if precision != "maintain": options.append("COORDINATE_PRECISION=" + unicode(precision)) QgsVectorFileWriter.writeAsVectorFormat(cleanLayer, tmpPath, "utf-8", epsg4326, 'GeoJson', 0, layerOptions=options) with open(path, "w") as f: f.write("var %s = " % ("geojson_" + sln)) with open(tmpPath, "r") as f2: for line in f2: if optimize: line = line.strip("\n\t ") line = removeSpaces(line) f.write(line) os.remove(tmpPath) elif (layer.type() == layer.RasterLayer and layer.providerType() != "wms"): feedback.showFeedback("Exporting %s to PNG..." % layer.name()) name_ts = (safeName(layer.name()) + unicode(count) + unicode(int(time.time()))) # We need to create a new file to export style piped_file = os.path.join(tempfile.gettempdir(), name_ts + '_piped.tif') piped_extent = layer.extent() piped_width = layer.height() piped_height = layer.width() piped_crs = layer.crs() piped_renderer = layer.renderer() piped_provider = layer.dataProvider() pipe = QgsRasterPipe() pipe.set(piped_provider.clone()) pipe.set(piped_renderer.clone()) file_writer = QgsRasterFileWriter(piped_file) file_writer.writeRaster(pipe, piped_width, piped_height, piped_extent, piped_crs) # Extent of the layer in EPSG:3857 crsSrc = layer.crs() crsDest = QgsCoordinateReferenceSystem(3857) xform = QgsCoordinateTransform(crsSrc, crsDest) extentRep = xform.transform(layer.extent()) extentRepNew = ','.join([ unicode(extentRep.xMinimum()), unicode(extentRep.xMaximum()), unicode(extentRep.yMinimum()), unicode(extentRep.yMaximum()) ]) # Reproject in 3857 piped_3857 = os.path.join(tempfile.gettempdir(), name_ts + '_piped_3857.tif') # Export layer as PNG out_raster = os.path.join( layersFolder, safeName(layer.name()) + unicode(count) + ".png") qgis_version = QGis.QGIS_VERSION if int(qgis_version.split('.')[1]) < 15: processing.runalg("gdalogr:warpreproject", piped_file, layer.crs().authid(), "EPSG:3857", "", 0, 1, 0, -1, 75, 6, 1, False, 0, False, "", piped_3857) processing.runalg("gdalogr:translate", piped_3857, 100, True, "", 0, "", extentRepNew, False, 0, 0, 75, 6, 1, False, 0, False, "", out_raster) else: try: warpArgs = { "INPUT": piped_file, "SOURCE_SRS": layer.crs().authid(), "DEST_SRS": "EPSG:3857", "NO_DATA": "", "TR": 0, "METHOD": 2, "RAST_EXT": extentRepNew, "EXT_CRS": "EPSG:3857", "RTYPE": 0, "COMPRESS": 4, "JPEGCOMPRESSION": 75, "ZLEVEL": 6, "PREDICTOR": 1, "TILED": False, "BIGTIFF": 0, "TFW": False, "EXTRA": "", "OUTPUT": piped_3857 } procRtn = processing.runalg("gdalogr:warpreproject", warpArgs) # force exception on algorithm fail for val in procRtn: pass except: try: warpArgs = { "INPUT": piped_file, "SOURCE_SRS": layer.crs().authid(), "DEST_SRS": "EPSG:3857", "NO_DATA": "", "TR": 0, "METHOD": 2, "RAST_EXT": extentRepNew, "RTYPE": 0, "COMPRESS": 4, "JPEGCOMPRESSION": 75, "ZLEVEL": 6, "PREDICTOR": 1, "TILED": False, "BIGTIFF": 0, "TFW": False, "EXTRA": "", "OUTPUT": piped_3857 } procRtn = processing.runalg("gdalogr:warpreproject", warpArgs) # force exception on algorithm fail for val in procRtn: pass except: try: warpArgs = { "INPUT": piped_file, "SOURCE_SRS": layer.crs().authid(), "DEST_SRS": "EPSG:3857", "NO_DATA": "", "TR": 0, "METHOD": 2, "RTYPE": 0, "COMPRESS": 4, "JPEGCOMPRESSION": 75, "ZLEVEL": 6, "PREDICTOR": 1, "TILED": False, "BIGTIFF": 0, "TFW": False, "EXTRA": "", "OUTPUT": piped_3857 } procRtn = processing.runalg( "gdalogr:warpreproject", warpArgs) # force exception on algorithm fail for val in procRtn: pass except: shutil.copyfile(piped_file, piped_3857) try: processing.runalg("gdalogr:translate", piped_3857, 100, True, "", 0, "", extentRepNew, False, 5, 4, 75, 6, 1, False, 0, False, "", out_raster) except: shutil.copyfile(piped_3857, out_raster) feedback.completeStep()
def 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): source = self.parameterAsSource(parameters, self.INPUT, context) extent = self.parameterAsExtent(parameters, self.TARGET_AREA, context) target_crs = self.parameterAsCrs(parameters, self.TARGET_AREA_CRS, context) target_geom = QgsGeometry.fromRect(extent) fields = QgsFields() fields.append(QgsField('auth_id', QVariant.String, '', 20)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem()) # make intersection tests nice and fast engine = QgsGeometry.createGeometryEngine(target_geom.constGet()) engine.prepareGeometry() layer_bounds = QgsGeometry.fromRect(source.sourceExtent()) crses_to_check = QgsCoordinateReferenceSystem.validSrsIds() total = 100.0 / len(crses_to_check) found_results = 0 transform_context = QgsCoordinateTransformContext() for current, srs_id in enumerate(crses_to_check): if feedback.isCanceled(): break candidate_crs = QgsCoordinateReferenceSystem.fromSrsId(srs_id) if not candidate_crs.isValid(): continue transform_candidate = QgsCoordinateTransform( candidate_crs, target_crs, transform_context) transformed_bounds = QgsGeometry(layer_bounds) try: if not transformed_bounds.transform(transform_candidate) == 0: continue except: continue try: if engine.intersects(transformed_bounds.constGet()): feedback.pushInfo( self.tr('Found candidate CRS: {}').format( candidate_crs.authid())) f = QgsFeature(fields) f.setAttributes([candidate_crs.authid()]) sink.addFeature(f, QgsFeatureSink.FastInsert) found_results += 1 except: continue feedback.setProgress(int(current * total)) if found_results == 0: feedback.reportError(self.tr('No matching projections found')) return {self.OUTPUT: dest_id}
def testWidget(self): """Test widget operations""" widget = QgsAggregateMappingWidget() for i in range(10): widget.appendField(QgsField(str(i)), source=str(i)) self.assertTrue(widget.model().rowCount(QModelIndex()), 10) def _compare(widget, expected): actual = [] for aggregate in widget.mapping(): actual.append(int(aggregate.source)) self.assertEqual(actual, expected) _compare(widget, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) selection_model = widget.selectionModel() selection_model.clear() for i in range(0, 10, 2): selection_model.select(widget.model().index(i, 0), QItemSelectionModel.Select) self.assertTrue(widget.moveSelectedFieldsDown()) _compare(widget, [1, 0, 3, 2, 5, 4, 7, 6, 9, 8]) selection_model.clear() for i in range(1, 10, 2): selection_model.select(widget.model().index(i, 0), QItemSelectionModel.Select) self.assertTrue(widget.moveSelectedFieldsUp()) _compare(widget, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) selection_model.clear() for i in range(0, 10, 2): selection_model.select(widget.model().index(i, 0), QItemSelectionModel.Select) self.assertTrue(widget.removeSelectedFields()) _compare(widget, [1, 3, 5, 7, 9]) widget.setSourceFields(self.source_fields) mapping = widget.mapping() self.assertEqual(mapping[0].field.name(), 'source_field1') self.assertEqual(mapping[0].source, '"source_field1"') self.assertEqual(mapping[0].aggregate, 'concatenate') self.assertEqual(mapping[0].delimiter, ',') self.assertEqual(mapping[1].field.name(), 'source_field2') self.assertEqual(mapping[1].source, '"source_field2"') self.assertEqual(mapping[1].aggregate, 'sum') self.assertEqual(mapping[1].delimiter, ',') mapping[0].source = 'upper("source_field2")' mapping[0].aggregate = 'first_value' mapping[0].delimiter = '|' new_aggregate = QgsAggregateMappingModel.Aggregate() new_aggregate.field = QgsField('output_field3', QVariant.Double, len=4, prec=2) new_aggregate.source = 'randf(1,2)' new_aggregate.aggregate = 'mean' new_aggregate.delimiter = '*' mapping.append(new_aggregate) widget.setMapping(mapping) mapping = widget.mapping() self.assertEqual(mapping[0].field.name(), 'source_field1') self.assertEqual(mapping[0].source, 'upper("source_field2")') self.assertEqual(mapping[0].aggregate, 'first_value') self.assertEqual(mapping[0].delimiter, '|') self.assertEqual(mapping[1].field.name(), 'source_field2') self.assertEqual(mapping[1].source, '"source_field2"') self.assertEqual(mapping[1].aggregate, 'sum') self.assertEqual(mapping[1].delimiter, ',') self.assertEqual(mapping[2].field.name(), 'output_field3') self.assertEqual(mapping[2].source, 'randf(1,2)') self.assertEqual(mapping[2].aggregate, 'mean') self.assertEqual(mapping[2].delimiter, '*')
def testModel(self): """Test the mapping model""" model = QgsAggregateMappingModel(self.source_fields) self.assertEqual(model.rowCount(QModelIndex()), 2) self.assertIsNone(model.data(model.index(9999, 0), Qt.DisplayRole)) self.assertEqual(model.data(model.index(0, 0), Qt.DisplayRole), '"source_field1"') self.assertEqual(model.data(model.index(0, 1), Qt.DisplayRole), 'concatenate') self.assertEqual(model.data(model.index(0, 2), Qt.DisplayRole), ',') self.assertEqual(model.data(model.index(0, 3), Qt.DisplayRole), 'source_field1') self.assertEqual(model.data(model.index(0, 4), Qt.DisplayRole), QVariant.String) self.assertEqual(model.data(model.index(0, 5), Qt.DisplayRole), 0) self.assertEqual(model.data(model.index(0, 6), Qt.DisplayRole), 0) self.assertEqual(model.data(model.index(1, 0), Qt.DisplayRole), '"source_field2"') self.assertEqual(model.data(model.index(1, 1), Qt.DisplayRole), 'sum') self.assertEqual(model.data(model.index(1, 2), Qt.DisplayRole), ',') self.assertEqual(model.data(model.index(1, 3), Qt.DisplayRole), 'source_field2') self.assertEqual(model.data(model.index(1, 4), Qt.DisplayRole), QVariant.Int) self.assertEqual(model.data(model.index(1, 5), Qt.DisplayRole), 10) self.assertEqual(model.data(model.index(1, 6), Qt.DisplayRole), 8) # Test expression scope ctx = model.contextGenerator().createExpressionContext() self.assertTrue('source_field1' in ctx.fields().names()) # Test add fields model.appendField(QgsField('field3', QVariant.String), 'upper("field3")', 'first_value') self.assertEqual(model.rowCount(QModelIndex()), 3) self.assertEqual(model.data(model.index(2, 0), Qt.DisplayRole), 'upper("field3")') self.assertEqual(model.data(model.index(2, 1), Qt.DisplayRole), 'first_value') self.assertEqual(model.data(model.index(2, 2), Qt.DisplayRole), ',') self.assertEqual(model.data(model.index(2, 3), Qt.DisplayRole), 'field3') self.assertEqual(model.data(model.index(2, 4), Qt.DisplayRole), QVariant.String) self.assertEqual(model.data(model.index(2, 5), Qt.DisplayRole), 0) self.assertEqual(model.data(model.index(2, 6), Qt.DisplayRole), 0) # Test remove field model.removeField(model.index(1, 0)) self.assertEqual(model.rowCount(QModelIndex()), 2) self.assertEqual(model.data(model.index(0, 0), Qt.DisplayRole), '"source_field1"') self.assertEqual(model.data(model.index(1, 0), Qt.DisplayRole), 'upper("field3")') # Test edit fields mapping = model.mapping() self.assertEqual(mapping[0].field.name(), 'source_field1') self.assertEqual(mapping[0].aggregate, 'concatenate') self.assertEqual(mapping[0].delimiter, ',') self.assertEqual(mapping[0].source, '"source_field1"') self.assertEqual(mapping[1].field.name(), 'field3') self.assertEqual(mapping[1].aggregate, 'first_value') self.assertEqual(mapping[1].delimiter, ',') self.assertEqual(mapping[1].source, 'upper("field3")') # Test move up or down self.assertFalse(model.moveUp(model.index(0, 0))) self.assertFalse(model.moveUp(model.index(100, 0))) self.assertFalse(model.moveDown(model.index(1, 0))) self.assertFalse(model.moveDown(model.index(100, 0))) self.assertTrue(model.moveDown(model.index(0, 0))) mapping = model.mapping() self.assertEqual(mapping[0].field.name(), 'field3') self.assertEqual(mapping[1].field.name(), 'source_field1') self.assertTrue(model.moveUp(model.index(1, 0))) mapping = model.mapping() self.assertEqual(mapping[0].field.name(), 'source_field1') self.assertEqual(mapping[1].field.name(), 'field3')
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, 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 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 testExportFeatures(self): """ Test exporting feature collections """ fields = QgsFields() fields.append(QgsField("name", QVariant.String)) fields.append(QgsField("cost", QVariant.Double)) fields.append(QgsField("population", QVariant.Int)) feature = QgsFeature(fields, 5) feature.setGeometry(QgsGeometry(QgsPoint(5, 6))) feature.setAttributes(['Valsier Peninsula', 6.8, 198]) exporter = QgsJsonExporter() # single feature expected = """{ "type": "FeatureCollection", "features":[ { "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":{ "name":"Valsier Peninsula", "cost":6.8, "population":198 } } ]}""" self.assertEqual(exporter.exportFeatures([feature]), expected) # multiple features feature2 = QgsFeature(fields, 6) feature2.setGeometry(QgsGeometry(QgsPoint(7, 8))) feature2.setAttributes(['Henry Gale Island', 9.7, 38]) expected = """{ "type": "FeatureCollection", "features":[ { "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":{ "name":"Valsier Peninsula", "cost":6.8, "population":198 } }, { "type":"Feature", "id":6, "geometry": {"type": "Point", "coordinates": [7, 8]}, "properties":{ "name":"Henry Gale Island", "cost":9.7, "population":38 } } ]}""" self.assertEqual(exporter.exportFeatures([feature, feature2]), expected)
def testJSONExporter(self): """ test converting features to GeoJSON """ fields = QgsFields() fields.append(QgsField("name", QVariant.String)) fields.append(QgsField("cost", QVariant.Double)) fields.append(QgsField("population", QVariant.Int)) feature = QgsFeature(fields, 5) feature.setGeometry(QgsGeometry(QgsPoint(5, 6))) feature.setAttributes(['Valsier Peninsula', 6.8, 198]) exporter = QgsJsonExporter() expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":{ "name":"Valsier Peninsula", "cost":6.8, "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) # test with linestring for bbox inclusion l = QgsLineString() l.setPoints([QgsPoint(5, 6), QgsPoint(15, 16)]) feature.setGeometry(QgsGeometry(QgsLineString(l))) expected = """{ "type":"Feature", "id":5, "bbox":[5, 6, 15, 16], "geometry": {"type": "LineString", "coordinates": [ [5, 6], [15, 16]]}, "properties":{ "name":"Valsier Peninsula", "cost":6.8, "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) # test that precision is respected feature.setGeometry(QgsGeometry(QgsPoint(5.444444444, 6.333333333))) exporter.setPrecision(3) self.assertEqual(exporter.precision(), 3) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5.444, 6.333]}, "properties":{ "name":"Valsier Peninsula", "cost":6.8, "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) feature.setGeometry(QgsGeometry(QgsPoint(5, 6))) exporter.setPrecision(17) # test that attribute subset is respected exporter.setAttributes([0, 2]) self.assertEqual(exporter.attributes(), [0, 2]) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":{ "name":"Valsier Peninsula", "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setAttributes([1]) self.assertEqual(exporter.attributes(), [1]) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":{ "cost":6.8 } }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setAttributes([]) # text excluding attributes exporter.setExcludedAttributes([1]) self.assertEqual(exporter.excludedAttributes(), [1]) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":{ "name":"Valsier Peninsula", "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setExcludedAttributes([1, 2]) self.assertEqual(exporter.excludedAttributes(), [1, 2]) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":{ "name":"Valsier Peninsula" } }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setExcludedAttributes([0, 1, 2]) self.assertEqual(exporter.excludedAttributes(), [0, 1, 2]) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":null }""" self.assertEqual(exporter.exportFeature(feature), expected) # test that excluded attributes take precedence over included exporter.setAttributes([1, 2]) exporter.setExcludedAttributes([0, 1]) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":{ "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setAttributes([]) exporter.setExcludedAttributes([]) # test excluding geometry exporter.setIncludeGeometry(False) self.assertEqual(exporter.includeGeometry(), False) feature.setGeometry(QgsGeometry(QgsLineString(l))) expected = """{ "type":"Feature", "id":5, "geometry":null, "properties":{ "name":"Valsier Peninsula", "cost":6.8, "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setIncludeGeometry(True) feature.setGeometry(QgsGeometry(QgsPoint(5, 6))) # test excluding attributes exporter.setIncludeAttributes(False) self.assertEqual(exporter.includeAttributes(), False) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":null }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setIncludeGeometry(False) expected = """{ "type":"Feature", "id":5, "geometry":null, "properties":null }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setIncludeAttributes(True) # test overriding ID expected = """{ "type":"Feature", "id":29, "geometry":null, "properties":{ "name":"Valsier Peninsula", "cost":6.8, "population":198 } }""" self.assertEqual(exporter.exportFeature(feature, id=29), expected) # test injecting extra attributes expected = """{ "type":"Feature", "id":5, "geometry":null, "properties":{ "name":"Valsier Peninsula", "cost":6.8, "population":198, "extra":"val1", "extra2":2 } }""" self.assertEqual( exporter.exportFeature(feature, extraProperties={ "extra": "val1", "extra2": 2 }), expected) exporter.setIncludeAttributes(False) expected = """{ "type":"Feature", "id":5, "geometry":null, "properties":{ "extra":"val1", "extra2":{"nested_map":5, "nested_map2":"val"}, "extra3":[1,2,3] } }""" expected2 = """{ "type":"Feature", "id":5, "geometry":null, "properties":{ "extra":"val1", "extra2":{"nested_map":5,"nested_map2":"val"}, "extra3":[1,2,3] } }""" exp_f = exporter.exportFeature(feature, extraProperties={ "extra": "val1", "extra2": { "nested_map": 5, "nested_map2": "val" }, "extra3": [1, 2, 3] }) self.assertTrue(exp_f == expected or exp_f == expected2) exporter.setIncludeGeometry(True)
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, 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[group_field_index] else: group = 1 order = f[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 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 processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) fields = QgsFields() fields.append(QgsField('POINTA', QVariant.Double, '', 24, 15)) fields.append(QgsField('POINTB', QVariant.Double, '', 24, 15)) fields.append(QgsField('POINTC', QVariant.Double, '', 24, 15)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Polygon, source.sourceCrs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) pts = [] ptDict = {} ptNdx = -1 c = voronoi.Context() features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, inFeat in enumerate(features): if feedback.isCanceled(): break geom = QgsGeometry(inFeat.geometry()) if geom.isNull(): continue if geom.isMultipart(): points = geom.asMultiPoint() else: points = [geom.asPoint()] for n, point in enumerate(points): x = point.x() y = point.y() pts.append((x, y)) ptNdx += 1 ptDict[ptNdx] = (inFeat.id(), n) feedback.setProgress(int(current * total)) if len(pts) < 3: raise QgsProcessingException( self.tr('Input file should contain at least 3 points. Choose ' 'another file and try again.')) uniqueSet = set(item for item in pts) ids = [pts.index(item) for item in uniqueSet] sl = voronoi.SiteList([voronoi.Site(*i) for i in uniqueSet]) c.triangulate = True voronoi.voronoi(sl, c) triangles = c.triangles feat = QgsFeature() total = 100.0 / len(triangles) if triangles else 1 for current, triangle in enumerate(triangles): if feedback.isCanceled(): break indices = list(triangle) indices.append(indices[0]) polygon = [] attrs = [] step = 0 for index in indices: fid, n = ptDict[ids[index]] request = QgsFeatureRequest().setFilterFid(fid) inFeat = next(source.getFeatures(request)) geom = QgsGeometry(inFeat.geometry()) if geom.isMultipart(): point = QgsPointXY(geom.asMultiPoint()[n]) else: point = QgsPointXY(geom.asPoint()) polygon.append(point) if step <= 3: attrs.append(ids[index]) step += 1 feat.setAttributes(attrs) geometry = QgsGeometry().fromPolygonXY([polygon]) feat.setGeometry(geometry) sink.addFeature(feat, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def calculate_iri( iface, current_layer, project_definition, svi_attr_id, aal_field_name, discarded_feats_ids, iri_operator=None ): """ Copy the AAL and calculate an IRI attribute to the current layer """ # set default if iri_operator is None: iri_operator = DEFAULT_COMBINATION aal_weight = project_definition["children"][0]["weight"] svi_weight = project_definition["children"][1]["weight"] iri_attr_name = "IRI" iri_field = QgsField(iri_attr_name, QVariant.Double) iri_field.setTypeName(DOUBLE_FIELD_TYPE_NAME) attr_names = ProcessLayer(current_layer).add_attributes([iri_field]) # get the id of the new attributes iri_attr_id = ProcessLayer(current_layer).find_attribute_id(attr_names[iri_attr_name]) discarded_aal_feats_ids = [] try: with LayerEditingManager(current_layer, "Add IRI", DEBUG): for feat in current_layer.getFeatures(): feat_id = feat.id() svi_value = feat.attributes()[svi_attr_id] aal_value = feat[aal_field_name] if aal_value == QPyNullVariant(float) or feat_id in discarded_feats_ids: iri_value = QPyNullVariant(float) discarded_aal_feats_ids.append(feat_id) elif iri_operator == "Sum (simple)": iri_value = svi_value + aal_value elif iri_operator == "Multiplication (simple)": iri_value = svi_value * aal_value elif iri_operator == "Sum (weighted)": iri_value = svi_value * svi_weight + aal_value * aal_weight elif iri_operator == "Multiplication (weighted)": iri_value = svi_value * svi_weight * aal_value * aal_weight elif iri_operator == "Average (equal weights)": # For "Average (equal weights)" it's equivalent to use # equal weights, or to sum the indices (all weights 1) # and divide by the number of indices (we use # the latter solution) iri_value = (svi_value + aal_value) / 2.0 # store IRI current_layer.changeAttributeValue(feat_id, iri_attr_id, iri_value) project_definition["iri_operator"] = iri_operator # set the field name for the copied AAL layer project_definition["aal_field"] = aal_field_name project_definition["iri_field"] = attr_names[iri_attr_name] msg = ( "The IRI has been calculated for fields containing " "non-NULL values and it was added to the layer as " "a new attribute called %s" ) % attr_names[iri_attr_name] iface.messageBar().pushMessage(tr("Info"), tr(msg), level=QgsMessageBar.INFO) widget = toggle_select_features_widget( tr("Warning"), tr("Invalid values were found in some features while calculating " "IRI"), tr("Select invalid features"), current_layer, discarded_aal_feats_ids, current_layer.selectedFeaturesIds(), ) iface.messageBar().pushWidget(widget, QgsMessageBar.WARNING) return iri_attr_id except TypeError as e: current_layer.dataProvider().deleteAttributes([iri_attr_id]) msg = "Could not calculate IRI due to data problems: %s" % e iface.messageBar().pushMessage(tr("Error"), tr(msg), level=QgsMessageBar.CRITICAL)
def processAlgorithm(self, parameters, context, feedback): line_source = self.parameterAsSource(parameters, self.LINES, context) poly_source = self.parameterAsSource(parameters, self.POLYGONS, context) length_field_name = self.parameterAsString(parameters, self.LEN_FIELD, context) count_field_name = self.parameterAsString(parameters, self.COUNT_FIELD, context) fields = poly_source.fields() if fields.lookupField(length_field_name) < 0: fields.append(QgsField(length_field_name, QVariant.Double)) length_field_index = fields.lookupField(length_field_name) if fields.lookupField(count_field_name) < 0: fields.append(QgsField(count_field_name, QVariant.Int)) count_field_index = fields.lookupField(count_field_name) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, poly_source.wkbType(), poly_source.sourceCrs()) spatialIndex = QgsSpatialIndex(line_source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(poly_source.sourceCrs())), feedback) distArea = QgsDistanceArea() distArea.setSourceCrs(poly_source.sourceCrs()) distArea.setEllipsoid(context.project().ellipsoid()) features = poly_source.getFeatures() total = 100.0 / poly_source.featureCount() if poly_source.featureCount() else 0 for current, poly_feature in enumerate(features): if feedback.isCanceled(): break output_feature = QgsFeature() count = 0 length = 0 if poly_feature.hasGeometry(): poly_geom = poly_feature.geometry() has_intersections = False lines = spatialIndex.intersects(poly_geom.boundingBox()) engine = None if len(lines) > 0: has_intersections = True # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(poly_geom.constGet()) engine.prepareGeometry() if has_intersections: request = QgsFeatureRequest().setFilterFids(lines).setSubsetOfAttributes([]).setDestinationCrs(poly_source.sourceCrs()) for line_feature in line_source.getFeatures(request): if feedback.isCanceled(): break if engine.intersects(line_feature.geometry().constGet()): outGeom = poly_geom.intersection(line_feature.geometry()) length += distArea.measureLength(outGeom) count += 1 output_feature.setGeometry(poly_geom) attrs = poly_feature.attributes() if length_field_index == len(attrs): attrs.append(length) else: attrs[length_field_index] = length if count_field_index == len(attrs): attrs.append(count) else: attrs[count_field_index] = count output_feature.setAttributes(attrs) sink.addFeature(output_feature, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) method = self.parameterAsEnum(parameters, self.METHOD, context) wkb_type = source.wkbType() fields = source.fields() new_fields = QgsFields() if QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.PolygonGeometry: new_fields.append(QgsField('area', QVariant.Double)) new_fields.append(QgsField('perimeter', QVariant.Double)) elif QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.LineGeometry: new_fields.append(QgsField('length', QVariant.Double)) if not QgsWkbTypes.isMultiType(source.wkbType()): new_fields.append(QgsField('straightdis', QVariant.Double)) new_fields.append(QgsField('sinuosity', QVariant.Double)) else: new_fields.append(QgsField('xcoord', QVariant.Double)) new_fields.append(QgsField('ycoord', QVariant.Double)) if QgsWkbTypes.hasZ(source.wkbType()): self.export_z = True new_fields.append(QgsField('zcoord', QVariant.Double)) if QgsWkbTypes.hasM(source.wkbType()): self.export_m = True new_fields.append(QgsField('mvalue', QVariant.Double)) fields = QgsProcessingUtils.combineFields(fields, new_fields) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, wkb_type, source.sourceCrs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) coordTransform = None # Calculate with: # 0 - layer CRS # 1 - project CRS # 2 - ellipsoidal self.distance_area = QgsDistanceArea() if method == 2: self.distance_area.setSourceCrs(source.sourceCrs(), context.transformContext()) self.distance_area.setEllipsoid(context.project().ellipsoid()) elif method == 1: coordTransform = QgsCoordinateTransform(source.sourceCrs(), context.project().crs(), context.project()) features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break outFeat = f attrs = f.attributes() inGeom = f.geometry() if inGeom: if coordTransform is not None: inGeom.transform(coordTransform) if inGeom.type() == QgsWkbTypes.PointGeometry: attrs.extend(self.point_attributes(inGeom)) elif inGeom.type() == QgsWkbTypes.PolygonGeometry: attrs.extend(self.polygon_attributes(inGeom)) else: attrs.extend(self.line_attributes(inGeom)) # ensure consistent count of attributes - otherwise null # geometry features will have incorrect attribute length # and provider may reject them if len(attrs) < len(fields): attrs += [NULL] * (len(fields) - len(attrs)) outFeat.setAttributes(attrs) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) field_name = self.parameterAsString(parameters, self.FIELD_NAME, context) field_type = self.TYPES[self.parameterAsEnum(parameters, self.FIELD_TYPE, context)] width = self.parameterAsInt(parameters, self.FIELD_LENGTH, context) precision = self.parameterAsInt(parameters, self.FIELD_PRECISION, context) code = self.parameterAsString(parameters, self.FORMULA, context) globalExpression = self.parameterAsString(parameters, self.GLOBAL, context) fields = source.fields() field = QgsField(field_name, field_type, '', width, precision) fields.append(field) new_ns = {} (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, source.wkbType(), source.sourceCrs()) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) # Run global code if globalExpression.strip() != '': try: bytecode = compile(globalExpression, '<string>', 'exec') exec(bytecode, new_ns) except: raise QgsProcessingException( self.tr("FieldPyculator code execute error.Global code block can't be executed!\n{0}\n{1}").format( str(sys.exc_info()[0].__name__), str(sys.exc_info()[1]))) # Replace all fields tags fields = source.fields() num = 0 for field in fields: field_name = str(field.name()) replval = '__attr[' + str(num) + ']' code = code.replace('<' + field_name + '>', replval) num += 1 # Replace all special vars code = code.replace('$id', '__id') code = code.replace('$geom', '__geom') need_id = code.find('__id') != -1 need_geom = code.find('__geom') != -1 need_attrs = code.find('__attr') != -1 # Compile try: bytecode = compile(code, '<string>', 'exec') except: raise QgsProcessingException( self.tr("FieldPyculator code execute error. Field code block can't be executed!\n{0}\n{1}").format( str(sys.exc_info()[0].__name__), str(sys.exc_info()[1]))) # Run features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, feat in enumerate(features): if feedback.isCanceled(): break feedback.setProgress(int(current * total)) attrs = feat.attributes() feat_id = feat.id() # Add needed vars if need_id: new_ns['__id'] = feat_id if need_geom: geom = feat.geometry() new_ns['__geom'] = geom if need_attrs: pyattrs = [a for a in attrs] new_ns['__attr'] = pyattrs # Clear old result if self.RESULT_VAR_NAME in new_ns: del new_ns[self.RESULT_VAR_NAME] # Exec exec(bytecode, new_ns) # Check result if self.RESULT_VAR_NAME not in new_ns: raise QgsProcessingException( self.tr("FieldPyculator code execute error\n" "Field code block does not return '{0}' variable! " "Please declare this variable in your code!").format(self.RESULT_VAR_NAME)) # Write feature attrs.append(new_ns[self.RESULT_VAR_NAME]) feat.setAttributes(attrs) sink.addFeature(feat, QgsFeatureSink.FastInsert) return {self.OUTPUT: dest_id}
def testWidget(self): """Test widget operations""" widget = QgsFieldMappingWidget() for i in range(10): widget.appendField(QgsField(str(i))) self.assertTrue(widget.model().rowCount(QModelIndex()), 10) def _compare(widget, expected): actual = [] for field in widget.mapping(): actual.append(int(field.originalName)) self.assertEqual(actual, expected) _compare(widget, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) selection_model = widget.selectionModel() selection_model.clear() for i in range(0, 10, 2): selection_model.select(widget.model().index(i, 0), QItemSelectionModel.Select) self.assertTrue(widget.moveSelectedFieldsDown()) _compare(widget, [1, 0, 3, 2, 5, 4, 7, 6, 9, 8]) selection_model.clear() for i in range(1, 10, 2): selection_model.select(widget.model().index(i, 0), QItemSelectionModel.Select) self.assertTrue(widget.moveSelectedFieldsUp()) _compare(widget, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) selection_model.clear() for i in range(0, 10, 2): selection_model.select(widget.model().index(i, 0), QItemSelectionModel.Select) self.assertTrue(widget.removeSelectedFields()) _compare(widget, [1, 3, 5, 7, 9]) # Test set destination fields widget.setSourceFields(self.source_fields) widget.setDestinationFields(self.destination_fields) mapping = widget.mapping() self.assertEqual(mapping[0].field.name(), 'destination_field1') self.assertEqual(mapping[1].field.name(), 'destination_field2') self.assertEqual(mapping[2].field.name(), 'destination_field3') self.assertEqual(mapping[0].originalName, 'destination_field1') self.assertEqual(mapping[1].originalName, 'destination_field2') self.assertEqual(mapping[2].originalName, 'destination_field3') # Test constraints f = QgsField('constraint_field', QVariant.Int) constraints = QgsFieldConstraints() constraints.setConstraint(QgsFieldConstraints.ConstraintNotNull, QgsFieldConstraints.ConstraintOriginProvider) constraints.setConstraint(QgsFieldConstraints.ConstraintExpression, QgsFieldConstraints.ConstraintOriginProvider) constraints.setConstraint(QgsFieldConstraints.ConstraintUnique, QgsFieldConstraints.ConstraintOriginProvider) f.setConstraints(constraints) fields = QgsFields() fields.append(f) widget.setDestinationFields(fields) self.assertEqual( widget.model().data(widget.model().index(0, 5, QModelIndex()), Qt.DisplayRole), "Constraints active") self.assertEqual( widget.model().data(widget.model().index(0, 5, QModelIndex()), Qt.ToolTipRole), "Unique<br>Not null<br>Expression") self.assertEqual( widget.model().data(widget.model().index(0, 5, QModelIndex()), Qt.BackgroundColorRole), QColor(255, 224, 178))
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 processAlgorithm(self, parameters, context, feedback): network = self.parameterAsSource(parameters, self.INPUT, context) startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs()) strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) travelCost = self.parameterAsDouble(parameters, self.TRAVEL_COST, context) directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) directionField = -1 if directionFieldName: directionField = network.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName: speedField = network.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(network, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = context.project().crs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor( distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) director.addStrategy(strategy) builder = QgsGraphBuilder(network.sourceCrs(), True, tolerance) feedback.pushInfo( QCoreApplication.translate('ServiceAreaFromPoint', 'Building graph…')) snappedPoints = director.makeGraph(builder, [startPoint], feedback) feedback.pushInfo( QCoreApplication.translate('ServiceAreaFromPoint', 'Calculating service area…')) graph = builder.graph() idxStart = graph.findVertex(snappedPoints[0]) tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) vertices = [] for i, v in enumerate(cost): if v > travelCost and tree[i] != -1: vertexId = graph.edge(tree[i]).fromVertex() if cost[vertexId] <= travelCost: vertices.append(i) upperBoundary = [] lowerBoundary = [] for i in vertices: upperBoundary.append( graph.vertex(graph.edge(tree[i]).toVertex()).point()) lowerBoundary.append( graph.vertex(graph.edge(tree[i]).fromVertex()).point()) feedback.pushInfo( QCoreApplication.translate('ServiceAreaFromPoint', 'Writing results…')) fields = QgsFields() fields.append(QgsField('type', QVariant.String, '', 254, 0)) fields.append(QgsField('start', QVariant.String, '', 254, 0)) feat = QgsFeature() feat.setFields(fields) geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary) geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.MultiPoint, network.sourceCrs()) feat.setGeometry(geomUpper) feat['type'] = 'upper' feat['start'] = startPoint.toString() sink.addFeature(feat, QgsFeatureSink.FastInsert) feat.setGeometry(geomLower) feat['type'] = 'lower' feat['start'] = startPoint.toString() sink.addFeature(feat, QgsFeatureSink.FastInsert) upperBoundary.append(startPoint) lowerBoundary.append(startPoint) geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary) geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary) return {self.OUTPUT: dest_id}