Example #1
0
    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}
Example #2
0
    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
Example #3
0
    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
Example #4
0
    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
Example #5
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_LAYER))
        layerType = self.getParameterValue(self.LAYER_TYPE)
        method = self.getParameterValue(self.METHOD)
        columns = self.getParameterValue(self.COLUMNS)
        rows = self.getParameterValue(self.ROWS)
        cellsizeX = self.getParameterValue(self.CELLSIZE_X)
        cellsizeY = self.getParameterValue(self.CELLSIZE_Y)
        extent = self.getParameterValue(self.EXTENT).split(',')
        output = self.getOutputValue(self.OUTPUT_LAYER)
        triangulation = self.getOutputValue(self.TRIANULATION_FILE)

        if not QgsWkbTypes.hasZ(layer.wkbType()):
            raise GeoAlgorithmExecutionException(
                self.tr('Geometries in input layer does not have Z coordinates.'))

        xMin = float(extent[0])
        xMax = float(extent[1])
        yMin = float(extent[2])
        yMax = float(extent[3])
        bbox = QgsRectangle(xMin, yMin, xMax, yMax)

        layerData = QgsInterpolator.LayerData()
        layerData.vectorLayer = layer
        layerData.zCoordInterpolation = True
        layerData.interpolationAttribute = -1

        if layerType == 0:
            layerData.mInputType = QgsInterpolator.POINTS
        elif layerType == 1:
            layerData.mInputType = QgsInterpolator.STRUCTURE_LINES
        else:
            layerData.mInputType = QgsInterpolator.BREAK_LINES

        if method == 0:
            interpolationMethod = QgsTINInterpolator.Linear
        else:
            interpolationMethod = QgsTINInterpolator.CloughTocher

        interpolator = QgsTINInterpolator([layerData], interpolationMethod)
        interpolator.setExportTriangulationToFile(True)
        interpolator.setTriangulationFilePath(triangulation)

        writer = QgsGridFileWriter(interpolator,
                                   output,
                                   bbox,
                                   columns,
                                   rows,
                                   cellsizeX,
                                   cellsizeY)

        writer.writeFile()
Example #6
0
    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
Example #7
0
    def processFeature(self, feature, feedback):
        input_geometry = feature.geometry()
        if input_geometry:
            new_geom = input_geometry.geometry().clone()
            if QgsWkbTypes.hasZ(new_geom.wkbType()):
                # addZValue won't alter existing Z values, so drop them first
                new_geom.dropZValue()

            new_geom.addZValue(self.z_value)

            feature.setGeometry(QgsGeometry(new_geom))

        return feature
Example #8
0
    def on_cmbLayers_layerChanged(self, layer):
        self.chkUseZCoordinate.setEnabled(False)

        if layer is None or not layer.isValid():
            return

        provider = layer.dataProvider()
        if not provider:
            return

        if QgsWkbTypes.hasZ(provider.wkbType()):
            self.chkUseZCoordinate.setEnabled(True)

        self.cmbFields.setLayer(layer)
Example #9
0
    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)
Example #11
0
    def processFeature(self, feature, context, feedback):
        input_geometry = feature.geometry()
        if input_geometry:
            new_geom = input_geometry.constGet().clone()
            if QgsWkbTypes.hasZ(new_geom.wkbType()):
                # addZValue won't alter existing Z values, so drop them first
                new_geom.dropZValue()

            z = self.z_value
            if self.dynamic_z:
                z, ok = self.z_property.valueAsDouble(context.expressionContext(), z)
            new_geom.addZValue(z)

            feature.setGeometry(QgsGeometry(new_geom))

        return [feature]
Example #12
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_LAYER))
        layerType = self.getParameterValue(self.LAYER_TYPE)
        coefficient = self.getParameterValue(self.DISTANCE_COEFFICIENT)
        columns = self.getParameterValue(self.COLUMNS)
        rows = self.getParameterValue(self.ROWS)
        cellsizeX = self.getParameterValue(self.CELLSIZE_X)
        cellsizeY = self.getParameterValue(self.CELLSIZE_Y)
        extent = self.getParameterValue(self.EXTENT).split(',')
        output = self.getOutputValue(self.OUTPUT_LAYER)

        if not QgsWkbTypes.hasZ(layer.wkbType()):
            raise GeoAlgorithmExecutionException(
                self.tr('Geometries in input layer does not have Z coordinates.'))

        xMin = float(extent[0])
        xMax = float(extent[1])
        yMin = float(extent[2])
        yMax = float(extent[3])
        bbox = QgsRectangle(xMin, yMin, xMax, yMax)

        layerData = QgsInterpolator.LayerData()
        layerData.vectorLayer = layer
        layerData.zCoordInterpolation = True
        layerData.interpolationAttribute = -1

        if layerType == 0:
            layerData.mInputType = QgsInterpolator.POINTS
        elif layerType == 1:
            layerData.mInputType = QgsInterpolator.STRUCTURE_LINES
        else:
            layerData.mInputType = QgsInterpolator.BREAK_LINES

        interpolator = QgsIDWInterpolator([layerData])
        interpolator.setDistanceCoefficient(coefficient)

        writer = QgsGridFileWriter(interpolator,
                                   output,
                                   bbox,
                                   columns,
                                   rows,
                                   cellsizeX,
                                   cellsizeY)

        writer.writeFile()
