def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) index = self.parameterAsEnum(parameters, self.TYPE, context) if index == 0: newType = QgsWkbTypes.Point elif index == 1: newType = QgsWkbTypes.Point if QgsWkbTypes.hasM(source.wkbType()): newType = QgsWkbTypes.addM(newType) if QgsWkbTypes.hasZ(source.wkbType()): newType = QgsWkbTypes.addZ(newType) elif index == 2: newType = QgsWkbTypes.LineString if QgsWkbTypes.hasM(source.wkbType()): newType = QgsWkbTypes.addM(newType) if QgsWkbTypes.hasZ(source.wkbType()): newType = QgsWkbTypes.addZ(newType) elif index == 3: newType = QgsWkbTypes.MultiLineString if QgsWkbTypes.hasM(source.wkbType()): newType = QgsWkbTypes.addM(newType) if QgsWkbTypes.hasZ(source.wkbType()): newType = QgsWkbTypes.addZ(newType) else: newType = QgsWkbTypes.Polygon if QgsWkbTypes.hasM(source.wkbType()): newType = QgsWkbTypes.addM(newType) if QgsWkbTypes.hasZ(source.wkbType()): newType = QgsWkbTypes.addZ(newType) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, source.fields(), newType, source.sourceCrs()) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break if not f.hasGeometry(): sink.addFeature(f, QgsFeatureSink.FastInsert) else: for p in self.convertGeometry(f.geometry(), index): feat = QgsFeature() feat.setAttributes(f.attributes()) feat.setGeometry(p) sink.addFeature(feat, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT_LAYER)) input_wkb = layer.wkbType() if QgsWkbTypes.geometryType(input_wkb) == QgsWkbTypes.LineGeometry: output_wkb = QgsWkbTypes.MultiPoint elif QgsWkbTypes.geometryType(input_wkb) == QgsWkbTypes.PolygonGeometry: output_wkb = QgsWkbTypes.MultiLineString if QgsWkbTypes.hasZ(input_wkb): output_wkb = QgsWkbTypes.addZ(output_wkb) if QgsWkbTypes.hasM(input_wkb): output_wkb = QgsWkbTypes.addM(output_wkb) writer = self.getOutputFromName(self.OUTPUT_LAYER).getVectorWriter(layer.fields(), output_wkb, layer.crs()) features = vector.features(layer) total = 100.0 / len(features) for current, input_feature in enumerate(features): output_feature = input_feature input_geometry = input_feature.geometry() if input_geometry: output_geometry = QgsGeometry(input_geometry.geometry().boundary()) if not output_geometry: raise GeoAlgorithmExecutionException(self.tr("Error calculating boundary")) output_feature.setGeometry(output_geometry) writer.addFeature(output_feature) progress.setPercentage(int(current * total)) del writer
def outputWkbType(self, input_wkb): if QgsWkbTypes.geometryType(input_wkb) == QgsWkbTypes.LineGeometry: output_wkb = QgsWkbTypes.MultiPoint elif QgsWkbTypes.geometryType(input_wkb) == QgsWkbTypes.PolygonGeometry: output_wkb = QgsWkbTypes.MultiLineString if QgsWkbTypes.hasZ(input_wkb): output_wkb = QgsWkbTypes.addZ(output_wkb) if QgsWkbTypes.hasM(input_wkb): output_wkb = QgsWkbTypes.addM(output_wkb) return output_wkb
def convertWkbToLines(self, wkb): multi_wkb = QgsWkbTypes.NoGeometry if QgsWkbTypes.singleType(QgsWkbTypes.flatType(wkb)) == QgsWkbTypes.Polygon: multi_wkb = QgsWkbTypes.MultiLineString elif QgsWkbTypes.singleType(QgsWkbTypes.flatType(wkb)) == QgsWkbTypes.CurvePolygon: multi_wkb = QgsWkbTypes.MultiCurve if QgsWkbTypes.hasM(wkb): multi_wkb = QgsWkbTypes.addM(multi_wkb) if QgsWkbTypes.hasZ(wkb): multi_wkb = QgsWkbTypes.addZ(multi_wkb) return multi_wkb
def convertWkbToPolygons(self, wkb): multi_wkb = QgsWkbTypes.NoGeometry if QgsWkbTypes.singleType(QgsWkbTypes.flatType(wkb)) == QgsWkbTypes.LineString: multi_wkb = QgsWkbTypes.MultiPolygon elif QgsWkbTypes.singleType(QgsWkbTypes.flatType(wkb)) == QgsWkbTypes.CompoundCurve: multi_wkb = QgsWkbTypes.MultiSurface if QgsWkbTypes.hasM(wkb): multi_wkb = QgsWkbTypes.addM(multi_wkb) if QgsWkbTypes.hasZ(wkb): multi_wkb = QgsWkbTypes.addZ(multi_wkb) return multi_wkb
def processFeature(self, feature, feedback): input_geometry = feature.geometry() if input_geometry: new_geom = input_geometry.constGet().clone() if QgsWkbTypes.hasM(new_geom.wkbType()): # addMValue won't alter existing M values, so drop them first new_geom.dropMValue() new_geom.addMValue(self.m_value) feature.setGeometry(QgsGeometry(new_geom)) return feature
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) fields = source.fields() fields.append(QgsField('node_index', QVariant.Int)) fields.append(QgsField('distance', QVariant.Double)) fields.append(QgsField('angle', QVariant.Double)) out_wkb = QgsWkbTypes.Point if QgsWkbTypes.hasM(source.wkbType()): out_wkb = QgsWkbTypes.addM(out_wkb) if QgsWkbTypes.hasZ(source.wkbType()): out_wkb = QgsWkbTypes.addZ(out_wkb) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, out_wkb, source.sourceCrs()) features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break input_geometry = f.geometry() if not input_geometry: sink.addFeature(f, QgsFeatureSink.FastInsert) else: i = 0 for part in input_geometry.geometry().coordinateSequence(): for ring in part: if feedback.isCanceled(): break for point in ring: distance = input_geometry.distanceToVertex(i) angle = math.degrees(input_geometry.angleAtVertex(i)) attrs = f.attributes() attrs.append(i) attrs.append(distance) attrs.append(angle) output_feature = QgsFeature() output_feature.setAttributes(attrs) output_feature.setGeometry(QgsGeometry(point.clone())) sink.addFeature(output_feature, QgsFeatureSink.FastInsert) i += 1 feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def test_zm(self): """Test Z dimension and M value""" l = QgsVectorLayer("dbname=%s table='test_z' (geometry) key='id'" % self.dbname, "test_z", "spatialite") self.assertTrue(l.isValid()) self.assertTrue(QgsWkbTypes.hasZ(l.wkbType())) feature = l.getFeature(1) geom = feature.geometry().constGet() self.assertEqual(geom.z(), 1.0) l = QgsVectorLayer("dbname=%s table='test_m' (geometry) key='id'" % self.dbname, "test_m", "spatialite") self.assertTrue(l.isValid()) self.assertTrue(QgsWkbTypes.hasM(l.wkbType())) feature = l.getFeature(1) geom = feature.geometry().constGet() self.assertEqual(geom.m(), 1.0) l = QgsVectorLayer("dbname=%s table='test_zm' (geometry) key='id'" % self.dbname, "test_zm", "spatialite") self.assertTrue(l.isValid()) self.assertTrue(QgsWkbTypes.hasZ(l.wkbType())) self.assertTrue(QgsWkbTypes.hasM(l.wkbType())) feature = l.getFeature(1) geom = feature.geometry().constGet() self.assertEqual(geom.z(), 1.0) self.assertEqual(geom.m(), 1.0)
def processFeature(self, feature, context, feedback): input_geometry = feature.geometry() if input_geometry: new_geom = input_geometry.constGet().clone() if QgsWkbTypes.hasM(new_geom.wkbType()): # addMValue won't alter existing M values, so drop them first new_geom.dropMValue() m = self.m_value if self.dynamic_m: m, ok = self.m_property.valueAsDouble(context.expressionContext(), m) new_geom.addMValue(m) feature.setGeometry(QgsGeometry(new_geom)) return feature
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT_LAYER, context) input_wkb = source.wkbType() if QgsWkbTypes.geometryType(input_wkb) == QgsWkbTypes.LineGeometry: output_wkb = QgsWkbTypes.MultiPoint elif QgsWkbTypes.geometryType(input_wkb) == QgsWkbTypes.PolygonGeometry: output_wkb = QgsWkbTypes.MultiLineString if QgsWkbTypes.hasZ(input_wkb): output_wkb = QgsWkbTypes.addZ(output_wkb) if QgsWkbTypes.hasM(input_wkb): output_wkb = QgsWkbTypes.addM(output_wkb) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context, source.fields(), output_wkb, source.sourceCrs()) features = source.getFeatures() total = 100.0 / source.featureCount() for current, input_feature in enumerate(features): if feedback.isCanceled(): break output_feature = input_feature input_geometry = input_feature.geometry() if input_geometry: output_geometry = QgsGeometry(input_geometry.geometry().boundary()) if not output_geometry: raise GeoAlgorithmExecutionException( self.tr('Error calculating boundary')) output_feature.setGeometry(output_geometry) sink.addFeature(output_feature) feedback.setProgress(int(current * total)) return {self.OUTPUT_LAYER: dest_id}
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) method = self.parameterAsEnum(parameters, self.METHOD, context) wkb_type = source.wkbType() fields = source.fields() if QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.PolygonGeometry: areaName = vector.createUniqueFieldName('area', fields) fields.append(QgsField(areaName, QVariant.Double)) perimeterName = vector.createUniqueFieldName('perimeter', fields) fields.append(QgsField(perimeterName, QVariant.Double)) elif QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.LineGeometry: lengthName = vector.createUniqueFieldName('length', fields) fields.append(QgsField(lengthName, QVariant.Double)) else: xName = vector.createUniqueFieldName('xcoord', fields) fields.append(QgsField(xName, QVariant.Double)) yName = vector.createUniqueFieldName('ycoord', fields) fields.append(QgsField(yName, QVariant.Double)) if QgsWkbTypes.hasZ(source.wkbType()): self.export_z = True zName = vector.createUniqueFieldName('zcoord', fields) fields.append(QgsField(zName, QVariant.Double)) if QgsWkbTypes.hasM(source.wkbType()): self.export_m = True zName = vector.createUniqueFieldName('mvalue', fields) fields.append(QgsField(zName, QVariant.Double)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, wkb_type, source.sourceCrs()) 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()) self.distance_area.setEllipsoid(context.project().ellipsoid()) elif method == 1: coordTransform = QgsCoordinateTransform(source.sourceCrs(), context.project().crs()) 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)) outFeat.setAttributes(attrs) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def make_features_compatible(new_features, input_layer): """Try to make the new features compatible with old features by: - converting single to multi part - dropping additional attributes - adding back M/Z values - drop Z/M - convert multi part to single part :param new_features: new features :type new_features: list of QgsFeatures :param input_layer: input layer :type input_layer: QgsVectorLayer :return: modified features :rtype: list of QgsFeatures """ input_wkb_type = input_layer.wkbType() result_features = [] for new_f in new_features: # Fix attributes if new_f.fields().count() > 0: attributes = [] for field in input_layer.fields(): if new_f.fields().indexFromName(field.name()) >= 0: attributes.append(new_f[field.name()]) else: attributes.append(None) f = QgsFeature(input_layer.fields()) f.setAttributes(attributes) f.setGeometry(new_f.geometry()) new_f = f else: lendiff = len(new_f.attributes()) - len(input_layer.fields()) if lendiff > 0: f = QgsFeature(input_layer.fields()) f.setGeometry(new_f.geometry()) f.setAttributes(new_f.attributes()[:len(input_layer.fields())]) new_f = f elif lendiff < 0: f = QgsFeature(input_layer.fields()) f.setGeometry(new_f.geometry()) attributes = new_f.attributes() + [None for i in range(-lendiff)] f.setAttributes(attributes) new_f = f # Check if we need geometry manipulation new_f_geom_type = QgsWkbTypes.geometryType(new_f.geometry().wkbType()) new_f_has_geom = new_f_geom_type not in (QgsWkbTypes.UnknownGeometry, QgsWkbTypes.NullGeometry) input_layer_has_geom = input_wkb_type not in (QgsWkbTypes.NoGeometry, QgsWkbTypes.Unknown) # Drop geometry if layer is geometry-less if not input_layer_has_geom and new_f_has_geom: f = QgsFeature(input_layer.fields()) f.setAttributes(new_f.attributes()) new_f = f result_features.append(new_f) continue # skip the rest if input_layer_has_geom and new_f_has_geom and \ new_f.geometry().wkbType() != input_wkb_type: # Fix geometry # Single -> Multi if (QgsWkbTypes.isMultiType(input_wkb_type) and not new_f.geometry().isMultipart()): new_geom = new_f.geometry() new_geom.convertToMultiType() new_f.setGeometry(new_geom) # Drop Z/M if (new_f.geometry().constGet().is3D() and not QgsWkbTypes.hasZ(input_wkb_type)): new_geom = new_f.geometry() new_geom.get().dropZValue() new_f.setGeometry(new_geom) if (new_f.geometry().constGet().isMeasure() and not QgsWkbTypes.hasM(input_wkb_type)): new_geom = new_f.geometry() new_geom.get().dropMValue() new_f.setGeometry(new_geom) # Add Z/M back (set it to 0) if (not new_f.geometry().constGet().is3D() and QgsWkbTypes.hasZ(input_wkb_type)): new_geom = new_f.geometry() new_geom.get().addZValue(0.0) new_f.setGeometry(new_geom) if (not new_f.geometry().constGet().isMeasure() and QgsWkbTypes.hasM(input_wkb_type)): new_geom = new_f.geometry() new_geom.get().addMValue(0.0) new_f.setGeometry(new_geom) # Multi -> Single if (not QgsWkbTypes.isMultiType(input_wkb_type) and new_f.geometry().isMultipart()): g = new_f.geometry() g2 = g.constGet() for i in range(g2.partCount()): # Clone or crash! g4 = QgsGeometry(g2.geometryN(i).clone()) f = QgsVectorLayerUtils.createFeature(input_layer, g4, {i: new_f.attribute(i) for i in range(new_f.fields().count())}) result_features.append(f) else: result_features.append(new_f) else: result_features.append(new_f) return result_features
def supportInPlaceEdit(self, layer): return super().supportInPlaceEdit(layer) and QgsWkbTypes.hasM(layer.wkbType())
def getVectorTables(self, schema=None): """Returns a list of vector table information """ items = [] for table in self.core_connection.tables( schema, QgsAbstractDatabaseProviderConnection.Vector | QgsAbstractDatabaseProviderConnection.Aspatial): if not (table.flags() & QgsAbstractDatabaseProviderConnection.Aspatial): geom_type = table.geometryColumnTypes()[0] # Use integer PG code for SRID srid = geom_type.crs.postgisSrid() geomtype_flatten = QgsWkbTypes.flatType(geom_type.wkbType) geomname = 'GEOMETRY' if geomtype_flatten == QgsWkbTypes.Point: geomname = 'POINT' elif geomtype_flatten == QgsWkbTypes.LineString: geomname = 'LINESTRING' elif geomtype_flatten == QgsWkbTypes.Polygon: geomname = 'POLYGON' elif geomtype_flatten == QgsWkbTypes.MultiPoint: geomname = 'MULTIPOINT' elif geomtype_flatten == QgsWkbTypes.MultiLineString: geomname = 'MULTILINESTRING' elif geomtype_flatten == QgsWkbTypes.MultiPolygon: geomname = 'MULTIPOLYGON' elif geomtype_flatten == QgsWkbTypes.GeometryCollection: geomname = 'GEOMETRYCOLLECTION' elif geomtype_flatten == QgsWkbTypes.CircularString: geomname = 'CIRCULARSTRING' elif geomtype_flatten == QgsWkbTypes.CompoundCurve: geomname = 'COMPOUNDCURVE' elif geomtype_flatten == QgsWkbTypes.CurvePolygon: geomname = 'CURVEPOLYGON' elif geomtype_flatten == QgsWkbTypes.MultiCurve: geomname = 'MULTICURVE' elif geomtype_flatten == QgsWkbTypes.MultiSurface: geomname = 'MULTISURFACE' geomdim = 'XY' if QgsWkbTypes.hasZ(geom_type.wkbType): geomdim += 'Z' if QgsWkbTypes.hasM(geom_type.wkbType): geomdim += 'M' item = [ Table.VectorType, table.tableName(), bool(table.flags() & QgsAbstractDatabaseProviderConnection.View ), # is_view table.tableName(), table.geometryColumn(), geomname, geomdim, srid ] self.mapSridToName[srid] = geom_type.crs.description() else: item = [ Table.TableType, table.tableName(), bool(table.flags() & QgsAbstractDatabaseProviderConnection.View), ] items.append(item) return items
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) fields = source.fields() fields.append(QgsField('node_pos', QVariant.Int)) fields.append(QgsField('node_index', QVariant.Int)) fields.append(QgsField('distance', QVariant.Double)) fields.append(QgsField('angle', QVariant.Double)) fields.append(QgsField('NUM_FIELD', QVariant.Int)) wkb_type = QgsWkbTypes.Point if QgsWkbTypes.hasM(source.wkbType()): wkb_type = QgsWkbTypes.addM(wkb_type) if QgsWkbTypes.hasZ(source.wkbType()): wkb_type = QgsWkbTypes.addZ(wkb_type) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, wkb_type, source.sourceCrs()) node_indices_string = self.parameterAsString(parameters, self.NODES, context) indices = [] for node in node_indices_string.split(','): try: indices.append(int(node)) except: raise QgsProcessingException( self.tr('\'{}\' is not a valid node index').format(node)) features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break input_geometry = f.geometry() if not input_geometry: sink.addFeature(f, QgsFeatureSink.FastInsert) else: total_nodes = input_geometry.geometry().nCoordinates() for node in indices: if node < 0: node_index = total_nodes + node else: node_index = node if node_index < 0 or node_index >= total_nodes: continue distance = input_geometry.distanceToVertex(node_index) angle = math.degrees(input_geometry.angleAtVertex(node_index)) output_feature = QgsFeature() attrs = f.attributes() attrs.append(node) attrs.append(node_index) attrs.append(distance) attrs.append(angle) output_feature.setAttributes(attrs) point = input_geometry.vertexAt(node_index) output_feature.setGeometry(QgsGeometry(point)) 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)) fields = source.fields() fields.append(QgsField('vertex_pos', QVariant.Int)) fields.append(QgsField('vertex_index', QVariant.Int)) fields.append(QgsField('vertex_part', QVariant.Int)) if QgsWkbTypes.geometryType( source.wkbType()) == QgsWkbTypes.PolygonGeometry: fields.append(QgsField('vertex_part_ring', QVariant.Int)) fields.append(QgsField('vertex_part_index', QVariant.Int)) fields.append(QgsField('distance', QVariant.Double)) fields.append(QgsField('angle', QVariant.Double)) wkb_type = QgsWkbTypes.Point if QgsWkbTypes.hasM(source.wkbType()): wkb_type = QgsWkbTypes.addM(wkb_type) if QgsWkbTypes.hasZ(source.wkbType()): wkb_type = QgsWkbTypes.addZ(wkb_type) (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)) vertex_indices_string = self.parameterAsString(parameters, self.VERTICES, context) indices = [] for vertex in vertex_indices_string.split(','): try: indices.append(int(vertex)) except: raise QgsProcessingException( self.tr('\'{}\' is not a valid vertex index').format( vertex)) features = source.getFeatures( QgsFeatureRequest(), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break input_geometry = f.geometry() if not input_geometry: sink.addFeature(f, QgsFeatureSink.FastInsert) else: total_vertices = input_geometry.constGet().nCoordinates() for vertex in indices: if vertex < 0: vertex_index = total_vertices + vertex else: vertex_index = vertex if vertex_index < 0 or vertex_index >= total_vertices: continue (success, vertex_id ) = input_geometry.vertexIdFromVertexNr(vertex_index) distance = input_geometry.distanceToVertex(vertex_index) angle = math.degrees( input_geometry.angleAtVertex(vertex_index)) output_feature = QgsFeature() attrs = f.attributes() attrs.append(vertex) attrs.append(vertex_index) attrs.append(vertex_id.part) if QgsWkbTypes.geometryType( source.wkbType()) == QgsWkbTypes.PolygonGeometry: attrs.append(vertex_id.ring) attrs.append(vertex_id.vertex) attrs.append(distance) attrs.append(angle) output_feature.setAttributes(attrs) point = input_geometry.vertexAt(vertex_index) output_feature.setGeometry(QgsGeometry(point)) 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)) close_path = self.parameterAsBool(parameters, self.CLOSE_PATH, context) group_field_name = self.parameterAsString(parameters, self.GROUP_FIELD, context) order_field_name = self.parameterAsString(parameters, self.ORDER_FIELD, context) order_expression = self.parameterAsString(parameters, self.ORDER_EXPRESSION, 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) if group_field_index >= 0: group_field_def = source.fields().at(group_field_index) else: group_field_def = None if order_field_name: order_expression = QgsExpression.quotedColumnRef(order_field_name) if not order_expression: raise QgsProcessingException( self.tr('ORDER_EXPRESSION parameter is missing.')) expression_context = self.createExpressionContext( parameters, context, source) expression = QgsExpression(order_expression) if expression.hasParserError(): raise QgsProcessingException(expression.parserErrorString()) expression.prepare(expression_context) order_field_type = QVariant.String if expression.isField(): field_name = next(iter(expression.referencedColumns())) order_field_type = source.fields().field(field_name).type() fields = QgsFields() if group_field_def is not None: fields.append(group_field_def) begin_field = QgsField('begin', order_field_type) fields.append(begin_field) end_field = QgsField('end', order_field_type) 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)) if text_dir and not (os.path.exists(text_dir)): raise QgsProcessingException( self.tr("The text output directory does not exist")) points = dict() required_fields = expression.referencedColumns() required_fields.add(group_field_name) features = source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes(required_fields, source.fields()), 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 expression_context.setFeature(f) order = expression.evaluate(expression_context) 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.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 close_path is True: if line[0] != line[-1]: line.append(line[0]) 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): ''' Here is where the processing itself takes place. ''' # if not is_dependencies_satisfied: return {} the_layer = self.parameterAsSource(parameters, self.THE_LAYER, context) if the_layer is None: raise QgsProcessingException(self.invalidSourceError(parameters, self.THE_LAYER)) # fidu_fld = self.parameterAsString(parameters, self.FID_FLD, context) data_fld = self.parameterAsString(parameters, self.DATA_FLD, context) line_fld = self.parameterAsString(parameters, self.LINE_FLD, context) invP = self.parameterAsBool(parameters, self.INVERTP, context) scale = self.parameterAsDouble(parameters, self.SCALE, context) offset = self.parameterAsDouble(parameters, self.OFFSET, context) join_to_line = self.parameterAsBool(parameters, self.JOINL, context) data = the_layer.fields().at(the_layer.fields().lookupField(data_fld)) fidu = the_layer.fields().at(the_layer.fields().lookupField(fidu_fld)) if not data.isNumeric() or not fidu.isNumeric(): raise QgsProcessingException(self.invalidSourceError(parameters, self.THE_LAYER)) line = the_layer.fields().at(the_layer.fields().lookupField(line_fld)) data_ix = the_layer.fields().lookupField(data_fld) line_ix = the_layer.fields().lookupField(line_fld) fidu_ix = the_layer.fields().lookupField(fidu_fld) # Set output vector layer output_wkb = QgsWkbTypes.LineString if QgsWkbTypes.hasM(the_layer.wkbType()): output_wkb = QgsWkbTypes.addM(output_wkb) if QgsWkbTypes.hasZ(the_layer.wkbType()): output_wkb = QgsWkbTypes.addZ(output_wkb) # Keep line into stacked profile vector line_def = the_layer.fields().at(line_ix) fields = QgsFields() if line_def is not None: fields.append(line_def) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, output_wkb, the_layer.sourceCrs()) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) # Get the features and fields of interest features = the_layer.getFeatures(QgsFeatureRequest().setSubsetOfAttributes( [fidu_ix, line_ix, data_ix]), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks) #... #Construct vector layer f = QgsFeature() f.setAttributes([line,]) line_pts = [QgsPoint(x,y) for x,y in zip(px, py)] if join_to_line: # Join profile to its line e = len(ar) - 1 ar0 = [QgsPoint(ar.X[0],ar.Y[0]),] ar1 = [QgsPoint(ar.X[e],ar.Y[e]),] line_pts = ar0 + line_pts + ar1 # f.setGeometry(QgsGeometry(QgsLineString(line_pts))) sink.addFeature(f, QgsFeatureSink.FastInsert)
def validate(self) -> str: layer = self.layer.currentLayer() if not layer: return tr('A layer is mandatory.') upstream = super().validate() if upstream: return upstream wfs_layers_list = QgsProject.instance().readListEntry('WFSLayers', '')[0] for wfs_layer in wfs_layers_list: if layer.id() == wfs_layer: break else: msg = tr( 'The layers you have chosen for this tool must be checked in the "WFS Capabilities"\n' ' option of the QGIS Server tab in the "Project Properties" dialog.' ) return msg create_feature = self.create_feature.isChecked() modify_attribute = self.edit_attributes.isChecked() modify_geometry = self.edit_geometry.isChecked() delete_feature = self.delete_feature.isChecked() if not create_feature and not modify_attribute and not modify_geometry and not delete_feature: return tr('At least one action is mandatory.') # Check Z or M values which will be lost when editing geometry_type = layer.wkbType() # noinspection PyArgumentList has_m_values = QgsWkbTypes.hasM(geometry_type) # noinspection PyArgumentList has_z_values = QgsWkbTypes.hasZ(geometry_type) if has_z_values or has_m_values: QMessageBox.warning( self, tr('Editing Z/M Values'), tr('Be careful, editing this layer with Lizmap will set the Z and M to 0.' ), ) has_snap = self.snap_node.isChecked() or self.snap_segments.isChecked( ) or self.snap_intersection.isChecked() layers = self.layers.selection() if len(layers) == 0 and has_snap: return tr( 'One snapping checkbox is checked, so at least one layer is mandatory in the list.' ) if len(layers) > 0 and not has_snap: return tr( 'One layer is selected in the list, so at least one snapping mode is mandatory.' ) missing_layers = [] for layer in layers: wfs_layers_list = QgsProject.instance().readListEntry( 'WFSLayers', '')[0] for wfs_layer in wfs_layers_list: if layer == wfs_layer: break else: missing_layers.append(layer) if missing_layers: missing_layers = [ QgsProject.instance().mapLayer(layer_id).name() for layer_id in missing_layers ] msg = tr( 'The layer "{}" for the snapping must be checked in the "WFS Capabilities"\n' ' option of the QGIS Server tab in the "Project Properties" dialog.' .format(', '.join(missing_layers))) return msg
def processAlgorithm(self, context, feedback): layer = QgsProcessingUtils.mapLayerFromString( self.getParameterValue(self.INPUT), context) method = self.getParameterValue(self.METHOD) geometryType = layer.geometryType() fields = layer.fields() export_z = False export_m = False if geometryType == QgsWkbTypes.PolygonGeometry: areaName = vector.createUniqueFieldName('area', fields) fields.append(QgsField(areaName, QVariant.Double)) perimeterName = vector.createUniqueFieldName('perimeter', fields) fields.append(QgsField(perimeterName, QVariant.Double)) elif geometryType == QgsWkbTypes.LineGeometry: lengthName = vector.createUniqueFieldName('length', fields) fields.append(QgsField(lengthName, QVariant.Double)) else: xName = vector.createUniqueFieldName('xcoord', fields) fields.append(QgsField(xName, QVariant.Double)) yName = vector.createUniqueFieldName('ycoord', fields) fields.append(QgsField(yName, QVariant.Double)) if QgsWkbTypes.hasZ(layer.wkbType()): export_z = True zName = vector.createUniqueFieldName('zcoord', fields) fields.append(QgsField(zName, QVariant.Double)) if QgsWkbTypes.hasM(layer.wkbType()): export_m = True zName = vector.createUniqueFieldName('mvalue', fields) fields.append(QgsField(zName, QVariant.Double)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, layer.wkbType(), layer.crs(), context) ellips = None crs = None coordTransform = None # Calculate with: # 0 - layer CRS # 1 - project CRS # 2 - ellipsoidal if method == 2: ellips = QgsProject.instance().ellipsoid() crs = layer.crs().srsid() elif method == 1: mapCRS = iface.mapCanvas().mapSettings().destinationCrs() layCRS = layer.crs() coordTransform = QgsCoordinateTransform(layCRS, mapCRS) outFeat = QgsFeature() outFeat.initAttributes(len(fields)) outFeat.setFields(fields) features = QgsProcessingUtils.getFeatures(layer, context) total = 100.0 / QgsProcessingUtils.featureCount(layer, context) for current, f in enumerate(features): inGeom = f.geometry() if method == 1: inGeom.transform(coordTransform) (attr1, attr2) = vector.simpleMeasure(inGeom, method, ellips, crs) outFeat.setGeometry(inGeom) attrs = f.attributes() attrs.append(attr1) if attr2 is not None: attrs.append(attr2) # add point z/m if export_z: attrs.append(inGeom.geometry().z()) if export_m: attrs.append(inGeom.geometry().m()) outFeat.setAttributes(attrs) writer.addFeature(outFeat) feedback.setProgress(int(current * total)) del writer
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) index = self.parameterAsEnum(parameters, self.TYPE, context) if index == 0: newType = QgsWkbTypes.Point elif index == 1: newType = QgsWkbTypes.Point if QgsWkbTypes.hasM(source.wkbType()): newType = QgsWkbTypes.addM(newType) if QgsWkbTypes.hasZ(source.wkbType()): newType = QgsWkbTypes.addZ(newType) elif index == 2: newType = QgsWkbTypes.LineString if QgsWkbTypes.hasM(source.wkbType()): newType = QgsWkbTypes.addM(newType) if QgsWkbTypes.hasZ(source.wkbType()): newType = QgsWkbTypes.addZ(newType) elif index == 3: newType = QgsWkbTypes.MultiLineString if QgsWkbTypes.hasM(source.wkbType()): newType = QgsWkbTypes.addM(newType) if QgsWkbTypes.hasZ(source.wkbType()): newType = QgsWkbTypes.addZ(newType) else: newType = QgsWkbTypes.Polygon if QgsWkbTypes.hasM(source.wkbType()): newType = QgsWkbTypes.addM(newType) if QgsWkbTypes.hasZ(source.wkbType()): newType = QgsWkbTypes.addZ(newType) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, source.fields(), newType, source.sourceCrs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break if not f.hasGeometry(): sink.addFeature(f, QgsFeatureSink.FastInsert) else: for p in self.convertGeometry(f.geometry(), index): feat = QgsFeature() feat.setAttributes(f.attributes()) feat.setGeometry(p) 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, context) fields = source.fields() fields.append(QgsField('node_pos', QVariant.Int)) fields.append(QgsField('node_index', QVariant.Int)) fields.append(QgsField('distance', QVariant.Double)) fields.append(QgsField('angle', QVariant.Double)) fields.append(QgsField('NUM_FIELD', QVariant.Int)) wkb_type = QgsWkbTypes.Point if QgsWkbTypes.hasM(source.wkbType()): wkb_type = QgsWkbTypes.addM(wkb_type) if QgsWkbTypes.hasZ(source.wkbType()): wkb_type = QgsWkbTypes.addZ(wkb_type) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, wkb_type, source.sourceCrs()) node_indices_string = self.parameterAsString(parameters, self.NODES, context) indices = [] for node in node_indices_string.split(','): try: indices.append(int(node)) except: raise QgsProcessingException( self.tr('\'{}\' is not a valid node index').format(node)) features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break input_geometry = f.geometry() if not input_geometry: sink.addFeature(f, QgsFeatureSink.FastInsert) else: total_nodes = input_geometry.geometry().nCoordinates() for node in indices: if node < 0: node_index = total_nodes + node else: node_index = node if node_index < 0 or node_index >= total_nodes: continue distance = input_geometry.distanceToVertex(node_index) angle = math.degrees( input_geometry.angleAtVertex(node_index)) output_feature = QgsFeature() attrs = f.attributes() attrs.append(node) attrs.append(node_index) attrs.append(distance) attrs.append(angle) output_feature.setAttributes(attrs) point = input_geometry.vertexAt(node_index) output_feature.setGeometry(QgsGeometry(point)) 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)) fields = source.fields() fields.append(QgsField('vertex_pos', QVariant.Int)) fields.append(QgsField('vertex_index', QVariant.Int)) fields.append(QgsField('vertex_part', QVariant.Int)) if QgsWkbTypes.geometryType(source.wkbType()) == QgsWkbTypes.PolygonGeometry: fields.append(QgsField('vertex_part_ring', QVariant.Int)) fields.append(QgsField('vertex_part_index', QVariant.Int)) fields.append(QgsField('distance', QVariant.Double)) fields.append(QgsField('angle', QVariant.Double)) wkb_type = QgsWkbTypes.Point if QgsWkbTypes.hasM(source.wkbType()): wkb_type = QgsWkbTypes.addM(wkb_type) if QgsWkbTypes.hasZ(source.wkbType()): wkb_type = QgsWkbTypes.addZ(wkb_type) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, wkb_type, source.sourceCrs(), QgsFeatureSink.RegeneratePrimaryKey) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) vertex_indices_string = self.parameterAsString(parameters, self.VERTICES, context) indices = [] for vertex in vertex_indices_string.split(','): try: indices.append(int(vertex)) except: raise QgsProcessingException( self.tr('\'{}\' is not a valid vertex index').format(vertex)) features = source.getFeatures(QgsFeatureRequest(), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break input_geometry = f.geometry() if not input_geometry: sink.addFeature(f, QgsFeatureSink.FastInsert) else: total_vertices = input_geometry.constGet().nCoordinates() for vertex in indices: if vertex < 0: vertex_index = total_vertices + vertex else: vertex_index = vertex if vertex_index < 0 or vertex_index >= total_vertices: continue (success, vertex_id) = input_geometry.vertexIdFromVertexNr(vertex_index) distance = input_geometry.distanceToVertex(vertex_index) angle = math.degrees(input_geometry.angleAtVertex(vertex_index)) output_feature = QgsFeature() attrs = f.attributes() attrs.append(vertex) attrs.append(vertex_index) attrs.append(vertex_id.part) if QgsWkbTypes.geometryType(source.wkbType()) == QgsWkbTypes.PolygonGeometry: attrs.append(vertex_id.ring) attrs.append(vertex_id.vertex) attrs.append(distance) attrs.append(angle) output_feature.setAttributes(attrs) point = input_geometry.vertexAt(vertex_index) output_feature.setGeometry(QgsGeometry(point)) 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)) 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) mvalue_exp = self.parameterAsExpression(parameters, self.MVALUE_EXPRESSION, context) text_dir = self.parameterAsString(parameters, self.OUTPUT_TEXT_DIR, context) QgsMessageLog.logMessage("-"*80) QgsMessageLog.logMessage(str(mvalue_exp)) QgsMessageLog.logMessage(mvalue_exp.__class__.__name__) # instantiate the expression if mvalue is set if mvalue_exp: expression = QgsExpression(mvalue_exp) expression_ctx = self.createExpressionContext(parameters, context) expression.prepare(expression_ctx) else: expression = None 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()) or mvalue_exp: 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() referencedColumns = expression.referencedAttributeIndexes(source.fields()) if expression else [group_field_index, order_field_index] features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes(referencedColumns), 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, f)) else: points[group] = [(order, point, f)] 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)) linestring = QgsLineString(line) if mvalue_exp: linestring.addMValue(0) for i, node in enumerate(vertices): QgsMessageLog.logMessage(node[2].__class__.__name__) expression_ctx.setFeature(node[2]) mvalue = expression.evaluate(expression_ctx) if expression.hasEvalError(): raise QgsProcessingException( self.tr('Evaluation error: {0}').format(expression.evalErrorString())) QgsMessageLog.logMessage("evaluating mvalue at {} to {} {}".format(i, mvalue, mvalue.__class__)) # mvalue = 12 # TODO : remove QgsMessageLog.logMessage("setting mvalue at {} to {} {}".format(i, mvalue, mvalue.__class__)) linestring.setMAt(i, mvalue) # test = linestring.mAt(i) # TODO : remove # QgsMessageLog.logMessage("mvalue at {} is {} {}".format(i, test, test.__class__)) # TODO : remove f.setGeometry(QgsGeometry(linestring)) 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)) 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) 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)) 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()) 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()) self.distance_area.setEllipsoid(context.project().ellipsoid()) elif method == 1: coordTransform = QgsCoordinateTransform(source.sourceCrs(), context.project().crs()) 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)) outFeat.setAttributes(attrs) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT)) method = self.getParameterValue(self.METHOD) geometryType = layer.geometryType() fields = layer.fields() export_z = False export_m = False if geometryType == QgsWkbTypes.PolygonGeometry: areaName = vector.createUniqueFieldName('area', fields) fields.append(QgsField(areaName, QVariant.Double)) perimeterName = vector.createUniqueFieldName('perimeter', fields) fields.append(QgsField(perimeterName, QVariant.Double)) elif geometryType == QgsWkbTypes.LineGeometry: lengthName = vector.createUniqueFieldName('length', fields) fields.append(QgsField(lengthName, QVariant.Double)) else: xName = vector.createUniqueFieldName('xcoord', fields) fields.append(QgsField(xName, QVariant.Double)) yName = vector.createUniqueFieldName('ycoord', fields) fields.append(QgsField(yName, QVariant.Double)) if QgsWkbTypes.hasZ(layer.wkbType()): export_z = True zName = vector.createUniqueFieldName('zcoord', fields) fields.append(QgsField(zName, QVariant.Double)) if QgsWkbTypes.hasM(layer.wkbType()): export_m = True zName = vector.createUniqueFieldName('mvalue', fields) fields.append(QgsField(zName, QVariant.Double)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields.toList(), layer.wkbType(), layer.crs()) ellips = None crs = None coordTransform = None # Calculate with: # 0 - layer CRS # 1 - project CRS # 2 - ellipsoidal if method == 2: ellips = QgsProject.instance().readEntry('Measure', '/Ellipsoid', 'NONE')[0] crs = layer.crs().srsid() elif method == 1: mapCRS = iface.mapCanvas().mapSettings().destinationCrs() layCRS = layer.crs() coordTransform = QgsCoordinateTransform(layCRS, mapCRS) outFeat = QgsFeature() inGeom = QgsGeometry() outFeat.initAttributes(len(fields)) outFeat.setFields(fields) features = vector.features(layer) total = 100.0 / len(features) for current, f in enumerate(features): inGeom = f.geometry() if method == 1: inGeom.transform(coordTransform) (attr1, attr2) = vector.simpleMeasure(inGeom, method, ellips, crs) outFeat.setGeometry(inGeom) attrs = f.attributes() attrs.append(attr1) if attr2 is not None: attrs.append(attr2) # add point z/m if export_z: attrs.append(inGeom.geometry().z()) if export_m: attrs.append(inGeom.geometry().m()) outFeat.setAttributes(attrs) writer.addFeature(outFeat) progress.setPercentage(int(current * total)) del writer
def processAlgorithm(self, parameters, context, model_feedback): feedback = QgsProcessingMultiStepFeedback(2, model_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) group_field_index = source.fields().lookupField(group_field_name) order_field_index = source.fields().lookupField(order_field_name) field_names = self.parameterAsFields(parameters, self.FIELDS, context) 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) #Create output for lines fields = QgsFields() self.addFields(source, fields, 'start_order', field_names, order_field_def) self.addFields(source, fields, 'end_order', field_names, order_field_def) fields.append(QgsField('COUNT', QVariant.LongLong)) 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) (self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LINE, context, fields, output_wkb, source.sourceCrs()) if self.sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT_LINE)) #Create output for Points fields_point = QgsFields() fields_point.append(QgsField("fid", QVariant.Int, "int", 9, 0)) self.addFields(source, fields_point, 'end_order', field_names) fields_point.append(QgsField("COUNT", QVariant.LongLong)) fields_point.append(QgsField("COUNT_IN", QVariant.LongLong)) fields_point.append(QgsField("COUNT_OUT", QVariant.LongLong)) (self.sink_point, self.dest_id_point) = self.parameterAsSink( parameters, self.OUTPUT_POINT, context, fields_point, source.wkbType(), source.sourceCrs(), QgsFeatureSink.RegeneratePrimaryKey) if self.sink_point is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT_POINT)) #Compute the lines points = dict() features = source.getFeatures( QgsFeatureRequest(), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): return {} if not f.hasGeometry(): continue point = f.geometry().asPoint() if group_field_index >= 0: group = f[group_field_index] else: group = 1 order = f[order_field_index] if date_format != '': if isinstance(order, QDateTime): pass else: try: order = datetime.strptime(str(order), date_format) except ValueError as ve: feedback.reportError( self.tr('Invalid format {}').format(ve)) return {} data = [order, point] for indice in self.field_indices: data.append(f[indice]) if group in points: points[group].append(data) else: points[group] = [data] feedback.setProgress(int(current * total)) feedback.setCurrentStep(1) #Create the features current = 0 total = 100.0 / len(points) if points else 1 edge_ids = {} end_points = {} self.point_id = 0 for group, vertices in points.items(): if feedback.isCanceled(): return {} feedback.setProgress(int(current * total)) # log("attrs: {}".format(vertices)) vertices.sort(key=lambda x: (x[0] is None, x[0])) for i in range(len(vertices) - 1): if feedback.isCanceled(): return {} start_id = vertices[i][1].asWkt() end_id = vertices[i + 1][1].asWkt() edge_id = start_id + "-" + end_id if edge_id in edge_ids: f = edge_ids[edge_id] count_index = 2 * (len(self.field_indices) + 1) count = f.attribute(count_index) + 1 f.setAttribute(count_index, count) else: f = QgsFeature() attrs = [] attrs.append(vertices[i][0]) #Add Order begin for j in range(len( self.field_indices)): #Add Attrs for begin attrs.append( vertices[i][j + 2]) # +2 ignore order and point attrs.append(vertices[i + 1][0]) #Add Order end for j in range(0, len( self.field_indices)): #Add Attrs for end attrs.append( vertices[i + 1][j + 2]) # +2 ignore order and point attrs.append(1) #Count = 1 f.setAttributes(attrs) line = [vertices[i][1], vertices[i + 1][1]] geom = QgsGeometry() f.setGeometry(QgsGeometry(geom.fromPolylineXY(line))) edge_ids[edge_id] = f self.updatePoints(start_id, end_points, vertices[i], 'start') self.updatePoints(end_id, end_points, vertices[i + 1], 'end') current += 1 feedback.setProgress(int(current * total)) for id in edge_ids: if feedback.isCanceled(): return {} self.sink.addFeature(edge_ids[id], QgsFeatureSink.FastInsert) for id in end_points: if feedback.isCanceled(): return {} self.sink_point.addFeature(end_points[id], QgsFeatureSink.FastInsert) return {self.OUTPUT_LINE: self.dest_id}
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) group_field_name = self.parameterAsString(parameters, self.GROUP_FIELD, context) order_field_name = self.parameterAsString(parameters, self.ORDER_FIELD, context) date_format = self.parameterAsString(parameters, self.DATE_FORMAT, context) text_dir = self.parameterAsString(parameters, self.OUTPUT_TEXT_DIR, context) group_field_index = source.fields().lookupField(group_field_name) order_field_index = source.fields().lookupField(order_field_name) if group_field_index >= 0: group_field_def = source.fields().at(group_field_index) else: group_field_def = None order_field_def = source.fields().at(order_field_index) fields = QgsFields() if group_field_def is not None: fields.append(group_field_def) begin_field = QgsField(order_field_def) begin_field.setName('begin') fields.append(begin_field) end_field = QgsField(order_field_def) end_field.setName('end') fields.append(end_field) output_wkb = QgsWkbTypes.LineString if QgsWkbTypes.hasM(source.wkbType()): output_wkb = QgsWkbTypes.addM(output_wkb) if QgsWkbTypes.hasZ(source.wkbType()): output_wkb = QgsWkbTypes.addZ(output_wkb) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, output_wkb, source.sourceCrs()) points = dict() features = source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes( [group_field_index, order_field_index])) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break if not f.hasGeometry(): continue point = f.geometry().constGet().clone() if group_field_index >= 0: group = f.attributes()[group_field_index] else: group = 1 order = f.attributes()[order_field_index] if date_format != '': order = datetime.strptime(str(order), date_format) if group in points: points[group].append((order, point)) else: points[group] = [(order, point)] feedback.setProgress(int(current * total)) feedback.setProgress(0) da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs(), context.transformContext()) da.setEllipsoid(context.project().ellipsoid()) current = 0 total = 100.0 / len(points) if points else 1 for group, vertices in list(points.items()): if feedback.isCanceled(): break vertices.sort() f = QgsFeature() attributes = [] if group_field_index >= 0: attributes.append(group) attributes.extend([vertices[0][0], vertices[-1][0]]) f.setAttributes(attributes) line = [node[1] for node in vertices] if text_dir: fileName = os.path.join(text_dir, '%s.txt' % group) with open(fileName, 'w') as fl: fl.write('angle=Azimuth\n') fl.write('heading=Coordinate_System\n') fl.write('dist_units=Default\n') for i in range(len(line)): if i == 0: fl.write('startAt=%f;%f;90\n' % (line[i].x(), line[i].y())) fl.write('survey=Polygonal\n') fl.write('[data]\n') else: angle = line[i - 1].azimuth(line[i]) distance = da.measureLine(QgsPointXY(line[i - 1]), QgsPointXY(line[i])) fl.write('%f;%f;90\n' % (angle, distance)) f.setGeometry(QgsGeometry(QgsLineString(line))) sink.addFeature(f, QgsFeatureSink.FastInsert) current += 1 feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def __setlayerproperties(self): self.__layergeometryType = self.__layer.geometryType() self.__layerwkbType = self.__layer.wkbType() self.__hasZ = QgsWkbTypes.hasZ(self.__layerwkbType) self.__hasM = QgsWkbTypes.hasM(self.__layerwkbType) self.__isMultiType = QgsWkbTypes.isMultiType(self.__layerwkbType)
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 supportInPlaceEdit(self, layer): return super().supportInPlaceEdit(layer) and QgsWkbTypes.hasM( layer.wkbType())
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 make_features_compatible(new_features, input_layer): """Try to make the new features compatible with old features by: - converting single to multi part - dropping additional attributes - adding back M/Z values - drop Z/M - convert multi part to single part :param new_features: new features :type new_features: list of QgsFeatures :param input_layer: input layer :type input_layer: QgsVectorLayer :return: modified features :rtype: list of QgsFeatures """ input_wkb_type = input_layer.wkbType() result_features = [] for new_f in new_features: # Fix attributes if new_f.fields().count() > 0: attributes = [] for field in input_layer.fields(): if new_f.fields().indexFromName(field.name()) >= 0: attributes.append(new_f[field.name()]) else: attributes.append(None) f = QgsFeature(input_layer.fields()) f.setAttributes(attributes) f.setGeometry(new_f.geometry()) new_f = f else: lendiff = len(new_f.attributes()) - len(input_layer.fields()) if lendiff > 0: f = QgsFeature(input_layer.fields()) f.setGeometry(new_f.geometry()) f.setAttributes(new_f.attributes()[:len(input_layer.fields())]) new_f = f elif lendiff < 0: f = QgsFeature(input_layer.fields()) f.setGeometry(new_f.geometry()) attributes = new_f.attributes() + [ None for i in range(-lendiff) ] f.setAttributes(attributes) new_f = f # Check if we need geometry manipulation new_f_geom_type = QgsWkbTypes.geometryType(new_f.geometry().wkbType()) new_f_has_geom = new_f_geom_type not in (QgsWkbTypes.UnknownGeometry, QgsWkbTypes.NullGeometry) input_layer_has_geom = input_wkb_type not in (QgsWkbTypes.NoGeometry, QgsWkbTypes.Unknown) # Drop geometry if layer is geometry-less if not input_layer_has_geom and new_f_has_geom: f = QgsFeature(input_layer.fields()) f.setAttributes(new_f.attributes()) new_f = f result_features.append(new_f) continue # skip the rest if input_layer_has_geom and new_f_has_geom and \ new_f.geometry().wkbType() != input_wkb_type: # Fix geometry # Single -> Multi if (QgsWkbTypes.isMultiType(input_wkb_type) and not new_f.geometry().isMultipart()): new_geom = new_f.geometry() new_geom.convertToMultiType() new_f.setGeometry(new_geom) # Drop Z/M if (new_f.geometry().constGet().is3D() and not QgsWkbTypes.hasZ(input_wkb_type)): new_geom = new_f.geometry() new_geom.get().dropZValue() new_f.setGeometry(new_geom) if (new_f.geometry().constGet().isMeasure() and not QgsWkbTypes.hasM(input_wkb_type)): new_geom = new_f.geometry() new_geom.get().dropMValue() new_f.setGeometry(new_geom) # Add Z/M back (set it to 0) if (not new_f.geometry().constGet().is3D() and QgsWkbTypes.hasZ(input_wkb_type)): new_geom = new_f.geometry() new_geom.get().addZValue(0.0) new_f.setGeometry(new_geom) if (not new_f.geometry().constGet().isMeasure() and QgsWkbTypes.hasM(input_wkb_type)): new_geom = new_f.geometry() new_geom.get().addMValue(0.0) new_f.setGeometry(new_geom) # Multi -> Single if (not QgsWkbTypes.isMultiType(input_wkb_type) and new_f.geometry().isMultipart()): g = new_f.geometry() g2 = g.constGet() for i in range(g2.partCount()): # Clone or crash! g4 = QgsGeometry(g2.geometryN(i).clone()) f = QgsVectorLayerUtils.createFeature( input_layer, g4, { i: new_f.attribute(i) for i in range(new_f.fields().count()) }) result_features.append(f) else: result_features.append(new_f) else: result_features.append(new_f) return result_features