Example #13
0
    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}
Example #14
0
 def supportInPlaceEdit(self, layer):
     return super().supportInPlaceEdit(layer) and QgsWkbTypes.hasZ(
         layer.wkbType())
Example #15
0
    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
Example #16
0
 def _get_non_z_geom_type(geom_type: QgsWkbTypes):
     if not QgsWkbTypes.hasZ(geom_type):
         return geom_type
     else:
         return QgsWkbTypes.dropZ(geom_type)
Example #17
0
    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
Example #18
0
    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 __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)
Example #20
0
    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}
Example #21
0
 def supportInPlaceEdit(self, layer):
     return super().supportInPlaceEdit(layer) and QgsWkbTypes.hasZ(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))

        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}
Example #23
0
    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}
Example #24
0
    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:
            if QgsWkbTypes.isMultiType(source.wkbType()):
                new_fields.append(QgsField('numparts', QVariant.Int))
            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}
Example #25
0
    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}
Example #26
0
    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
Example #27
0
    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}
Example #28
0
    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())
        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}
Example #29
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        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())

        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()
        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}
Example #30
0
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
Example #31
0
    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}
Example #32
0
    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}
Example #33
0
    def processAlgorithm(self, parameters, context, feedback):

        source = self.parameterAsSource(parameters, self.INPUT, context)

        fcount = source.featureCount()
        source_fields = source.fields()

        hasZ = QgsWkbTypes.hasZ(source.wkbType())

        if not hasZ:
            raise QgsProcessingException(
                self.
                tr('The layer does not have Z values. If you have a DEM, use the Drape algorithm to extract Z values.'
                   ))

        thefields = QgsFields()
        climbindex = -1
        descentindex = -1
        minelevindex = -1
        maxelevindex = -1
        fieldnumber = 0

        # Create new fields for climb and descent
        thefields.append(QgsField(self.CLIMBATTRIBUTE, QVariant.Double))
        thefields.append(QgsField(self.DESCENTATTRIBUTE, QVariant.Double))
        thefields.append(QgsField(self.MINELEVATTRIBUTE, QVariant.Double))
        thefields.append(QgsField(self.MAXELEVATTRIBUTE, QVariant.Double))

        # combine all the vector fields
        out_fields = QgsProcessingUtils.combineFields(thefields, source_fields)

        layerwithz = source

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, out_fields,
                                               layerwithz.wkbType(),
                                               source.sourceCrs())

        # get features from source (with z values)
        features = layerwithz.getFeatures()
        totalclimb = 0
        totaldescent = 0
        minelevation = float('Infinity')
        maxelevation = float('-Infinity')

        no_z_nodes = []
        no_geometry = []

        for current, feature in enumerate(features):
            if feedback.isCanceled():
                break
            climb = 0
            descent = 0
            minelev = float('Infinity')
            maxelev = float('-Infinity')
            # In case of multigeometries we need to do the parts
            parts = feature.geometry().constParts()
            partnumber = 0
            if not feature.hasGeometry():
                no_geometry.append(
                    self.tr('Feature: {feature_id}'.format(
                        feature_id=feature.id())))
            for part in parts:
                # Calculate the climb
                first = True
                zval = 0
                for idx, v in enumerate(part.vertices()):
                    zval = v.z()
                    if math.isnan(zval):
                        no_z_nodes.append(
                            self.
                            tr('Feature: {feature_id}, part: {part_id}, point: {point_id}'
                               .format(feature_id=feature.id(),
                                       part_id=partnumber,
                                       point_id=idx)))
                        continue
                    if first:
                        prevz = zval
                        minelev = zval
                        maxelev = zval
                        first = False
                    else:
                        diff = zval - prevz
                        if diff > 0:
                            climb = climb + diff
                        else:
                            descent = descent - diff
                        if minelev > zval:
                            minelev = zval
                        if maxelev < zval:
                            maxelev = zval
                    prevz = zval
                totalclimb = totalclimb + climb
                totaldescent = totaldescent + descent
                partnumber += 1
            # Set the attribute values
            attrs = []
            # Append the attributes to the end of the existing ones
            attrs.append(climb)
            attrs.append(descent)
            attrs.append(minelev)
            attrs.append(maxelev)
            attrs.extend(feature.attributes())

            # Set the final attribute list
            feature.setAttributes(attrs)
            # Add a feature to the sink
            sink.addFeature(feature, QgsFeatureSink.FastInsert)
            if minelevation > minelev:
                minelevation = minelev
            if maxelevation < maxelev:
                maxelevation = maxelev
            # Update the progress bar
            if fcount > 0:
                feedback.setProgress(int(100 * current / fcount))

        feedback.pushInfo(
            self.
            tr('The following features do not have geometry: {no_geometry_report}'
               .format(no_geometry_report=(', '.join(no_geometry)))))

        feedback.pushInfo(
            self.tr('The following points do not have Z values: {no_z_report}'.
                    format(no_z_report=(', '.join(no_z_nodes)))))
        # Return the results
        return {
            self.OUTPUT: dest_id,
            self.TOTALCLIMB: totalclimb,
            self.TOTALDESCENT: totaldescent,
            self.MINELEVATION: minelevation,
            self.MAXELEVATION: maxelevation
        }
Example #34
0
    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}
Example #35
0
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