Example #1
0
 def outputWkbType(self, inputWkb):
     wkb = inputWkb
     if self.drop_m:
         wkb = QgsWkbTypes.dropM(wkb)
     if self.drop_z:
         wkb = QgsWkbTypes.dropZ(wkb)
     return wkb
Example #2
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)

        fields = source.fields()
        x_field_index = fields.lookupField(self.parameterAsString(parameters, self.XFIELD, context))
        y_field_index = fields.lookupField(self.parameterAsString(parameters, self.YFIELD, context))
        z_field_index = -1
        if self.parameterAsString(parameters, self.ZFIELD, context):
            z_field_index = fields.lookupField(self.parameterAsString(parameters, self.ZFIELD, context))
        m_field_index = -1
        if self.parameterAsString(parameters, self.MFIELD, context):
            m_field_index = fields.lookupField(self.parameterAsString(parameters, self.MFIELD, context))

        wkb_type = QgsWkbTypes.Point
        if z_field_index >= 0:
            wkb_type = QgsWkbTypes.addZ(wkb_type)
        if m_field_index >= 0:
            wkb_type = QgsWkbTypes.addM(wkb_type)

        target_crs = self.parameterAsCrs(parameters, self.TARGET_CRS, context)

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               fields, wkb_type, target_crs)

        request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry)
        features = source.getFeatures()
        total = 100.0 / source.featureCount() if source.featureCount() else 0

        for current, feature in enumerate(features):
            if feedback.isCanceled():
                break

            feedback.setProgress(int(current * total))
            attrs = feature.attributes()

            try:
                x = float(attrs[x_field_index])
                y = float(attrs[y_field_index])

                point = QgsPoint(x, y)

                if z_field_index >= 0:
                    try:
                        point.addZValue(float(attrs[z_field_index]))
                    except:
                        point.addZValue(0.0)

                if m_field_index >= 0:
                    try:
                        point.addMValue(float(attrs[m_field_index]))
                    except:
                        point.addMValue(0.0)

                feature.setGeometry(QgsGeometry(point))
            except:
                pass  # no geometry

            sink.addFeature(feature)

        return {self.OUTPUT: dest_id}
Example #3
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_LAYER))

        geometry_type = self.getParameterValue(self.OUTPUT_GEOMETRY)
        wkb_type = None
        if geometry_type == 0:
            wkb_type = QgsWkbTypes.Polygon
        elif geometry_type == 1:
            wkb_type = QgsWkbTypes.LineString
        else:
            wkb_type = QgsWkbTypes.Point
        if self.getParameterValue(self.WITH_Z):
            wkb_type = QgsWkbTypes.addZ(wkb_type)
        if self.getParameterValue(self.WITH_M):
            wkb_type = QgsWkbTypes.addM(wkb_type)

        writer = self.getOutputFromName(
            self.OUTPUT_LAYER).getVectorWriter(
                layer.fields(),
                wkb_type,
                layer.crs())

        expression = QgsExpression(self.getParameterValue(self.EXPRESSION))
        if expression.hasParserError():
            raise GeoAlgorithmExecutionException(expression.parserErrorString())

        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(QgsExpressionContextUtils.projectScope())
        exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer))

        if not expression.prepare(exp_context):
            raise GeoAlgorithmExecutionException(
                self.tr('Evaluation error: %s' % expression.evalErrorString()))

        features = vector.features(layer)
        total = 100.0 / len(features)
        for current, input_feature in enumerate(features):
            output_feature = input_feature

            exp_context.setFeature(input_feature)
            value = expression.evaluate(exp_context)
            if expression.hasEvalError():
                raise GeoAlgorithmExecutionException(
                    self.tr('Evaluation error: %s' % expression.evalErrorString()))

            if not value:
                output_feature.setGeometry(QgsGeometry())
            else:
                if not isinstance(value, QgsGeometry):
                    raise GeoAlgorithmExecutionException(
                        self.tr('{} is not a geometry').format(value))
                output_feature.setGeometry(value)

            writer.addFeature(output_feature)
            progress.setPercentage(int(current * total))

        del writer
Example #4
0
    def processAlgorithm(self, progress):
        source = self.getParameterValue(self.INPUT)
        vlayer = dataobjects.getObjectFromUri(source)
        output = self.getOutputFromName(self.OUTPUT)

        fields = vlayer.fields()
        x_field_index = fields.lookupField(self.getParameterValue(self.XFIELD))
        y_field_index = fields.lookupField(self.getParameterValue(self.YFIELD))
        z_field_index = None
        if self.getParameterValue(self.ZFIELD):
            z_field_index = fields.lookupField(self.getParameterValue(self.ZFIELD))
        m_field_index = None
        if self.getParameterValue(self.MFIELD):
            m_field_index = fields.lookupField(self.getParameterValue(self.MFIELD))

        wkb_type = QgsWkbTypes.Point
        if z_field_index is not None:
            wkb_type = QgsWkbTypes.addZ(wkb_type)
        if m_field_index is not None:
            wkb_type = QgsWkbTypes.addM(wkb_type)

        crsId = self.getParameterValue(self.TARGET_CRS)
        target_crs = QgsCoordinateReferenceSystem()
        target_crs.createFromUserInput(crsId)

        writer = output.getVectorWriter(fields, wkb_type, target_crs)

        features = vector.features(vlayer)
        total = 100.0 / len(features)

        for current, feature in enumerate(features):
            progress.setPercentage(int(current * total))
            attrs = feature.attributes()

            try:
                x = float(attrs[x_field_index])
                y = float(attrs[y_field_index])

                point = QgsPointV2(x, y)

                if z_field_index is not None:
                    try:
                        point.addZValue(float(attrs[z_field_index]))
                    except:
                        point.addZValue(0.0)

                if m_field_index is not None:
                    try:
                        point.addMValue(float(attrs[m_field_index]))
                    except:
                        point.addMValue(0.0)

                feature.setGeometry(QgsGeometry(point))
            except:
                pass  # no geometry

            writer.addFeature(feature)

        del writer
Example #5
0
    def processAlgorithm(self, progress):
        vlayerA = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT))
        vlayerB = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT2))

        geomType = QgsWkbTypes.multiType(vlayerA.wkbType())
        fields = vector.combineVectorFields(vlayerA, vlayerB)
        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields,
                                                                     geomType, vlayerA.crs())
        outFeat = QgsFeature()
        index = vector.spatialindex(vlayerB)
        selectionA = vector.features(vlayerA)
        total = 100.0 / len(selectionA)
        for current, inFeatA in enumerate(selectionA):
            progress.setPercentage(int(current * total))
            geom = inFeatA.geometry()
            atMapA = inFeatA.attributes()
            intersects = index.intersects(geom.boundingBox())
            request = QgsFeatureRequest().setFilterFids(intersects)

            engine = None
            if len(intersects) > 0:
                # use prepared geometries for faster intersection tests
                engine = QgsGeometry.createGeometryEngine(geom.geometry())
                engine.prepareGeometry()

            for inFeatB in vlayerB.getFeatures(request):
                tmpGeom = inFeatB.geometry()
                if engine.intersects(tmpGeom.geometry()):
                    atMapB = inFeatB.attributes()
                    int_geom = QgsGeometry(geom.intersection(tmpGeom))
                    if int_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(int_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection:
                        int_com = geom.combine(tmpGeom)
                        int_geom = QgsGeometry()
                        if int_com:
                            int_sym = geom.symDifference(tmpGeom)
                            int_geom = QgsGeometry(int_com.difference(int_sym))
                    if int_geom.isGeosEmpty() or not int_geom.isGeosValid():
                        ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                               self.tr('GEOS geoprocessing error: One or '
                                                       'more input features have invalid '
                                                       'geometry.'))
                    try:
                        if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]:
                            outFeat.setGeometry(int_geom)
                            attrs = []
                            attrs.extend(atMapA)
                            attrs.extend(atMapB)
                            outFeat.setAttributes(attrs)
                            writer.addFeature(outFeat)
                    except:
                        ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
                                               self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
                        continue

        del writer
Example #6
0
 def _setRubberBandMarker(self, geom):
     m = QgsRubberBand(self.qgisIface.mapCanvas(), False)  # not polygon
     if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.LineGeometry:
         linegeom = geom
     elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PolygonGeometry:
         linegeom = QgsGeometry.fromPolylineXY(geom.asPolygon()[0])
     m.setToGeometry(linegeom, None)
     m.setColor(QColor(self.config['rubber_color']))
     m.setWidth(self.config['rubber_width'])
     return m
Example #7
0
    def processAlgorithm(self, parameters, context, feedback):
        vlayerA = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context)
        vlayerB = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT2), context)

        geomType = QgsWkbTypes.multiType(vlayerA.wkbType())
        fields = vector.combineVectorFields(vlayerA, vlayerB)
        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, geomType, vlayerA.crs(), context)
        outFeat = QgsFeature()
        index = QgsProcessingUtils.createSpatialIndex(vlayerB, context)
        selectionA = QgsProcessingUtils.getFeatures(vlayerA, context)
        total = 100.0 / vlayerA.featureCount() if vlayerA.featureCount() else 0
        for current, inFeatA in enumerate(selectionA):
            feedback.setProgress(int(current * total))
            geom = inFeatA.geometry()
            atMapA = inFeatA.attributes()
            intersects = index.intersects(geom.boundingBox())
            request = QgsFeatureRequest().setFilterFids(intersects)

            engine = None
            if len(intersects) > 0:
                # use prepared geometries for faster intersection tests
                engine = QgsGeometry.createGeometryEngine(geom.geometry())
                engine.prepareGeometry()

            for inFeatB in vlayerB.getFeatures(request):
                tmpGeom = inFeatB.geometry()
                if engine.intersects(tmpGeom.geometry()):
                    atMapB = inFeatB.attributes()
                    int_geom = QgsGeometry(geom.intersection(tmpGeom))
                    if int_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(int_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection:
                        int_com = geom.combine(tmpGeom)
                        int_geom = QgsGeometry()
                        if int_com:
                            int_sym = geom.symDifference(tmpGeom)
                            int_geom = QgsGeometry(int_com.difference(int_sym))
                    if int_geom.isEmpty() or not int_geom.isGeosValid():
                        raise GeoAlgorithmExecutionException(
                            self.tr('GEOS geoprocessing error: One or '
                                    'more input features have invalid '
                                    'geometry.'))
                    try:
                        if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]:
                            outFeat.setGeometry(int_geom)
                            attrs = []
                            attrs.extend(atMapA)
                            attrs.extend(atMapB)
                            outFeat.setAttributes(attrs)
                            writer.addFeature(outFeat, QgsFeatureSink.FastInsert)
                    except:
                        raise GeoAlgorithmExecutionException(
                            self.tr('Feature geometry error: One or more '
                                    'output features ignored due to invalid '
                                    'geometry.'))

        del writer
Example #8
0
 def _setMarkerGeom(self, geom):
     if geom.isMultipart():
         geometries = self._extractAsSingle(geom)
         for g in geometries:
             self._setMarkerGeom(g)
     else:
         if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry:
             m = self._setPointMarker(geom)
         elif QgsWkbTypes.geometryType(geom.wkbType()) in (QgsWkbTypes.LineGeometry, QgsWkbTypes.PolygonGeometry):
             m = self._setRubberBandMarker(geom)
         self.markers.append( m )
Example #9
0
    def processAlgorithm(self, parameters, context, feedback):
        layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)

        geometry_type = self.getParameterValue(self.OUTPUT_GEOMETRY)
        wkb_type = None
        if geometry_type == 0:
            wkb_type = QgsWkbTypes.Polygon
        elif geometry_type == 1:
            wkb_type = QgsWkbTypes.LineString
        else:
            wkb_type = QgsWkbTypes.Point
        if self.getParameterValue(self.WITH_Z):
            wkb_type = QgsWkbTypes.addZ(wkb_type)
        if self.getParameterValue(self.WITH_M):
            wkb_type = QgsWkbTypes.addM(wkb_type)

        writer = self.getOutputFromName(
            self.OUTPUT_LAYER).getVectorWriter(layer.fields(), wkb_type, layer.crs(), context)

        expression = QgsExpression(self.getParameterValue(self.EXPRESSION))
        if expression.hasParserError():
            raise GeoAlgorithmExecutionException(expression.parserErrorString())

        exp_context = QgsExpressionContext(QgsExpressionContextUtils.globalProjectLayerScopes(layer))

        if not expression.prepare(exp_context):
            raise GeoAlgorithmExecutionException(
                self.tr('Evaluation error: {0}').format(expression.evalErrorString()))

        features = QgsProcessingUtils.getFeatures(layer, context)
        total = 100.0 / QgsProcessingUtils.featureCount(layer, context)
        for current, input_feature in enumerate(features):
            output_feature = input_feature

            exp_context.setFeature(input_feature)
            value = expression.evaluate(exp_context)
            if expression.hasEvalError():
                raise GeoAlgorithmExecutionException(
                    self.tr('Evaluation error: {0}').format(expression.evalErrorString()))

            if not value:
                output_feature.setGeometry(QgsGeometry())
            else:
                if not isinstance(value, QgsGeometry):
                    raise GeoAlgorithmExecutionException(
                        self.tr('{} is not a geometry').format(value))
                output_feature.setGeometry(value)

            writer.addFeature(output_feature)
            feedback.setProgress(int(current * total))

        del writer
Example #10
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}
Example #11
0
    def processAlgorithm(self, parameters, context, feedback):
        layerA = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(Difference.INPUT), context)
        layerB = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(Difference.OVERLAY), context)

        geomType = QgsWkbTypes.multiType(layerA.wkbType())
        writer = self.getOutputFromName(
            Difference.OUTPUT).getVectorWriter(layerA.fields(), geomType, layerA.crs(), context)

        outFeat = QgsFeature()
        index = QgsProcessingUtils.createSpatialIndex(layerB, context)
        selectionA = QgsProcessingUtils.getFeatures(layerA, context)
        total = 100.0 / layerA.featureCount() if layerA.featureCount() else 0
        for current, inFeatA in enumerate(selectionA):
            geom = inFeatA.geometry()
            diff_geom = QgsGeometry(geom)
            attrs = inFeatA.attributes()
            intersections = index.intersects(geom.boundingBox())

            request = QgsFeatureRequest().setFilterFids(intersections).setSubsetOfAttributes([])
            for inFeatB in layerB.getFeatures(request):
                tmpGeom = inFeatB.geometry()
                if diff_geom.intersects(tmpGeom):
                    diff_geom = QgsGeometry(diff_geom.difference(tmpGeom))

            try:
                outFeat.setGeometry(diff_geom)
                outFeat.setAttributes(attrs)
                writer.addFeature(outFeat, QgsFeatureSink.FastInsert)
            except:
                QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'), self.tr('Processing'), QgsMessageLog.WARNING)
                continue

            feedback.setProgress(int(current * total))

        del writer
Example #12
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               source.fields(), QgsWkbTypes.singleType(source.wkbType()), source.sourceCrs())

        features = source.getFeatures()
        total = 100.0 / source.featureCount() if source.featureCount() else 0
        for current, feature in enumerate(features):
            if feedback.isCanceled():
                break

            feedback.setProgress(int(current * total))

            if not feature.hasGeometry():
                sink.addFeature(feature, QgsFeatureSink.FastInsert)
                continue

            outFeat = QgsFeature()
            inGeom = feature.geometry()
            segments = self.extractAsSingleSegments(inGeom)
            outFeat.setAttributes(feature.attributes())
            for segment in segments:
                outFeat.setGeometry(segment)
                sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
        return {self.OUTPUT: dest_id}
Example #13
0
 def convertToLineStrings(self, geom):
     if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry:
         raise QgsProcessingException(
             self.tr('Cannot convert from {0} to LineStrings').format(QgsWkbTypes.displayString(geom.wkbType())))
     elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.LineGeometry:
         if QgsWkbTypes.isMultiType(geom.wkbType()):
             return geom.asGeometryCollection()
         else:
             #line to line
             return [geom]
     else:
         # polygons to lines
         # we just use the boundary here - that consists of all rings in the (multi)polygon
         boundary = QgsGeometry(geom.constGet().boundary())
         # boundary will be multipart
         return boundary.asGeometryCollection()
Example #14
0
 def convertToMultiLineStrings(self, geom):
     if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry:
         raise QgsProcessingException(
             self.tr('Cannot convert from {0} to MultiLineStrings').format(QgsWkbTypes.displayString(geom.wkbType())))
     elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.LineGeometry:
         if QgsWkbTypes.isMultiType(geom.wkbType()):
             return [geom]
         else:
             # line to multiLine
             ml = QgsMultiLineString()
             ml.addGeometry(geom.constGet().clone())
             return [QgsGeometry(ml)]
     else:
         # polygons to multilinestring
         # we just use the boundary here - that consists of all rings in the (multi)polygon
         return [QgsGeometry(geom.constGet().boundary())]
Example #15
0
    def __init__(self, table, parent=None):
        TableDataModel.__init__(self, table, parent)

        self.layer = None

        if isinstance(table, LVectorTable):
            self.layer = VLayerRegistry.instance().getLayer(table.name)
        else:
            self.layer = VLayerRegistry.instance().getLayer(table)

        if not self.layer:
            return
        # populate self.resdata
        self.resdata = []
        for f in self.layer.getFeatures():
            a = f.attributes()
            # add the geometry type
            if f.hasGeometry():
                a.append(QgsWkbTypes.displayString(f.geometry().wkbType()))
            else:
                a.append('None')
            self.resdata.append(a)

        self.fetchedFrom = 0
        self.fetchedCount = len(self.resdata)
Example #16
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT))
        geomType = QgsWkbTypes.singleType(layer.wkbType())

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            layer.fields().toList(), geomType, layer.crs())

        features = vector.features(layer)
        total = 100.0 / len(features)
        for current, f in enumerate(features):
            input_geometry = f.geometry()
            if input_geometry:
                if input_geometry.isMultipart():
                    for g in input_geometry.asGeometryCollection():
                        output_feature = f
                        output_feature.setGeometry(g)
                        writer.addFeature(output_feature)
                else:
                    writer.addFeature(f)
            else:
                #input feature with null geometry
                writer.addFeature(f)

            progress.setPercentage(int(current * total))

        del writer
Example #17
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 #18
0
    def processAlgorithm(self, feedback):
        layer = dataobjects.getLayerFromString(
            self.getParameterValue(self.INPUT))

        writer = self.getOutputFromName(
            self.OUTPUT).getVectorWriter(
                layer.fields(),
                QgsWkbTypes.multiType(layer.wkbType()),
                layer.crs())

        features = vector.features(layer)
        if len(features) == 0:
            raise GeoAlgorithmExecutionException(self.tr('There are no features in the input layer'))

        total = 100.0 / len(features)
        for current, inputFeature in enumerate(features):
            outputFeature = inputFeature
            if inputFeature.geometry():
                outputGeometry = inputFeature.geometry().makeValid()
                if not outputGeometry:
                    ProcessingLog.addToLog(ProcessingLog.LOG_WARNING,
                                           'makeValid failed for feature {}'.format(inputFeature.id()))

                if outputGeometry.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(outputGeometry.geometry().wkbType()) == QgsWkbTypes.GeometryCollection:
                    tmpGeometries = outputGeometry.asGeometryCollection()
                    for g in tmpGeometries:
                        if g.type() == inputFeature.geometry().type():
                            try:
                                g.convertToMultiType()
                                outputFeature.setGeometry(QgsGeometry(g))
                                writer.addFeature(outputFeature)
                            except:
                                pass
                    feedback.setProgress(int(current * total))
                    continue

                outputGeometry.convertToMultiType()
                outputFeature.setGeometry(outputGeometry)

            writer.addFeature(outputFeature)
            feedback.setProgress(int(current * total))

        del writer
Example #19
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 #20
0
    def _openShapefile(self):
        layer = QgsVectorLayer(self.shapePath, self.fileName, "ogr")

        wkbType = layer.wkbType()
        if wkbType != QgsWkbTypes.PointZ:
            self.importError.emit(
                self.tr("File has incorrect WKB type '{}'. Please select layer "
                        "with 'PointZ' WKB type.".format(QgsWkbTypes.displayString(wkbType))))
            return None

        return layer
Example #21
0
    def processAlgorithm(self, progress):
        layerA = dataobjects.getObjectFromUri(
            self.getParameterValue(Difference.INPUT))
        layerB = dataobjects.getObjectFromUri(
            self.getParameterValue(Difference.OVERLAY))
        ignoreInvalid = self.getParameterValue(Difference.IGNORE_INVALID)

        geomType = QgsWkbTypes.multiType(layerA.wkbType())
        writer = self.getOutputFromName(
            Difference.OUTPUT).getVectorWriter(layerA.fields(),
                                               geomType,
                                               layerA.crs())

        outFeat = QgsFeature()
        index = vector.spatialindex(layerB)
        selectionA = vector.features(layerA)
        total = 100.0 / len(selectionA)
        for current, inFeatA in enumerate(selectionA):
            add = True
            geom = inFeatA.geometry()
            diff_geom = QgsGeometry(geom)
            attrs = inFeatA.attributes()
            intersections = index.intersects(geom.boundingBox())

            request = QgsFeatureRequest().setFilterFids(intersections).setSubsetOfAttributes([])
            for inFeatB in layerB.getFeatures(request):
                tmpGeom = inFeatB.geometry()
                if diff_geom.intersects(tmpGeom):
                    diff_geom = QgsGeometry(diff_geom.difference(tmpGeom))
                    if diff_geom.isGeosEmpty():
                        ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
                                               self.tr('Feature with NULL geometry found.'))
                    if not diff_geom.isGeosValid():
                        if ignoreInvalid:
                            ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                                   self.tr('GEOS geoprocessing error: One or more input features have invalid geometry.'))
                            add = False
                        else:
                            raise GeoAlgorithmExecutionException(self.tr('Features with invalid geometries found. Please fix these errors or specify the "Ignore invalid input features" flag'))
                        break

            if add:
                try:
                    outFeat.setGeometry(diff_geom)
                    outFeat.setAttributes(attrs)
                    writer.addFeature(outFeat)
                except:
                    ProcessingLog.addToLog(ProcessingLog.LOG_WARNING,
                                           self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
                    continue

            progress.setPercentage(int(current * total))

        del writer
Example #22
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 #23
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 #24
0
    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
Example #25
0
    def convertToLines(self, geometry):
        rings = self.getRings(geometry.constGet())
        output_wkb = self.convertWkbToLines(geometry.wkbType())
        out_geom = None
        if QgsWkbTypes.flatType(output_wkb) == QgsWkbTypes.MultiLineString:
            out_geom = QgsMultiLineString()
        else:
            out_geom = QgsMultiCurve()

        for ring in rings:
            out_geom.addGeometry(ring)

        return out_geom
Example #26
0
    def convertToPolygons(self, geometry):
        surfaces = self.getSurfaces(geometry.constGet())
        output_wkb = self.convertWkbToPolygons(geometry.wkbType())
        out_geom = None
        if QgsWkbTypes.flatType(output_wkb) == QgsWkbTypes.MultiPolygon:
            out_geom = QgsMultiPolygon()
        else:
            out_geom = QgsMultiSurface()

        for surface in surfaces:
            out_geom.addGeometry(surface)

        return out_geom
Example #27
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               source.fields(), QgsWkbTypes.multiType(source.wkbType()), source.sourceCrs())

        features = source.getFeatures(QgsFeatureRequest(), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks)
        total = 100.0 / source.featureCount() if source.featureCount() else 0
        for current, inputFeature in enumerate(features):
            if feedback.isCanceled():
                break

            outputFeature = inputFeature
            if inputFeature.geometry():
                outputGeometry = inputFeature.geometry().makeValid()
                if not outputGeometry:
                    feedback.pushInfo('makeValid failed for feature {}'.format(inputFeature.id()))

                if outputGeometry.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(outputGeometry.geometry().wkbType()) == QgsWkbTypes.GeometryCollection:
                    tmpGeometries = outputGeometry.asGeometryCollection()
                    for g in tmpGeometries:
                        if g.type() == inputFeature.geometry().type():
                            try:
                                g.convertToMultiType()
                                outputFeature.setGeometry(QgsGeometry(g))
                                sink.addFeature(outputFeature, QgsFeatureSink.FastInsert)
                            except:
                                pass
                    feedback.setProgress(int(current * total))
                    continue

                outputGeometry.convertToMultiType()
                outputFeature.setGeometry(outputGeometry)

            sink.addFeature(outputFeature, QgsFeatureSink.FastInsert)
            feedback.setProgress(int(current * total))

        return {self.OUTPUT: dest_id}
Example #28
0
    def processAlgorithm(self, parameters, context, feedback):
        layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context)

        writer = self.getOutputFromName(
            self.OUTPUT).getVectorWriter(layer.fields(), QgsWkbTypes.multiType(layer.wkbType()), layer.crs(), context)

        features = QgsProcessingUtils.getFeatures(layer, context)
        if QgsProcessingUtils.featureCount(layer, context) == 0:
            raise GeoAlgorithmExecutionException(self.tr('There are no features in the input layer'))

        total = 100.0 / QgsProcessingUtils.featureCount(layer, context)
        for current, inputFeature in enumerate(features):
            outputFeature = inputFeature
            if inputFeature.geometry():
                outputGeometry = inputFeature.geometry().makeValid()
                if not outputGeometry:
                    QgsMessageLog.logMessage('makeValid failed for feature {}'.format(inputFeature.id()), self.tr('Processing'), QgsMessageLog.WARNING)

                if outputGeometry.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(outputGeometry.geometry().wkbType()) == QgsWkbTypes.GeometryCollection:
                    tmpGeometries = outputGeometry.asGeometryCollection()
                    for g in tmpGeometries:
                        if g.type() == inputFeature.geometry().type():
                            try:
                                g.convertToMultiType()
                                outputFeature.setGeometry(QgsGeometry(g))
                                writer.addFeature(outputFeature)
                            except:
                                pass
                    feedback.setProgress(int(current * total))
                    continue

                outputGeometry.convertToMultiType()
                outputFeature.setGeometry(outputGeometry)

            writer.addFeature(outputFeature)
            feedback.setProgress(int(current * total))

        del writer
Example #29
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 #30
0
    def processAlgorithm(self, context, feedback):
        source_layer = QgsProcessingUtils.mapLayerFromString(
            self.getParameterValue(Clip.INPUT), context)
        mask_layer = QgsProcessingUtils.mapLayerFromString(
            self.getParameterValue(Clip.OVERLAY), context)

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            source_layer.fields(),
            QgsWkbTypes.multiType(source_layer.wkbType()), source_layer.crs(),
            context)

        # first build up a list of clip geometries
        clip_geoms = []
        for maskFeat in QgsProcessingUtils.getFeatures(
                mask_layer, context,
                QgsFeatureRequest().setSubsetOfAttributes([])):
            clip_geoms.append(maskFeat.geometry())

        # are we clipping against a single feature? if so, we can show finer progress reports
        if len(clip_geoms) > 1:
            combined_clip_geom = QgsGeometry.unaryUnion(clip_geoms)
            single_clip_feature = False
        else:
            combined_clip_geom = clip_geoms[0]
            single_clip_feature = True

        # use prepared geometries for faster intersection tests
        engine = QgsGeometry.createGeometryEngine(
            combined_clip_geom.geometry())
        engine.prepareGeometry()

        tested_feature_ids = set()

        for i, clip_geom in enumerate(clip_geoms):
            input_features = [
                f for f in QgsProcessingUtils.getFeatures(
                    source_layer, context,
                    QgsFeatureRequest().setFilterRect(clip_geom.boundingBox()))
            ]

            if not input_features:
                continue

            if single_clip_feature:
                total = 100.0 / len(input_features)
            else:
                total = 0

            for current, in_feat in enumerate(input_features):
                if not in_feat.geometry():
                    continue

                if in_feat.id() in tested_feature_ids:
                    # don't retest a feature we have already checked
                    continue

                tested_feature_ids.add(in_feat.id())

                if not engine.intersects(in_feat.geometry().geometry()):
                    continue

                if not engine.contains(in_feat.geometry().geometry()):
                    cur_geom = in_feat.geometry()
                    new_geom = combined_clip_geom.intersection(cur_geom)
                    if new_geom.wkbType(
                    ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(
                            new_geom.geometry().wkbType(
                            )) == QgsWkbTypes.GeometryCollection:
                        int_com = in_feat.geometry().combine(new_geom)
                        int_sym = in_feat.geometry().symDifference(new_geom)
                        new_geom = int_com.difference(int_sym)
                else:
                    # clip geometry totally contains feature geometry, so no need to perform intersection
                    new_geom = in_feat.geometry()

                try:
                    out_feat = QgsFeature()
                    out_feat.setGeometry(new_geom)
                    out_feat.setAttributes(in_feat.attributes())
                    writer.addFeature(out_feat)
                except:
                    QgsMessageLog.logMessage(
                        self.tr('Feature geometry error: One or more '
                                'output features ignored due to '
                                'invalid geometry.'), self.tr('Processing'),
                        QgsMessageLog.CRITICAL)
                    continue

                if single_clip_feature:
                    feedback.setProgress(int(current * total))

            if not single_clip_feature:
                # coarse progress report for multiple clip geometries
                feedback.setProgress(100.0 * i / len(clip_geoms))

        del writer
Example #31
0
    def processAlgorithm(self, feedback):
        source = self.getParameterValue(self.INPUT)
        vlayer = dataobjects.getLayerFromString(source)
        output = self.getOutputFromName(self.OUTPUT)

        fields = vlayer.fields()
        x_field_index = fields.lookupField(self.getParameterValue(self.XFIELD))
        y_field_index = fields.lookupField(self.getParameterValue(self.YFIELD))
        z_field_index = None
        if self.getParameterValue(self.ZFIELD):
            z_field_index = fields.lookupField(
                self.getParameterValue(self.ZFIELD))
        m_field_index = None
        if self.getParameterValue(self.MFIELD):
            m_field_index = fields.lookupField(
                self.getParameterValue(self.MFIELD))

        wkb_type = QgsWkbTypes.Point
        if z_field_index is not None:
            wkb_type = QgsWkbTypes.addZ(wkb_type)
        if m_field_index is not None:
            wkb_type = QgsWkbTypes.addM(wkb_type)

        crsId = self.getParameterValue(self.TARGET_CRS)
        target_crs = QgsCoordinateReferenceSystem()
        target_crs.createFromUserInput(crsId)

        writer = output.getVectorWriter(fields, wkb_type, target_crs)

        features = vector.features(vlayer)
        total = 100.0 / len(features)

        for current, feature in enumerate(features):
            feedback.setProgress(int(current * total))
            attrs = feature.attributes()

            try:
                x = float(attrs[x_field_index])
                y = float(attrs[y_field_index])

                point = QgsPointV2(x, y)

                if z_field_index is not None:
                    try:
                        point.addZValue(float(attrs[z_field_index]))
                    except:
                        point.addZValue(0.0)

                if m_field_index is not None:
                    try:
                        point.addMValue(float(attrs[m_field_index]))
                    except:
                        point.addMValue(0.0)

                feature.setGeometry(QgsGeometry(point))
            except:
                pass  # no geometry

            writer.addFeature(feature)

        del writer
Example #32
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        line_source = self.parameterAsSource(parameters, self.LINES, context)

        sameLayer = parameters[self.INPUT] == parameters[self.LINES]

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               source.fields(), QgsWkbTypes.multiType(source.wkbType()), source.sourceCrs())

        spatialIndex = QgsSpatialIndex()
        splitGeoms = {}
        request = QgsFeatureRequest()
        request.setSubsetOfAttributes([])
        request.setDestinationCrs(source.sourceCrs())

        for aSplitFeature in line_source.getFeatures(request):
            if feedback.isCanceled():
                break

            splitGeoms[aSplitFeature.id()] = aSplitFeature.geometry()
            spatialIndex.insertFeature(aSplitFeature)
            # honor the case that user has selection on split layer and has setting "use selection"

        outFeat = QgsFeature()
        features = source.getFeatures()

        total = 100.0 / source.featureCount() if source.featureCount() else 100

        for current, inFeatA in enumerate(features):
            if feedback.isCanceled():
                break

            inGeom = inFeatA.geometry()
            attrsA = inFeatA.attributes()
            outFeat.setAttributes(attrsA)

            if inGeom.isMultipart():
                inGeoms = []

                for g in inGeom.asGeometryCollection():
                    inGeoms.append(g)
            else:
                inGeoms = [inGeom]

            lines = spatialIndex.intersects(inGeom.boundingBox())

            if len(lines) > 0:  # has intersection of bounding boxes
                splittingLines = []

                engine = QgsGeometry.createGeometryEngine(inGeom.geometry())
                engine.prepareGeometry()

                for i in lines:
                    try:
                        splitGeom = splitGeoms[i]
                    except:
                        continue

                    # check if trying to self-intersect
                    if sameLayer:
                        if inFeatA.id() == i:
                            continue

                    if engine.intersects(splitGeom.geometry()):
                        splittingLines.append(splitGeom)

                if len(splittingLines) > 0:
                    for splitGeom in splittingLines:
                        splitterPList = None
                        outGeoms = []

                        split_geom_engine = QgsGeometry.createGeometryEngine(splitGeom.geometry())
                        split_geom_engine.prepareGeometry()

                        while len(inGeoms) > 0:
                            if feedback.isCanceled():
                                break

                            inGeom = inGeoms.pop()

                            if inGeom.isNull():  # this has been encountered and created a run-time error
                                continue

                            if split_geom_engine.intersects(inGeom.geometry()):
                                inPoints = vector.extractPoints(inGeom)
                                if splitterPList is None:
                                    splitterPList = vector.extractPoints(splitGeom)

                                try:
                                    result, newGeometries, topoTestPoints = inGeom.splitGeometry(splitterPList, False)
                                except:
                                    feedback.reportError(self.tr('Geometry exception while splitting'))
                                    result = 1

                                # splitGeometry: If there are several intersections
                                # between geometry and splitLine, only the first one is considered.
                                if result == 0:  # split occurred
                                    if inPoints == vector.extractPoints(inGeom):
                                        # bug in splitGeometry: sometimes it returns 0 but
                                        # the geometry is unchanged
                                        outGeoms.append(inGeom)
                                    else:
                                        inGeoms.append(inGeom)

                                        for aNewGeom in newGeometries:
                                            inGeoms.append(aNewGeom)
                                else:
                                    outGeoms.append(inGeom)
                            else:
                                outGeoms.append(inGeom)

                        inGeoms = outGeoms

            parts = []

            for aGeom in inGeoms:
                if feedback.isCanceled():
                    break

                passed = True

                if QgsWkbTypes.geometryType(aGeom.wkbType()) == QgsWkbTypes.LineGeometry:
                    numPoints = aGeom.geometry().numPoints()

                    if numPoints <= 2:
                        if numPoints == 2:
                            passed = not aGeom.geometry().isClosed()  # tests if vertex 0 = vertex 1
                        else:
                            passed = False
                            # sometimes splitting results in lines of zero length

                if passed:
                    parts.append(aGeom)

            if len(parts) > 0:
                outFeat.setGeometry(QgsGeometry.collectGeometry(parts))
                sink.addFeature(outFeat, QgsFeatureSink.FastInsert)

            feedback.setProgress(int(current * total))
        return {self.OUTPUT: dest_id}
Example #33
0
    def processAlgorithm(self, parameters, context, feedback):
        sourceA = self.parameterAsSource(parameters, self.INPUT, context)
        sourceB = self.parameterAsSource(parameters, self.OVERLAY, context)

        geomType = QgsWkbTypes.multiType(sourceA.wkbType())

        fieldsA = self.parameterAsFields(parameters, self.INPUT_FIELDS,
                                         context)
        fieldsB = self.parameterAsFields(parameters, self.OVERLAY_FIELDS,
                                         context)

        fieldListA = QgsFields()
        field_indices_a = []
        if len(fieldsA) > 0:
            for f in fieldsA:
                idxA = sourceA.fields().lookupField(f)
                if idxA >= 0:
                    field_indices_a.append(idxA)
                    fieldListA.append(sourceA.fields()[idxA])
        else:
            fieldListA = sourceA.fields()
            field_indices_a = [i for i in range(0, fieldListA.count())]

        fieldListB = QgsFields()
        field_indices_b = []
        if len(fieldsB) > 0:
            for f in fieldsB:
                idxB = sourceB.fields().lookupField(f)
                if idxB >= 0:
                    field_indices_b.append(idxB)
                    fieldListB.append(sourceB.fields()[idxB])
        else:
            fieldListB = sourceB.fields()
            field_indices_b = [i for i in range(0, fieldListB.count())]

        output_fields = QgsProcessingUtils.combineFields(
            fieldListA, fieldListB)

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, output_fields,
                                               geomType, sourceA.sourceCrs())

        outFeat = QgsFeature()
        indexB = QgsSpatialIndex(
            sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes(
                []).setDestinationCrs(sourceA.sourceCrs(),
                                      context.transformContext())), feedback)

        total = 100.0 / sourceA.featureCount() if sourceA.featureCount() else 1
        count = 0

        for featA in sourceA.getFeatures(
                QgsFeatureRequest().setSubsetOfAttributes(field_indices_a)):
            if feedback.isCanceled():
                break

            if not featA.hasGeometry():
                continue

            geom = featA.geometry()
            atMapA = featA.attributes()
            intersects = indexB.intersects(geom.boundingBox())

            request = QgsFeatureRequest().setFilterFids(intersects)
            request.setDestinationCrs(sourceA.sourceCrs(),
                                      context.transformContext())
            request.setSubsetOfAttributes(field_indices_b)

            engine = None
            if len(intersects) > 0:
                # use prepared geometries for faster intersection tests
                engine = QgsGeometry.createGeometryEngine(geom.constGet())
                engine.prepareGeometry()

            for featB in sourceB.getFeatures(request):
                if feedback.isCanceled():
                    break

                tmpGeom = featB.geometry()
                if engine.intersects(tmpGeom.constGet()):
                    out_attributes = [
                        featA.attributes()[i] for i in field_indices_a
                    ]
                    out_attributes.extend(
                        [featB.attributes()[i] for i in field_indices_b])
                    int_geom = QgsGeometry(geom.intersection(tmpGeom))
                    if int_geom.wkbType(
                    ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(
                            int_geom.wkbType(
                            )) == QgsWkbTypes.GeometryCollection:
                        int_com = geom.combine(tmpGeom)
                        int_geom = QgsGeometry()
                        if int_com:
                            int_sym = geom.symDifference(tmpGeom)
                            int_geom = QgsGeometry(int_com.difference(int_sym))
                    if int_geom.isEmpty() or not int_geom.isGeosValid():
                        raise QgsProcessingException(
                            self.tr('GEOS geoprocessing error: One or '
                                    'more input features have invalid '
                                    'geometry.'))
                    try:
                        if QgsWkbTypes.geometryType(int_geom.wkbType(
                        )) == QgsWkbTypes.geometryType(geomType):
                            int_geom.convertToMultiType()
                            outFeat.setGeometry(int_geom)
                            outFeat.setAttributes(out_attributes)
                            sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
                    except:
                        raise QgsProcessingException(
                            self.tr('Feature geometry error: One or more '
                                    'output features ignored due to invalid '
                                    'geometry.'))

            count += 1
            feedback.setProgress(int(count * total))

        return {self.OUTPUT: dest_id}
Example #34
0
 def outputWkbType(self, inputWkb):
     return QgsWkbTypes.singleType(inputWkb)
Example #35
0
    def __init__(self,
                 destination,
                 encoding,
                 fields,
                 geometryType,
                 crs,
                 options=None):
        self.destination = destination
        self.isNotFileBased = False
        self.layer = None
        self.writer = None

        if encoding is None:
            settings = QgsSettings()
            encoding = settings.value('/Processing/encoding', 'System', str)

        if self.destination.startswith(self.MEMORY_LAYER_PREFIX):
            self.isNotFileBased = True

            uri = QgsWkbTypes.displayString(geometryType) + "?uuid=" + str(
                uuid.uuid4())
            if crs.isValid():
                uri += '&crs=' + crs.authid()
            fieldsdesc = []
            for f in fields:
                qgsfield = _toQgsField(f)
                fieldsdesc.append(
                    'field=%s:%s' %
                    (qgsfield.name(),
                     TYPE_MAP_MEMORY_LAYER.get(qgsfield.type(), "string")))
            if fieldsdesc:
                uri += '&' + '&'.join(fieldsdesc)

            self.layer = QgsVectorLayer(uri, self.destination, 'memory')
            self.writer = self.layer.dataProvider()
        elif self.destination.startswith(self.POSTGIS_LAYER_PREFIX):
            self.isNotFileBased = True
            uri = QgsDataSourceUri(
                self.destination[len(self.POSTGIS_LAYER_PREFIX):])
            connInfo = uri.connectionInfo()
            (success, user,
             passwd) = QgsCredentials.instance().get(connInfo, None, None)
            if success:
                QgsCredentials.instance().put(connInfo, user, passwd)
            else:
                raise GeoAlgorithmExecutionException(
                    "Couldn't connect to database")
            try:
                db = postgis.GeoDB(host=uri.host(),
                                   port=int(uri.port()),
                                   dbname=uri.database(),
                                   user=user,
                                   passwd=passwd)
            except postgis.DbError as e:
                raise GeoAlgorithmExecutionException(
                    "Couldn't connect to database:\n%s" % e.message)

            def _runSQL(sql):
                try:
                    db._exec_sql_and_commit(str(sql))
                except postgis.DbError as e:
                    raise GeoAlgorithmExecutionException(
                        'Error creating output PostGIS table:\n%s' % e.message)

            fields = [_toQgsField(f) for f in fields]
            fieldsdesc = ",".join(
                '%s %s' %
                (f.name(), TYPE_MAP_POSTGIS_LAYER.get(f.type(), "VARCHAR"))
                for f in fields)

            _runSQL("CREATE TABLE %s.%s (%s)" %
                    (uri.schema(), uri.table().lower(), fieldsdesc))
            if geometryType != QgsWkbTypes.NullGeometry:
                _runSQL(
                    "SELECT AddGeometryColumn('{schema}', '{table}', 'the_geom', {srid}, '{typmod}', 2)"
                    .format(table=uri.table().lower(),
                            schema=uri.schema(),
                            srid=crs.authid().split(":")[-1],
                            typmod=QgsWkbTypes.displayString(
                                geometryType).upper()))

            self.layer = QgsVectorLayer(uri.uri(), uri.table(), "postgres")
            self.writer = self.layer.dataProvider()
        elif self.destination.startswith(self.SPATIALITE_LAYER_PREFIX):
            self.isNotFileBased = True
            uri = QgsDataSourceUri(
                self.destination[len(self.SPATIALITE_LAYER_PREFIX):])
            try:
                db = spatialite.GeoDB(uri=uri)
            except spatialite.DbError as e:
                raise GeoAlgorithmExecutionException(
                    "Couldn't connect to database:\n%s" % e.message)

            def _runSQL(sql):
                try:
                    db._exec_sql_and_commit(str(sql))
                except spatialite.DbError as e:
                    raise GeoAlgorithmExecutionException(
                        'Error creating output Spatialite table:\n%s' % str(e))

            fields = [_toQgsField(f) for f in fields]
            fieldsdesc = ",".join(
                '%s %s' %
                (f.name(), TYPE_MAP_SPATIALITE_LAYER.get(f.type(), "VARCHAR"))
                for f in fields)

            _runSQL("DROP TABLE IF EXISTS %s" % uri.table().lower())
            _runSQL("CREATE TABLE %s (%s)" % (uri.table().lower(), fieldsdesc))
            if geometryType != QgsWkbTypes.NullGeometry:
                _runSQL(
                    "SELECT AddGeometryColumn('{table}', 'the_geom', {srid}, '{typmod}', 2)"
                    .format(table=uri.table().lower(),
                            srid=crs.authid().split(":")[-1],
                            typmod=QgsWkbTypes.displayString(
                                geometryType).upper()))

            self.layer = QgsVectorLayer(uri.uri(), uri.table(), "spatialite")
            self.writer = self.layer.dataProvider()
        else:
            formats = QgsVectorFileWriter.supportedFiltersAndFormats()
            OGRCodes = {}
            for (key, value) in list(formats.items()):
                extension = str(key)
                extension = extension[extension.find('*.') + 2:]
                extension = extension[:extension.find(' ')]
                OGRCodes[extension] = value
            OGRCodes['dbf'] = "DBF file"

            extension = self.destination[self.destination.rfind('.') + 1:]

            if extension not in OGRCodes:
                extension = 'shp'
                self.destination = self.destination + '.shp'

            if geometryType == QgsWkbTypes.NoGeometry:
                if extension == 'shp':
                    extension = 'dbf'
                    self.destination = self.destination[:self.destination.
                                                        rfind('.')] + '.dbf'
                if extension not in self.nogeometry_extensions:
                    raise GeoAlgorithmExecutionException(
                        "Unsupported format for tables with no geometry")

            qgsfields = QgsFields()
            for field in fields:
                qgsfields.append(_toQgsField(field))

            # use default dataset/layer options
            dataset_options = QgsVectorFileWriter.defaultDatasetOptions(
                OGRCodes[extension])
            layer_options = QgsVectorFileWriter.defaultLayerOptions(
                OGRCodes[extension])

            self.writer = QgsVectorFileWriter(self.destination, encoding,
                                              qgsfields, geometryType, crs,
                                              OGRCodes[extension],
                                              dataset_options, layer_options)
Example #36
0
    def layers(self, filter_layer_list=[]):
        ignored_layers = self.get_ignored_layers()
        tables_info = self.get_tables_info()
        layers = list()

        db_factory = self.db_simple_factory.create_factory(self.tool)

        layer_uri = db_factory.get_layer_uri(self.uri)
        layer_uri.pg_estimated_metadata = self.pg_estimated_metadata

        for record in tables_info:
            # When in PostGIS mode, leaving schema blank should load tables from
            # all schemas, except the ignored ones
            if self.schema:
                if record['schemaname'] != self.schema:
                    continue

            if ignored_layers and record['tablename'] in ignored_layers:
                continue

            if filter_layer_list and record['tablename'] not in filter_layer_list:
                continue

            is_domain = record['kind_settings'] == 'ENUM' or record[
                'kind_settings'] == 'CATALOGUE' if 'kind_settings' in record else False
            is_attribute = bool(record['attribute_name']) if 'attribute_name' in record else False
            is_structure = record['kind_settings'] == 'STRUCTURE' if 'kind_settings' in record else False
            is_nmrel = record['kind_settings'] == 'ASSOCIATION' if 'kind_settings' in record else False

            alias = record['table_alias'] if 'table_alias' in record else None
            if not alias:
                if is_domain and is_attribute:
                    short_name = record['ili_name'].split('.')[-2] + '_' + record['ili_name'].split('.')[-1] if 'ili_name' in record else ''
                else:
                    short_name = record['ili_name'].split('.')[-1] if 'ili_name' in record else ''
                alias = short_name

            display_expression = ''
            if 'ili_name' in record:
                meta_attrs = self.get_meta_attrs(record['ili_name'])
                for attr_record in meta_attrs:
                    if attr_record['attr_name'] == 'dispExpression':
                        display_expression = attr_record['attr_value']

            coord_decimals = record['coord_decimals'] if 'coord_decimals' in record else None
            coordinate_precision = None
            if coord_decimals:
                coordinate_precision = 1 / (10 ** coord_decimals)

            layer = Layer(layer_uri.provider,
                layer_uri.get_data_source_uri(record),
                record['tablename'],
                record['srid'],
                record['extent'] if 'extent' in record else None,
                record['geometry_column'],
                QgsWkbTypes.parseType(
                  record['type']) or QgsWkbTypes.Unknown,
                alias,
                is_domain,
                is_structure,
                is_nmrel,
                display_expression,
                coordinate_precision )

            # Configure fields for current table
            fields_info = self.get_fields_info(record['tablename'])
            min_max_info = self.get_min_max_info(record['tablename'])
            value_map_info = self.get_value_map_info(record['tablename'])
            re_iliname = re.compile(r'.*\.(.*)$')

            for fielddef in fields_info:
                column_name = fielddef['column_name']
                fully_qualified_name = fielddef['fully_qualified_name'] if 'fully_qualified_name' in fielddef else None
                m = re_iliname.match(fully_qualified_name) if fully_qualified_name else None

                alias = None
                if 'column_alias' in fielddef:
                    alias = fielddef['column_alias']
                if m and not alias:
                    alias = m.group(1)

                field = Field(column_name)
                field.alias = alias

                # Should we hide the field?
                hide_attribute = False

                if 'fully_qualified_name' in fielddef:
                    fully_qualified_name = fielddef['fully_qualified_name']
                    if fully_qualified_name:
                        meta_attrs_column = self.get_meta_attrs(fully_qualified_name)

                        for attr_record in meta_attrs_column:
                            if attr_record['attr_name'] == 'hidden':
                                if attr_record['attr_value'] == 'True':
                                    hide_attribute = True
                                    break

                if column_name in IGNORED_FIELDNAMES:
                    hide_attribute = True

                field.hidden = hide_attribute

                if column_name in READONLY_FIELDNAMES:
                    field.read_only = True

                if column_name in min_max_info:
                    field.widget = 'Range'
                    field.widget_config['Min'] = min_max_info[column_name][0]
                    field.widget_config['Max'] = min_max_info[column_name][1]
                    if 'numeric_scale' in fielddef:
                        field.widget_config['Step'] = pow(10, -1 * fielddef['numeric_scale'])
                    # field.widget_config['Suffix'] = fielddef['unit'] if 'unit' in fielddef else ''
                    if 'unit' in fielddef and fielddef['unit'] is not None:
                        field.alias = '{alias} [{unit}]'.format(
                            alias=alias or column_name, unit=fielddef['unit'])

                if column_name in value_map_info:
                    field.widget = 'ValueMap'
                    field.widget_config['map'] = [{val: val} for val in value_map_info[column_name]]

                if 'texttype' in fielddef and fielddef['texttype'] == 'MTEXT':
                    field.widget = 'TextEdit'
                    field.widget_config['IsMultiline'] = True

                data_type = self._db_connector.map_data_types(
                    fielddef['data_type'])
                if 'time' in data_type or 'date' in data_type:
                    field.widget = 'DateTime'
                    field.widget_config['calendar_popup'] = True

                    dateFormat = QLocale(QgsApplication.instance(
                    ).locale()).dateFormat(QLocale.ShortFormat)
                    timeFormat = QLocale(QgsApplication.instance(
                    ).locale()).timeFormat(QLocale.ShortFormat)
                    dateTimeFormat = QLocale(QgsApplication.instance(
                    ).locale()).dateTimeFormat(QLocale.ShortFormat)

                    if data_type == self._db_connector.QGIS_TIME_TYPE:
                        field.widget_config['display_format'] = timeFormat
                    elif data_type == self._db_connector.QGIS_DATE_TIME_TYPE:
                        field.widget_config['display_format'] = dateTimeFormat
                    elif data_type == self._db_connector.QGIS_DATE_TYPE:
                        field.widget_config['display_format'] = dateFormat

                db_factory.customize_widget_editor(field, data_type)

                if 'default_value_expression' in fielddef:
                    field.default_value_expression = fielddef['default_value_expression']

                if 'enum_domain' in fielddef and fielddef['enum_domain']:
                    field.enum_domain = fielddef['enum_domain']

                layer.fields.append(field)

            layers.append(layer)

        self.print_messages()

        return layers
Example #37
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()

        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(), 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 #38
0
    def processAlgorithm(self, feedback):
        vlayerA = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT))
        vlayerB = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT2))

        geomType = QgsWkbTypes.multiType(vlayerA.wkbType())
        fields = vector.combineVectorFields(vlayerA, vlayerB)
        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fields, geomType, vlayerA.crs())
        outFeat = QgsFeature()
        index = vector.spatialindex(vlayerB)
        selectionA = vector.features(vlayerA)
        total = 100.0 / len(selectionA)
        for current, inFeatA in enumerate(selectionA):
            feedback.setProgress(int(current * total))
            geom = inFeatA.geometry()
            atMapA = inFeatA.attributes()
            intersects = index.intersects(geom.boundingBox())
            request = QgsFeatureRequest().setFilterFids(intersects)

            engine = None
            if len(intersects) > 0:
                # use prepared geometries for faster intersection tests
                engine = QgsGeometry.createGeometryEngine(geom.geometry())
                engine.prepareGeometry()

            for inFeatB in vlayerB.getFeatures(request):
                tmpGeom = inFeatB.geometry()
                if engine.intersects(tmpGeom.geometry()):
                    atMapB = inFeatB.attributes()
                    int_geom = QgsGeometry(geom.intersection(tmpGeom))
                    if int_geom.wkbType(
                    ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(
                            int_geom.geometry().wkbType(
                            )) == QgsWkbTypes.GeometryCollection:
                        int_com = geom.combine(tmpGeom)
                        int_geom = QgsGeometry()
                        if int_com:
                            int_sym = geom.symDifference(tmpGeom)
                            int_geom = QgsGeometry(int_com.difference(int_sym))
                    if int_geom.isEmpty() or not int_geom.isGeosValid():
                        ProcessingLog.addToLog(
                            ProcessingLog.LOG_ERROR,
                            self.tr('GEOS geoprocessing error: One or '
                                    'more input features have invalid '
                                    'geometry.'))
                    try:
                        if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[
                                int_geom.wkbType()]]:
                            outFeat.setGeometry(int_geom)
                            attrs = []
                            attrs.extend(atMapA)
                            attrs.extend(atMapB)
                            outFeat.setAttributes(attrs)
                            writer.addFeature(outFeat)
                    except:
                        ProcessingLog.addToLog(
                            ProcessingLog.LOG_INFO,
                            self.
                            tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                               ))
                        continue

        del writer
Example #39
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('node_part', QVariant.Int))
        if QgsWkbTypes.geometryType(
                source.wkbType()) == QgsWkbTypes.PolygonGeometry:
            fields.append(QgsField('node_part_ring', QVariant.Int))
        fields.append(QgsField('node_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())

        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.constGet().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

                    (success, vertex_id
                     ) = input_geometry.vertexIdFromVertexNr(node_index)

                    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(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(node_index)
                    output_feature.setGeometry(QgsGeometry(point))

                    sink.addFeature(output_feature, QgsFeatureSink.FastInsert)

            feedback.setProgress(int(current * total))

        return {self.OUTPUT: dest_id}
Example #40
0
 def outputWkbType(self, inputWkb):
     return QgsWkbTypes.addM(inputWkb)
Example #41
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 #42
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 #43
0
    def processAlgorithm(self, feedback):
        layerA = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_A))
        splitLayer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_B))

        sameLayer = self.getParameterValue(
            self.INPUT_A) == self.getParameterValue(self.INPUT_B)
        fieldList = layerA.fields()

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fieldList, QgsWkbTypes.multiType(layerA.wkbType()), layerA.crs())

        spatialIndex = QgsSpatialIndex()
        splitGeoms = {}
        request = QgsFeatureRequest()
        request.setSubsetOfAttributes([])

        for aSplitFeature in vector.features(splitLayer, request):
            splitGeoms[aSplitFeature.id()] = aSplitFeature.geometry()
            spatialIndex.insertFeature(aSplitFeature)
            # honor the case that user has selection on split layer and has setting "use selection"

        outFeat = QgsFeature()
        features = vector.features(layerA)

        if len(features) == 0:
            total = 100
        else:
            total = 100.0 / float(len(features))

        for current, inFeatA in enumerate(features):
            inGeom = inFeatA.geometry()
            attrsA = inFeatA.attributes()
            outFeat.setAttributes(attrsA)

            if inGeom.isMultipart():
                inGeoms = []

                for g in inGeom.asGeometryCollection():
                    inGeoms.append(g)
            else:
                inGeoms = [inGeom]

            lines = spatialIndex.intersects(inGeom.boundingBox())

            if len(lines) > 0:  # has intersection of bounding boxes
                splittingLines = []

                engine = QgsGeometry.createGeometryEngine(inGeom.geometry())
                engine.prepareGeometry()

                for i in lines:
                    try:
                        splitGeom = splitGeoms[i]
                    except:
                        continue

                    # check if trying to self-intersect
                    if sameLayer:
                        if inFeatA.id() == i:
                            continue

                    if engine.intersects(splitGeom.geometry()):
                        splittingLines.append(splitGeom)

                if len(splittingLines) > 0:
                    for splitGeom in splittingLines:
                        splitterPList = None
                        outGeoms = []

                        split_geom_engine = QgsGeometry.createGeometryEngine(
                            splitGeom.geometry())
                        split_geom_engine.prepareGeometry()

                        while len(inGeoms) > 0:
                            inGeom = inGeoms.pop()

                            if inGeom.isNull(
                            ):  # this has been encountered and created a run-time error
                                continue

                            if split_geom_engine.intersects(inGeom.geometry()):
                                inPoints = vector.extractPoints(inGeom)
                                if splitterPList == None:
                                    splitterPList = vector.extractPoints(
                                        splitGeom)

                                try:
                                    result, newGeometries, topoTestPoints = inGeom.splitGeometry(
                                        splitterPList, False)
                                except:
                                    ProcessingLog.addToLog(
                                        ProcessingLog.LOG_WARNING,
                                        self.
                                        tr('Geometry exception while splitting'
                                           ))
                                    result = 1

                                # splitGeometry: If there are several intersections
                                # between geometry and splitLine, only the first one is considered.
                                if result == 0:  # split occurred
                                    if inPoints == vector.extractPoints(
                                            inGeom):
                                        # bug in splitGeometry: sometimes it returns 0 but
                                        # the geometry is unchanged
                                        outGeoms.append(inGeom)
                                    else:
                                        inGeoms.append(inGeom)

                                        for aNewGeom in newGeometries:
                                            inGeoms.append(aNewGeom)
                                else:
                                    outGeoms.append(inGeom)
                            else:
                                outGeoms.append(inGeom)

                        inGeoms = outGeoms

            parts = []

            for aGeom in inGeoms:
                passed = True

                if QgsWkbTypes.geometryType(
                        aGeom.wkbType()) == QgsWkbTypes.LineGeometry:
                    numPoints = aGeom.geometry().numPoints()

                    if numPoints <= 2:
                        if numPoints == 2:
                            passed = not aGeom.geometry().isClosed(
                            )  # tests if vertex 0 = vertex 1
                        else:
                            passed = False
                            # sometimes splitting results in lines of zero length

                if passed:
                    parts.append(aGeom)

            if len(parts) > 0:
                outFeat.setGeometry(QgsGeometry.collectGeometry(parts))
                writer.addFeature(outFeat)

            feedback.setProgress(int(current * total))
        del writer
Example #44
0
File: Union.py Project: rossia/QGIS
    def processAlgorithm(self, parameters, context, feedback):
        sourceA = self.parameterAsSource(parameters, self.INPUT, context)
        sourceB = self.parameterAsSource(parameters, self.OVERLAY, context)

        geomType = QgsWkbTypes.multiType(sourceA.wkbType())
        fields = QgsProcessingUtils.combineFields(sourceA.fields(),
                                                  sourceB.fields())

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, fields, geomType,
                                               sourceA.sourceCrs())

        featA = QgsFeature()
        featB = QgsFeature()
        outFeat = QgsFeature()

        indexA = QgsSpatialIndex(sourceA, feedback)
        indexB = QgsSpatialIndex(
            sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes(
                []).setDestinationCrs(sourceA.sourceCrs())), feedback)

        total = 100.0 / (sourceA.featureCount() *
                         sourceB.featureCount()) if sourceA.featureCount(
                         ) and sourceB.featureCount() else 1
        count = 0

        for featA in sourceA.getFeatures():
            if feedback.isCanceled():
                break

            lstIntersectingB = []
            geom = featA.geometry()
            atMapA = featA.attributes()
            intersects = indexB.intersects(geom.boundingBox())
            if len(intersects) < 1:
                try:
                    geom.convertToMultiType()
                    outFeat.setGeometry(geom)
                    outFeat.setAttributes(atMapA)
                    sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
                except:
                    # This really shouldn't happen, as we haven't
                    # edited the input geom at all
                    feedback.pushInfo(
                        self.
                        tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                           ))
            else:
                request = QgsFeatureRequest().setFilterFids(
                    intersects).setSubsetOfAttributes([])
                request.setDestinationCrs(sourceA.sourceCrs())

                engine = QgsGeometry.createGeometryEngine(geom.geometry())
                engine.prepareGeometry()

                for featB in sourceB.getFeatures(request):
                    atMapB = featB.attributes()
                    tmpGeom = featB.geometry()

                    if engine.intersects(tmpGeom.geometry()):
                        int_geom = geom.intersection(tmpGeom)
                        lstIntersectingB.append(tmpGeom)

                        if not int_geom:
                            # There was a problem creating the intersection
                            feedback.pushInfo(
                                self.
                                tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                                   ))
                            int_geom = QgsGeometry()
                        else:
                            int_geom = QgsGeometry(int_geom)

                        if int_geom.wkbType(
                        ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(
                                int_geom.geometry().wkbType(
                                )) == QgsWkbTypes.GeometryCollection:
                            # Intersection produced different geomety types
                            temp_list = int_geom.asGeometryCollection()
                            for i in temp_list:
                                if i.type() == geom.type():
                                    int_geom = QgsGeometry(i)
                                    try:
                                        int_geom.convertToMultiType()
                                        outFeat.setGeometry(int_geom)
                                        outFeat.setAttributes(atMapA + atMapB)
                                        sink.addFeature(
                                            outFeat, QgsFeatureSink.FastInsert)
                                    except:
                                        feedback.pushInfo(
                                            self.
                                            tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                                               ))
                        else:
                            # Geometry list: prevents writing error
                            # in geometries of different types
                            # produced by the intersection
                            # fix #3549
                            if QgsWkbTypes.geometryType(int_geom.wkbType(
                            )) == QgsWkbTypes.geometryType(geomType):
                                try:
                                    int_geom.convertToMultiType()
                                    outFeat.setGeometry(int_geom)
                                    outFeat.setAttributes(atMapA + atMapB)
                                    sink.addFeature(outFeat,
                                                    QgsFeatureSink.FastInsert)
                                except:
                                    feedback.pushInfo(
                                        self.
                                        tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                                           ))

                # the remaining bit of featA's geometry
                # if there is nothing left, this will just silently fail and we're good
                diff_geom = QgsGeometry(geom)
                if len(lstIntersectingB) != 0:
                    intB = QgsGeometry.unaryUnion(lstIntersectingB)
                    diff_geom = diff_geom.difference(intB)

                if diff_geom.wkbType(
                ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(
                        diff_geom.geometry().wkbType(
                        )) == QgsWkbTypes.GeometryCollection:
                    temp_list = diff_geom.asGeometryCollection()
                    for i in temp_list:
                        if i.type() == geom.type():
                            diff_geom = QgsGeometry(i)
                try:
                    diff_geom.convertToMultiType()
                    outFeat.setGeometry(diff_geom)
                    outFeat.setAttributes(atMapA)
                    sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
                except:
                    feedback.pushInfo(
                        self.
                        tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                           ))

            count += 1
            feedback.setProgress(int(count * total))

        length = len(sourceA.fields())
        atMapA = [None] * length

        for featA in sourceB.getFeatures(QgsFeatureRequest().setDestinationCrs(
                sourceA.sourceCrs())):
            if feedback.isCanceled():
                break

            add = False
            geom = featA.geometry()
            diff_geom = QgsGeometry(geom)
            atMap = [None] * length
            atMap.extend(featA.attributes())
            intersects = indexA.intersects(geom.boundingBox())

            if len(intersects) < 1:
                try:
                    geom.convertToMultiType()
                    outFeat.setGeometry(geom)
                    outFeat.setAttributes(atMap)
                    sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
                except:
                    feedback.pushInfo(
                        self.
                        tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                           ))
            else:
                request = QgsFeatureRequest().setFilterFids(
                    intersects).setSubsetOfAttributes([])
                request.setDestinationCrs(sourceA.sourceCrs())

                # use prepared geometries for faster intersection tests
                engine = QgsGeometry.createGeometryEngine(diff_geom.geometry())
                engine.prepareGeometry()

                for featB in sourceA.getFeatures(request):
                    atMapB = featB.attributes()
                    tmpGeom = featB.geometry()

                    if engine.intersects(tmpGeom.geometry()):
                        add = True
                        diff_geom = QgsGeometry(diff_geom.difference(tmpGeom))
                    else:
                        try:
                            # Ihis only happens if the bounding box
                            # intersects, but the geometry doesn't
                            diff_geom.convertToMultiType()
                            outFeat.setGeometry(diff_geom)
                            outFeat.setAttributes(atMap)
                            sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
                        except:
                            feedback.pushInfo(
                                self.
                                tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                                   ))

            if add:
                try:
                    diff_geom.convertToMultiType()
                    outFeat.setGeometry(diff_geom)
                    outFeat.setAttributes(atMap)
                    sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
                except:
                    feedback.pushInfo(
                        self.
                        tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                           ))

            count += 1
            feedback.setProgress(int(count * total))

        return {self.OUTPUT: dest_id}
Example #45
0
    def linearMatrix(self, parameters, context, source, inField, target_source,
                     targetField, same_source_and_target, matType, nPoints,
                     feedback):

        if same_source_and_target:
            # need to fetch an extra point from the index, since the closest match will always be the same
            # as the input feature
            nPoints += 1

        inIdx = source.fields().lookupField(inField)
        outIdx = target_source.fields().lookupField(targetField)

        fields = QgsFields()
        input_id_field = source.fields()[inIdx]
        input_id_field.setName('InputID')
        fields.append(input_id_field)
        if matType == 0:
            target_id_field = target_source.fields()[outIdx]
            target_id_field.setName('TargetID')
            fields.append(target_id_field)
            fields.append(QgsField('Distance', QVariant.Double))
        else:
            fields.append(QgsField('MEAN', QVariant.Double))
            fields.append(QgsField('STDDEV', QVariant.Double))
            fields.append(QgsField('MIN', QVariant.Double))
            fields.append(QgsField('MAX', QVariant.Double))

        out_wkb = QgsWkbTypes.multiType(
            source.wkbType()) if matType == 0 else source.wkbType()
        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, fields, out_wkb,
                                               source.sourceCrs())
        if sink is None:
            raise QgsProcessingException(
                self.invalidSinkError(parameters, self.OUTPUT))

        index = QgsSpatialIndex(
            target_source.getFeatures(
                QgsFeatureRequest().setSubsetOfAttributes(
                    []).setDestinationCrs(source.sourceCrs(),
                                          context.transformContext())),
            feedback)

        distArea = QgsDistanceArea()
        distArea.setSourceCrs(source.sourceCrs(), context.transformContext())
        distArea.setEllipsoid(context.project().ellipsoid())

        features = source.getFeatures(
            QgsFeatureRequest().setSubsetOfAttributes([inIdx]))
        total = 100.0 / source.featureCount() if source.featureCount() else 0
        for current, inFeat in enumerate(features):
            if feedback.isCanceled():
                break

            inGeom = inFeat.geometry()
            inID = str(inFeat.attributes()[inIdx])
            featList = index.nearestNeighbor(inGeom.asPoint(), nPoints)
            distList = []
            vari = 0.0
            request = QgsFeatureRequest().setFilterFids(
                featList).setSubsetOfAttributes([outIdx]).setDestinationCrs(
                    source.sourceCrs(), context.transformContext())
            for outFeat in target_source.getFeatures(request):
                if feedback.isCanceled():
                    break

                if same_source_and_target and inFeat.id() == outFeat.id():
                    continue

                outID = outFeat.attributes()[outIdx]
                outGeom = outFeat.geometry()
                dist = distArea.measureLine(inGeom.asPoint(),
                                            outGeom.asPoint())

                if matType == 0:
                    out_feature = QgsFeature()
                    out_geom = QgsGeometry.unaryUnion(
                        [inFeat.geometry(),
                         outFeat.geometry()])
                    out_feature.setGeometry(out_geom)
                    out_feature.setAttributes([inID, outID, dist])
                    sink.addFeature(out_feature, QgsFeatureSink.FastInsert)
                else:
                    distList.append(float(dist))

            if matType != 0:
                mean = sum(distList) / len(distList)
                for i in distList:
                    vari += (i - mean) * (i - mean)
                vari = math.sqrt(vari / len(distList))

                out_feature = QgsFeature()
                out_feature.setGeometry(inFeat.geometry())
                out_feature.setAttributes(
                    [inID, mean, vari,
                     min(distList),
                     max(distList)])
                sink.addFeature(out_feature, QgsFeatureSink.FastInsert)

            feedback.setProgress(int(current * total))

        return {self.OUTPUT: dest_id}
Example #46
0
    def processAlgorithm(self, parameters, 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 #47
0
    def processAlgorithm(self, parameters, context, feedback):
        sourceA = self.parameterAsSource(parameters, self.INPUT, context)
        sourceB = self.parameterAsSource(parameters, self.OVERLAY, context)

        geomType = QgsWkbTypes.multiType(sourceA.wkbType())
        fields = vector.combineFields(sourceA.fields(), sourceB.fields())

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, fields, geomType,
                                               sourceA.sourceCrs())

        featB = QgsFeature()
        outFeat = QgsFeature()

        indexA = QgsSpatialIndex(sourceA, feedback)
        indexB = QgsSpatialIndex(
            sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes(
                []).setDestinationCrs(sourceA.sourceCrs())), feedback)

        total = 100.0 / (sourceA.featureCount() *
                         sourceB.featureCount()) if sourceA.featureCount(
                         ) and sourceB.featureCount() else 1
        count = 0

        for featA in sourceA.getFeatures():
            if feedback.isCanceled():
                break

            geom = featA.geometry()
            diffGeom = QgsGeometry(geom)
            attrs = featA.attributes()
            intersects = indexB.intersects(geom.boundingBox())
            request = QgsFeatureRequest().setFilterFids(
                intersects).setSubsetOfAttributes([])
            request.setDestinationCrs(sourceA.sourceCrs())
            for featB in sourceB.getFeatures(request):
                if feedback.isCanceled():
                    break
                tmpGeom = featB.geometry()
                if diffGeom.intersects(tmpGeom):
                    diffGeom = QgsGeometry(diffGeom.difference(tmpGeom))

            try:
                outFeat.setGeometry(diffGeom)
                outFeat.setAttributes(attrs)
                sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
            except:
                QgsMessageLog.logMessage(
                    self.
                    tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                       ), self.tr('Processing'), QgsMessageLog.WARNING)
                continue

            count += 1
            feedback.setProgress(int(count * total))

        length = len(sourceA.fields())

        for featA in sourceB.getFeatures(QgsFeatureRequest().setDestinationCrs(
                sourceA.sourceCrs())):
            if feedback.isCanceled():
                break

            geom = featA.geometry()
            diffGeom = QgsGeometry(geom)
            attrs = featA.attributes()
            attrs = [NULL] * length + attrs
            intersects = indexA.intersects(geom.boundingBox())
            request = QgsFeatureRequest().setFilterFids(
                intersects).setSubsetOfAttributes([])
            for featB in sourceA.getFeatures(request):
                if feedback.isCanceled():
                    break

                tmpGeom = featB.geometry()
                if diffGeom.intersects(tmpGeom):
                    diffGeom = QgsGeometry(diffGeom.difference(tmpGeom))

            try:
                outFeat.setGeometry(diffGeom)
                outFeat.setAttributes(attrs)
                sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
            except:
                QgsMessageLog.logMessage(
                    self.
                    tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                       ), self.tr('Processing'), QgsMessageLog.WARNING)
                continue

            count += 1
            feedback.setProgress(int(count * total))

        return {self.OUTPUT: dest_id}
Example #48
0
 def supportInPlaceEdit(self, layer):
     return super().supportInPlaceEdit(layer) and QgsWkbTypes.hasM(
         layer.wkbType())
Example #49
0
    def processAlgorithm(self, parameters, context, feedback):
        expr_context = self.createExpressionContext(parameters, context,
                                                    self.source)
        self.group_by_expr.prepare(expr_context)

        # Group features in memory layers
        source = self.source
        count = self.source.featureCount()
        if count:
            progress_step = 50.0 / count
        current = 0
        groups = {}
        keys = []  # We need deterministic order for the tests
        feature = QgsFeature()
        for feature in self.source.getFeatures():
            expr_context.setFeature(feature)
            group_by_value = self.evaluateExpression(self.group_by_expr,
                                                     expr_context)

            # Get an hashable key for the dict
            key = group_by_value
            if isinstance(key, list):
                key = tuple(key)

            group = groups.get(key, None)
            if group is None:
                sink, id = QgsProcessingUtils.createFeatureSink(
                    'memory:', context, source.fields(), source.wkbType(),
                    source.sourceCrs())
                layer = QgsProcessingUtils.mapLayerFromString(id, context)
                group = {'sink': sink, 'layer': layer, 'feature': feature}
                groups[key] = group
                keys.append(key)

            group['sink'].addFeature(feature, QgsFeatureSink.FastInsert)

            current += 1
            feedback.setProgress(int(current * progress_step))
            if feedback.isCanceled():
                return

        (sink, dest_id) = self.parameterAsSink(
            parameters, self.OUTPUT, context, self.fields,
            QgsWkbTypes.multiType(source.wkbType()), source.sourceCrs())
        if sink is None:
            raise QgsProcessingException(
                self.invalidSinkError(parameters, self.OUTPUT))

        # Calculate aggregates on memory layers
        if len(keys):
            progress_step = 50.0 / len(keys)
        for current, key in enumerate(keys):
            group = groups[key]
            expr_context = self.createExpressionContext(parameters, context)
            expr_context.appendScope(
                QgsExpressionContextUtils.layerScope(group['layer']))
            expr_context.setFeature(group['feature'])

            geometry = self.evaluateExpression(self.geometry_expr,
                                               expr_context)
            if geometry is not None and not geometry.isEmpty():
                geometry = QgsGeometry.unaryUnion(
                    geometry.asGeometryCollection())
                if geometry.isEmpty():
                    raise QgsProcessingException(
                        'Impossible to combine geometries for {} = {}'.format(
                            self.group_by, group_by_value))

            attrs = []
            for fields_expr in self.fields_expr:
                attrs.append(self.evaluateExpression(fields_expr,
                                                     expr_context))

            # Write output feature
            outFeat = QgsFeature()
            if geometry is not None:
                outFeat.setGeometry(geometry)
            outFeat.setAttributes(attrs)
            sink.addFeature(outFeat, QgsFeatureSink.FastInsert)

            feedback.setProgress(50 + int(current * progress_step))
            if feedback.isCanceled():
                return

        return {self.OUTPUT: dest_id}
Example #50
0
    def processAlgorithm(self, progress):
        layerA = dataobjects.getObjectFromUri(
            self.getParameterValue(Difference.INPUT))
        layerB = dataobjects.getObjectFromUri(
            self.getParameterValue(Difference.OVERLAY))
        ignoreInvalid = self.getParameterValue(Difference.IGNORE_INVALID)

        geomType = QgsWkbTypes.multiType(layerA.wkbType())
        writer = self.getOutputFromName(Difference.OUTPUT).getVectorWriter(
            layerA.fields(), geomType, layerA.crs())

        outFeat = QgsFeature()
        index = vector.spatialindex(layerB)
        selectionA = vector.features(layerA)
        total = 100.0 / len(selectionA)
        for current, inFeatA in enumerate(selectionA):
            add = True
            geom = inFeatA.geometry()
            diff_geom = QgsGeometry(geom)
            attrs = inFeatA.attributes()
            intersections = index.intersects(geom.boundingBox())

            request = QgsFeatureRequest().setFilterFids(
                intersections).setSubsetOfAttributes([])
            for inFeatB in layerB.getFeatures(request):
                tmpGeom = inFeatB.geometry()
                if diff_geom.intersects(tmpGeom):
                    diff_geom = QgsGeometry(diff_geom.difference(tmpGeom))
                    if diff_geom.isGeosEmpty():
                        ProcessingLog.addToLog(
                            ProcessingLog.LOG_INFO,
                            self.tr('Feature with NULL geometry found.'))
                    if not diff_geom.isGeosValid():
                        if ignoreInvalid:
                            ProcessingLog.addToLog(
                                ProcessingLog.LOG_ERROR,
                                self.
                                tr('GEOS geoprocessing error: One or more input features have invalid geometry.'
                                   ))
                            add = False
                        else:
                            raise GeoAlgorithmExecutionException(
                                self.
                                tr('Features with invalid geometries found. Please fix these errors or specify the "Ignore invalid input features" flag'
                                   ))
                        break

            if add:
                try:
                    outFeat.setGeometry(diff_geom)
                    outFeat.setAttributes(attrs)
                    writer.addFeature(outFeat)
                except:
                    ProcessingLog.addToLog(
                        ProcessingLog.LOG_WARNING,
                        self.
                        tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                           ))
                    continue

            progress.setPercentage(int(current * total))

        del writer
Example #51
0
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        self.progress = 0
        # extent = self.parameterAsExtent(parameters, self.EXTENT, context)
        workspace = self.parameterAsFile(parameters, self.INPUT, context)
        output = self.parameterAsFileOutput(parameters, self.OUTPUT, context)

        # if not extent:
        #     raise_exception('can\'t read extent')

        if not workspace:
            raise_exception('can\'t get wokrspace')

        if not output:
            raise_exception('can\'t get an output')

        feedback.pushInfo(tr('The algorithm is running'))

        dummy = QgsVectorLayer(workspace, "dummy", "ogr")
        sublyrs = dummy.dataProvider().subLayers()

        layers = []
        for sublyr in sublyrs:
            name = sublyr.split('!!::!!')[1]
            uri = "%s|layername=%s" % (workspace, name)
            layer = QgsVectorLayer(uri, name, "ogr")
            layers.append(layer)

        for layer in layers:
            features = list(layer.getFeatures())
            features_count = len(features)
            fields = layer.dataProvider().fields()
            indexes = [fields.indexFromName(field.name()) for field in fields]

            unique_values_per_field = {key: set() for key in indexes}
            points_num = 0
            total_length = 0
            bend_num = 0
            total_bend_area = 0.0
            ave_bend_base_line_len = 0.0
            ave_bend_height = 0.0
            ave_bend_length = 0.0
            total_polygon_area = 0.0
            count = 0.0
            total_intersections = 0

            total = 100.0 / features_count if features_count > 0 else 0

            for current, feature in enumerate(features):
                if feedback.isCanceled():
                    break

                update_unique_values(feature, indexes, unique_values_per_field)
                geom = feature.geometry()
                is_single_type = QgsWkbTypes.isSingleType(geom.wkbType())

                if geom.type() == QgsWkbTypes.LineGeometry:
                    total_length += geom.length()

                    if is_single_type:
                        data_list = [(v.x(), v.y()) for v in geom.vertices()]

                        if len(data_list) < 3:
                            continue

                        result = get(data_list)
                        count = count + 1
                        points_num += result[0]
                        bend_num += result[1]
                        total_bend_area += result[2]
                        ave_bend_base_line_len += result[3]
                        ave_bend_height += result[4]
                        ave_bend_length += result[5]
                    else:
                        for part in geom.parts():
                            data_list = [(v.x(), v.y())
                                         for v in part.vertices()]

                            if len(data_list) < 3:
                                continue

                            result = get(data_list)
                            count = count + 1
                            points_num += result[0]
                            bend_num += result[1]
                            total_bend_area += result[2]
                            ave_bend_base_line_len += result[3]
                            ave_bend_height += result[4]
                            ave_bend_length += result[5]
                elif geom.type() == QgsWkbTypes.PolygonGeometry:
                    total_length += geom.length()

                    if is_single_type:
                        data_list = [(v.x(), v.y()) for v in geom.vertices()]

                        if len(data_list) < 3:
                            continue

                        result = get(data_list)
                        count = count + 1
                        points_num += result[0]
                        bend_num += result[1]
                        total_bend_area += result[2]
                        ave_bend_base_line_len += result[3]
                        ave_bend_height += result[4]
                        ave_bend_length += result[5]
                        total_polygon_area += geom.area()
                    else:
                        for part in geom.parts():
                            data_list = [(v.x(), v.y())
                                         for v in part.vertices()]

                            if len(data_list) < 3:
                                continue

                            result = get(data_list)
                            count = count + 1
                            points_num += result[0]
                            bend_num += result[1]
                            total_bend_area += result[2]
                            ave_bend_base_line_len += result[3]
                            ave_bend_height += result[4]
                            ave_bend_length += result[5]
                        total_polygon_area += geom.area()
                else:
                    break

                self.progress = int(current * total)
                feedback.setProgress(self.progress)

            uniq_values_number = get_unique_values_ratio(
                unique_values_per_field, features_count)
            ave_uniq_values_number = get_ave_unique_values_ratio(
                uniq_values_number, len(fields))

            feedback.pushInfo('Total intersections:')
            filtered_layers = filter_layers([layer])

            if filtered_layers:
                total_intersections = len(
                    get_total_intersection(filtered_layers[0], feedback))

            header = [
                'workspace',
                'layer',
                'field_count',
                'features_count',
                'uniq_values_number',
                'average_uniq_values',
                'total_length',
                'number_of_points',
                'number_of_bends',
                'average_area_of_bends',
                'average_length_of_bends_baseline',
                'average_height_of_bends',
                'average_length_of_the_bends',
                'total_polygons_area',
                'average_polygons_area',
                'average_length',
                'layer_type',
                'total_bends_area',
                'total_intersections',
            ]
            row = [{
                header[0]:
                os.path.basename(os.path.normpath(workspace)),
                header[1]:
                layer.name(),
                header[2]:
                len(fields),
                header[3]:
                features_count,
                header[4]:
                uniq_values_number,
                header[5]:
                ave_uniq_values_number,
                header[6]:
                get_formatted_result(total_length),
                header[7]:
                points_num,
                header[8]:
                bend_num,
                header[9]:
                get_formatted_result(total_bend_area /
                                     bend_num) if bend_num > 0 else 0.0,
                header[10]:
                get_formatted_result(ave_bend_base_line_len /
                                     bend_num) if bend_num > 0 else 0.0,
                header[11]:
                get_formatted_result(ave_bend_height /
                                     bend_num) if bend_num > 0 else 0.0,
                header[12]:
                get_formatted_result(ave_bend_length /
                                     bend_num) if bend_num > 0 else 0.0,
                header[13]:
                get_formatted_result(total_polygon_area),
                header[14]:
                get_formatted_result(total_polygon_area /
                                     count) if count > 0 else 0.0,
                header[15]:
                get_formatted_result(total_length /
                                     count) if count > 0 else 0.0,
                header[16]:
                QgsWkbTypes.geometryDisplayString(int(layer.geometryType())),
                header[17]:
                get_formatted_result(total_bend_area),
                header[18]:
                get_formatted_result(total_intersections),
            }]

            if output:
                feedback.pushInfo(tr('Writing to file'))
                write_to_file(output, header, row, ';')

        return row[0]
Example #52
0
    def update_available_layers(self):
        self.trw_layers.setUpdatesEnabled(False) # Don't render until we're ready

        # Grab some context data
        show_domains = self.chk_show_domains.isChecked()
        show_structures = self.chk_show_structures.isChecked()
        show_associations = self.chk_show_associations.isChecked()
        top_level_items_expanded_info = []
        for i in range(self.trw_layers.topLevelItemCount()):
            top_level_items_expanded_info.append(self.trw_layers.topLevelItem(i).isExpanded())

        # Save selection
        self.update_selected_items()

        # Iterate models adding children
        self.trw_layers.blockSignals(True) # We don't want to get itemSelectionChanged here
        self.trw_layers.clear()
        self.trw_layers.blockSignals(False)

        sorted_models = sorted(self.models_tree.keys())
        for model in sorted_models:
            children = []
            model_item = QTreeWidgetItem([model])

            # Filter by search text
            list_tables = self.filter_tables_by_search_text(self.models_tree[model].keys(), self.txt_search_text.text())
            sorted_tables = sorted(list_tables)

            for table in sorted_tables:
                current_table_info = self.models_tree[model][table]
                if current_table_info[KIND_SETTINGS] == TABLE_PROP_DOMAIN and not show_domains \
                   or current_table_info[KIND_SETTINGS] == TABLE_PROP_STRUCTURE and not show_structures \
                   or current_table_info[KIND_SETTINGS] == TABLE_PROP_ASSOCIATION and not show_associations:
                    continue

                table_item = QTreeWidgetItem([table])
                table_item.setData(0, Qt.UserRole, self.models_tree[model][table])
                geometry_type = QgsWkbTypes().geometryType(QgsWkbTypes().parseType(current_table_info[GEOMETRY_TYPE])) if current_table_info[GEOMETRY_TYPE] else None
                icon_name = self.icon_names[3 if geometry_type is None else geometry_type]

                # Is the layer already loaded?
                if self.qgis_utils.get_layer_from_layer_tree(current_table_info[TABLE_NAME],
                         self._db.schema,
                         geometry_type) is not None:
                    table_item.setText(0, table + QCoreApplication.translate("DialogLoadLayers",
                                               " [already loaded]"))
                    table_item.setData(0, Qt.ForegroundRole, QBrush(Qt.lightGray))
                    table_item.setFlags(Qt.ItemIsEnabled) # Not selectable
                else: # Laye not in QGIS Layer Tree
                    if not current_table_info[KIND_SETTINGS]: # This is a class
                        font = QFont()
                        font.setBold(True)
                        table_item.setData(0, Qt.FontRole, font)

                if current_table_info[KIND_SETTINGS] == TABLE_PROP_DOMAIN:
                    icon_name = self.icon_names[4]
                elif current_table_info[KIND_SETTINGS] == TABLE_PROP_STRUCTURE:
                    icon_name = self.icon_names[5]
                elif current_table_info[KIND_SETTINGS] == TABLE_PROP_ASSOCIATION:
                    icon_name = self.icon_names[6]
                icon = QIcon(":/Asistente-LADM_COL/resources/images/{}.png".format(icon_name))
                table_item.setData(0, Qt.DecorationRole, icon)

                children.append(table_item)

            model_item.addChildren(children)
            self.trw_layers.addTopLevelItem(model_item)

        # Set selection
        iterator = QTreeWidgetItemIterator(self.trw_layers, QTreeWidgetItemIterator.Selectable)
        self.trw_layers.blockSignals(True) # We don't want to get itemSelectionChanged here
        while iterator.value():
            item = iterator.value()
            if item.text(0) in self.selected_items_dict:
                item.setSelected(True)

            iterator += 1

        self.trw_layers.blockSignals(False)

        # Make model items non selectable
        # Set expand taking previous states into account
        for i in range(self.trw_layers.topLevelItemCount()):
            self.trw_layers.topLevelItem(i).setFlags(Qt.ItemIsEnabled) # Not selectable
            self.trw_layers.topLevelItem(i).setExpanded(top_level_items_expanded_info[i] if top_level_items_expanded_info else True)

        self.trw_layers.setUpdatesEnabled(True) # Now render!
Example #53
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 #54
0
    def convert_vector_layer(
            layer,  # pylint: disable=too-many-locals,too-many-branches,too-many-statements
            project,
            data_folder,
            feedback,
            conversion_results: ConversionResults,
            change_source_on_error: bool = False,
            verbose_log=False):
        """
        Converts a vector layer to a standard format
        """
        if layer.customProperty('original_uri'):
            uri = layer.customProperty('original_uri')
            if verbose_log:
                feedback.pushDebugInfo(
                    f'Original layer URI from custom properties is {uri}')
        else:
            uri = layer.source()
            if verbose_log:
                feedback.pushDebugInfo(
                    'Original layer URI not found in custom properties')

        source = QgsProviderRegistry.instance().decodeUri(
            layer.providerType(), uri)
        if verbose_log:
            feedback.pushInfo('')

        # older versions of QGIS didn't correctly strip out the subset from the layerName:
        if 'subset' not in source:
            if '|subset=' in source['layerName']:
                if verbose_log:
                    feedback.pushDebugInfo(
                        'Stripping out subset string from layerName: {}'.
                        format(source['layerName']))
                layer_name = source['layerName']
                parts = layer_name.split('|subset=')
                if len(parts) == 2:
                    source['layerName'] = parts[0]
                    if verbose_log:
                        feedback.pushDebugInfo('Cleaned layer name: {}'.format(
                            source['layerName']))
                elif verbose_log:
                    feedback.reportError('Failed to strip subset string!')
            elif '|subset=' in source['path']:
                path = source['path']
                if verbose_log:
                    feedback.pushDebugInfo(
                        'Stripping out subset string from path: {}'.format(
                            source['path']))
                parts = path.split('|subset=')
                if len(parts) == 2:
                    source['path'] = parts[0]
                    if verbose_log:
                        feedback.pushDebugInfo('Cleaned path: {}'.format(
                            source['path']))
                elif verbose_log:
                    feedback.reportError('Failed to strip subset string!')

        # convert to Geopackage
        source_uri = QgsProviderRegistry.instance().encodeUri(
            layer.providerType(), {
                'path': source['path'],
                'layerName': source['layerName']
            })

        # Sometimes the case varies in ArcMap documents, so when comparing to previously converted layers
        # we use a case-insensitive path/layername which is normalized
        result_key = QgsProviderRegistry.instance().encodeUri(
            layer.providerType(), {
                'path': pathlib.Path(
                    source['path']).resolve().as_posix().lower(),
                'layerName': source['layerName'].lower()
            })

        if verbose_log:
            feedback.pushDebugInfo('Converting layer: {} ( {} )'.format(
                source['path'], source['layerName']))
            feedback.pushDebugInfo(f'Cached result key: {result_key}')

        provider_options = QgsDataProvider.ProviderOptions()
        provider_options.transformContext = project.transformContext()
        subset = layer.subsetString()

        # have we maybe already converted this layer??
        if result_key in conversion_results.layer_map:

            previous_results = conversion_results.layer_map[result_key]
            if previous_results.get('error'):
                if verbose_log:
                    feedback.pushDebugInfo(
                        'Already tried to convert this layer, but failed last time, skipping...'
                    )
                    feedback.pushDebugInfo('Restoring stored URI')

                layer.setDataSource(uri, layer.name(), 'ogr', provider_options)
            else:
                if verbose_log:
                    feedback.pushDebugInfo(
                        'Already converted this layer, reusing previous converted path: {} layername: {}'
                        .format(previous_results['destPath'],
                                previous_results['destLayer']))

                layer.setDataSource(
                    QgsProviderRegistry.instance().encodeUri(
                        'ogr', {
                            'path': previous_results['destPath'],
                            'layerName': previous_results['destLayer']
                        }), layer.name(), 'ogr', provider_options)
                if verbose_log:
                    feedback.pushDebugInfo('new source {}'.format(
                        layer.dataProvider().dataSourceUri()))
            if subset:
                if verbose_log:
                    feedback.pushDebugInfo(
                        'Resetting subset string: {}'.format(subset))
                layer.setSubsetString(subset)

            return previous_results

        source_layer = QgsVectorLayer(source_uri, '', layer.providerType())

        path = pathlib.Path(source['path'])

        dest_file_name = ((pathlib.Path(data_folder) /
                           path.stem).with_suffix('.gpkg')).as_posix()
        if dest_file_name not in conversion_results.created_databases:
            # about to use a new file -- let's double-check that it doesn't already exist. We don't want
            # to put layers into a database which we didn't make for this project
            counter = 1
            while pathlib.Path(dest_file_name).exists():
                counter += 1
                dest_file_name = ((pathlib.Path(data_folder) /
                                   (path.stem + '_' + str(counter))
                                   ).with_suffix('.gpkg')).as_posix()
                if dest_file_name in conversion_results.created_databases:
                    break

            if verbose_log:
                feedback.pushDebugInfo(
                    'Creating new destination file {}'.format(dest_file_name))
        elif verbose_log:
            feedback.pushDebugInfo(
                'Reusing existing destination file {}'.format(dest_file_name))

        # now this filename is ok for other layers to be stored in for this conversion
        conversion_results.created_databases.add(dest_file_name)

        layer_name_candidate = source['layerName']
        counter = 1
        while QgsVectorFileWriter.targetLayerExists(dest_file_name,
                                                    layer_name_candidate):
            counter += 1
            layer_name_candidate = '{}_{}'.format(source['layerName'], counter)

        if verbose_log:
            feedback.pushDebugInfo(
                'Target layer name is {}'.format(layer_name_candidate))

        if not source_layer.isValid():
            if verbose_log:
                feedback.reportError('Source layer is not valid')
            if path.exists():
                if verbose_log:
                    feedback.pushDebugInfo('File path DOES exist')

                    test_layer = QgsVectorLayer(path.as_posix())
                    sub_layers = test_layer.dataProvider().subLayers()
                    feedback.pushDebugInfo(
                        f'Readable layers from "{path.as_posix()}" are:')
                    for sub_layer in sub_layers:
                        _, name, count, geom_type, _, _ = sub_layer.split(
                            QgsDataProvider.sublayerSeparator())
                        feedback.pushDebugInfo(
                            f'- "{name}" ({count} features, geometry type {geom_type})'
                        )

            if path.exists() and path.suffix.lower() == '.mdb':
                try:
                    source['layerName'].encode('ascii')
                except UnicodeDecodeError:
                    error = f'''MDB layers with unicode names are not supported by QGIS -- cannot convert "{source['layerName']}"'''
                    if verbose_log:
                        feedback.reportError(error)
                        feedback.pushDebugInfo('Restoring stored URI')

                    layer.setDataSource(uri, layer.name(), 'ogr',
                                        provider_options)
                    if subset:
                        if verbose_log:
                            feedback.pushDebugInfo(
                                'Resetting subset string: {}'.format(subset))
                        layer.setSubsetString(subset)

                    conversion_results.layer_map[result_key] = {'error': error}
                    return conversion_results.layer_map[result_key]

                # maybe a non-spatial table, which can't be read with GDAL < 3.2
                source_layer = None

                if verbose_log:
                    feedback.pushDebugInfo('Layer type is {}'.format(
                        QgsWkbTypes.displayString(layer.wkbType())))

                if layer.wkbType() == QgsWkbTypes.NoGeometry:
                    if verbose_log:
                        feedback.pushDebugInfo(
                            'Attempting fallback for non-spatial tables')
                    try:
                        source_layer = ConversionUtils.convert_mdb_table_to_memory_layer(
                            str(path), source['layerName'])
                        if verbose_log:
                            feedback.pushDebugInfo('Fallback succeeded!')
                    except Exception as e:  # nopep8, pylint: disable=broad-except
                        if verbose_log:
                            feedback.reportError('Fallback failed: {}'.format(
                                str(e)))
                        source_layer = None
                elif verbose_log:
                    feedback.reportError(
                        'Nothing else to try, conversion failed')

                if not source_layer:
                    # here we fake things. We don't leave the original path to the mdb layer intact in the converted
                    # project, as this can cause massive issues with QGIS as it attempts to re-read this path constantly
                    # rather we "pretend" that the conversion was ok and set the broken layer's path to what the gpkg
                    # converted version WOULD have been! It'll still be broken in the converted project (obviously),
                    # but QGIS will no longer try endless to read the MDB and get all hung up on this...
                    conversion_results.layer_map[result_key] = {
                        'sourcePath':
                        source['path'],
                        'sourceLayer':
                        source['layerName'],
                        'destPath':
                        dest_file_name,
                        'destLayer':
                        layer_name_candidate,
                        'error':
                        'Could not open {} ({}) for conversion'.format(
                            source_uri, source['layerName'])
                    }

                    if change_source_on_error:
                        if verbose_log:
                            feedback.pushDebugInfo('Restoring stored URI')

                        layer.setDataSource(uri, layer.name(), 'ogr',
                                            provider_options)
                        if subset:
                            if verbose_log:
                                feedback.pushDebugInfo(
                                    'Resetting subset string: {}'.format(
                                        subset))
                            layer.setSubsetString(subset)
                        if verbose_log:
                            feedback.pushDebugInfo('new source {}'.format(
                                layer.dataProvider().dataSourceUri()))

                    return conversion_results.layer_map[result_key]
            else:
                if not path.exists():
                    error = 'The referenced file {} does NOT exist!'.format(
                        str(path))
                else:
                    error = 'The referenced file exists, but could not open {} ({}) for conversion'.format(
                        source_uri, source['layerName'])

                if verbose_log:
                    feedback.reportError(error)
                    feedback.pushDebugInfo('Restoring stored URI')

                layer.setDataSource(uri, layer.name(), 'ogr', provider_options)
                if subset:
                    if verbose_log:
                        feedback.pushDebugInfo(
                            'Resetting subset string: {}'.format(subset))
                    layer.setSubsetString(subset)

                conversion_results.layer_map[result_key] = {'error': error}
                return conversion_results.layer_map[result_key]

        if verbose_log:
            feedback.pushDebugInfo('Source is valid, converting')

        options = QgsVectorFileWriter.SaveVectorOptions()

        options.layerName = layer_name_candidate
        options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer if pathlib.Path(
            dest_file_name).exists(
            ) else QgsVectorFileWriter.CreateOrOverwriteFile
        options.feedback = feedback

        error, error_message = QgsVectorFileWriter.writeAsVectorFormatV2(
            source_layer, dest_file_name, project.transformContext(), options)
        if error != QgsVectorFileWriter.NoError:
            if verbose_log:
                feedback.reportError('Failed: {}'.format(error_message))
                feedback.pushDebugInfo('Restoring stored URI')

            layer.setDataSource(uri, layer.name(), 'ogr', provider_options)
            if subset:
                if verbose_log:
                    feedback.pushDebugInfo(
                        'Resetting subset string: {}'.format(subset))
                layer.setSubsetString(subset)

            conversion_results.layer_map[result_key] = {'error': error_message}
            return conversion_results.layer_map[result_key]

        if verbose_log:
            feedback.pushDebugInfo('Success!')

        provider_options = QgsDataProvider.ProviderOptions()
        provider_options.transformContext = project.transformContext()
        subset = layer.subsetString()
        layer.setDataSource(
            QgsProviderRegistry.instance().encodeUri(
                'ogr', {
                    'path': dest_file_name,
                    'layerName': options.layerName
                }), layer.name(), 'ogr', provider_options)
        if subset:
            if verbose_log:
                feedback.pushDebugInfo(
                    'Resetting subset string: {}'.format(subset))
            layer.setSubsetString(subset)

        if verbose_log:
            feedback.pushDebugInfo('new source {}'.format(
                layer.dataProvider().dataSourceUri()))

        conversion_results.layer_map[result_key] = {
            'sourcePath': source['path'],
            'sourceLayer': source['layerName'],
            'destPath': dest_file_name,
            'destLayer': options.layerName
        }

        return conversion_results.layer_map[result_key]
    def testWriteShapefileWithSingleConversion(self):
        """Check writing geometries from a POLYGON ESRI shapefile does not
        convert to multi when "forceSinglePartGeometryType" options is TRUE
        also checks failing cases.

        OGR provider always report MULTI for POLYGON and LINESTRING, but if we set
        the import option "forceSinglePartGeometryType" the writer must respect the
        actual single-part type if the features in the data provider are actually single
        and not multi.
        """

        ml = QgsVectorLayer(
            ('Polygon?crs=epsg:4326&field=id:int'),
            'test',
            'memory')

        provider = ml.dataProvider()
        ft = QgsFeature()
        ft.setGeometry(QgsGeometry.fromWkt('Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))'))
        ft.setAttributes([1])
        res, features = provider.addFeatures([ft])

        dest_file_name = os.path.join(self.basetestpath, 'multipart.shp')
        write_result, error_message = QgsVectorLayerExporter.exportLayer(ml,
                                                                         dest_file_name,
                                                                         'ogr',
                                                                         ml.crs(),
                                                                         False,
                                                                         {"driverName": "ESRI Shapefile"}
                                                                         )
        self.assertEqual(write_result, QgsVectorLayerExporter.NoError, error_message)

        # Open the newly created layer
        shapefile_layer = QgsVectorLayer(dest_file_name)

        dest_singlepart_file_name = os.path.join(self.basetestpath, 'singlepart.gpkg')
        write_result, error_message = QgsVectorLayerExporter.exportLayer(shapefile_layer,
                                                                         dest_singlepart_file_name,
                                                                         'ogr',
                                                                         shapefile_layer.crs(),
                                                                         False,
                                                                         {
                                                                             "forceSinglePartGeometryType": True,
                                                                             "driverName": "GPKG",
                                                                         })
        self.assertEqual(write_result, QgsVectorLayerExporter.NoError, error_message)

        # Load result layer and check that it's NOT MULTI
        single_layer = QgsVectorLayer(dest_singlepart_file_name)
        self.assertTrue(single_layer.isValid())
        self.assertTrue(QgsWkbTypes.isSingleType(single_layer.wkbType()))

        # Now save the shapfile layer into a gpkg with no force options
        dest_multipart_file_name = os.path.join(self.basetestpath, 'multipart.gpkg')
        write_result, error_message = QgsVectorLayerExporter.exportLayer(shapefile_layer,
                                                                         dest_multipart_file_name,
                                                                         'ogr',
                                                                         shapefile_layer.crs(),
                                                                         False,
                                                                         {
                                                                             "forceSinglePartGeometryType": False,
                                                                             "driverName": "GPKG",
                                                                         })
        self.assertEqual(write_result, QgsVectorLayerExporter.NoError, error_message)
        # Load result layer and check that it's MULTI
        multi_layer = QgsVectorLayer(dest_multipart_file_name)
        self.assertTrue(multi_layer.isValid())
        self.assertTrue(QgsWkbTypes.isMultiType(multi_layer.wkbType()))

        # Failing case: add a real multi to the shapefile and try to force to single
        self.assertTrue(shapefile_layer.startEditing())
        ft = QgsFeature()
        ft.setGeometry(QgsGeometry.fromWkt('MultiPolygon (((0 0, 0 1, 1 1, 1 0, 0 0)), ((-10 -10,-10 -9,-9 -9,-10 -10)))'))
        ft.setAttributes([2])
        self.assertTrue(shapefile_layer.addFeatures([ft]))
        self.assertTrue(shapefile_layer.commitChanges())

        dest_multipart_failure_file_name = os.path.join(self.basetestpath, 'multipart_failure.gpkg')
        write_result, error_message = QgsVectorLayerExporter.exportLayer(shapefile_layer,
                                                                         dest_multipart_failure_file_name,
                                                                         'ogr',
                                                                         shapefile_layer.crs(),
                                                                         False,
                                                                         {
                                                                             "forceSinglePartGeometryType": True,
                                                                             "driverName": "GPKG",
                                                                         })
        self.assertTrue(QgsWkbTypes.isMultiType(multi_layer.wkbType()))
        self.assertEqual(write_result, QgsVectorLayerExporter.ErrFeatureWriteFailed, "Failed to transform a feature with ID '1' to single part. Writing stopped.")
Example #56
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()
        x_field_index = fields.lookupField(self.parameterAsString(parameters, self.XFIELD, context))
        y_field_index = fields.lookupField(self.parameterAsString(parameters, self.YFIELD, context))
        z_field_index = -1
        if self.parameterAsString(parameters, self.ZFIELD, context):
            z_field_index = fields.lookupField(self.parameterAsString(parameters, self.ZFIELD, context))
        m_field_index = -1
        if self.parameterAsString(parameters, self.MFIELD, context):
            m_field_index = fields.lookupField(self.parameterAsString(parameters, self.MFIELD, context))

        wkb_type = QgsWkbTypes.Point
        if z_field_index >= 0:
            wkb_type = QgsWkbTypes.addZ(wkb_type)
        if m_field_index >= 0:
            wkb_type = QgsWkbTypes.addM(wkb_type)

        target_crs = self.parameterAsCrs(parameters, self.TARGET_CRS, context)

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               fields, wkb_type, target_crs)
        if sink is None:
            raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))

        request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry)
        features = source.getFeatures(QgsFeatureRequest(), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks)
        total = 100.0 / source.featureCount() if source.featureCount() else 0

        for current, feature in enumerate(features):
            if feedback.isCanceled():
                break

            feedback.setProgress(int(current * total))
            attrs = feature.attributes()

            try:
                x = float(attrs[x_field_index])
                y = float(attrs[y_field_index])

                point = QgsPoint(x, y)

                if z_field_index >= 0:
                    try:
                        point.addZValue(float(attrs[z_field_index]))
                    except:
                        point.addZValue(0.0)

                if m_field_index >= 0:
                    try:
                        point.addMValue(float(attrs[m_field_index]))
                    except:
                        point.addMValue(0.0)

                feature.setGeometry(QgsGeometry(point))
            except:
                pass  # no geometry

            sink.addFeature(feature)

        return {self.OUTPUT: dest_id}
Example #57
0
    def processFeature(self, feature, feedback):
        if feature.hasGeometry():
            geom = feature.geometry()
            geomType = QgsWkbTypes.flatType(geom.wkbType())
            newGeom = None

            if geomType == QgsWkbTypes.Point:
                points = self._gridify([geom.asPoint()], self.h_spacing,
                                       self.v_spacing)
                newGeom = QgsGeometry.fromPoint(points[0])
            elif geomType == QgsWkbTypes.MultiPoint:
                points = self._gridify(geom.asMultiPoint(), self.h_spacing,
                                       self.v_spacing)
                newGeom = QgsGeometry.fromMultiPoint(points)
            elif geomType == QgsWkbTypes.LineString:
                points = self._gridify(geom.asPolyline(), self.h_spacing,
                                       self.v_spacing)
                if len(points) < 2:
                    feedback.reportError(
                        self.tr(
                            'Failed to gridify feature with FID {0}').format(
                                feature.id()))
                    newGeom = None
                else:
                    newGeom = QgsGeometry.fromPolyline(points)
            elif geomType == QgsWkbTypes.MultiLineString:
                polyline = []
                for line in geom.asMultiPolyline():
                    points = self._gridify(line, self.h_spacing,
                                           self.v_spacing)
                    if len(points) > 1:
                        polyline.append(points)
                if len(polyline) <= 0:
                    feedback.reportError(
                        self.tr(
                            'Failed to gridify feature with FID {0}').format(
                                feature.id()))
                    newGeom = None
                else:
                    newGeom = QgsGeometry.fromMultiPolyline(polyline)

            elif geomType == QgsWkbTypes.Polygon:
                polygon = []
                for line in geom.asPolygon():
                    points = self._gridify(line, self.h_spacing,
                                           self.v_spacing)
                    if len(points) > 1:
                        polygon.append(points)
                if len(polygon) <= 0:
                    feedback.reportError(
                        self.tr(
                            'Failed to gridify feature with FID {0}').format(
                                feature.id()))
                    newGeom = None
                else:
                    newGeom = QgsGeometry.fromPolygon(polygon)
            elif geomType == QgsWkbTypes.MultiPolygon:
                multipolygon = []
                for polygon in geom.asMultiPolygon():
                    newPolygon = []
                    for line in polygon:
                        points = self._gridify(line, self.h_spacing,
                                               self.v_spacing)
                        if len(points) > 2:
                            newPolygon.append(points)

                    if len(newPolygon) > 0:
                        multipolygon.append(newPolygon)

                if len(multipolygon) <= 0:
                    feedback.reportError(
                        self.tr(
                            'Failed to gridify feature with FID {0}').format(
                                feature.id()))
                    newGeom = None
                else:
                    newGeom = QgsGeometry.fromMultiPolygon(multipolygon)

            if newGeom is not None:
                feature.setGeometry(newGeom)
            else:
                feature.clearGeometry()
        return feature
Example #58
0
    def testWriteShapefileWithZ(self):
        """Check writing geometries with Z dimension to an ESRI shapefile."""

        # start by saving a memory layer and forcing z
        ml = QgsVectorLayer(('Point?crs=epsg:4326&field=id:int'), 'test',
                            'memory')

        self.assertIsNotNone(ml, 'Provider not initialized')
        self.assertTrue(ml.isValid(), 'Source layer not valid')
        provider = ml.dataProvider()
        self.assertIsNotNone(provider)

        ft = QgsFeature()
        ft.setGeometry(QgsGeometry.fromWkt('PointZ (1 2 3)'))
        ft.setAttributes([1])
        res, features = provider.addFeatures([ft])
        self.assertTrue(res)
        self.assertTrue(features)

        # check with both a standard PointZ and 25d style Point25D type
        for t in [QgsWkbTypes.PointZ, QgsWkbTypes.Point25D]:
            dest_file_name = os.path.join(
                str(QDir.tempPath()),
                'point_{}.shp'.format(QgsWkbTypes.displayString(t)))
            crs = QgsCoordinateReferenceSystem()
            crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
            write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
                ml,
                dest_file_name,
                'utf-8',
                crs,
                'ESRI Shapefile',
                overrideGeometryType=t)
            self.assertEqual(write_result, QgsVectorFileWriter.NoError,
                             error_message)

            # Open result and check
            created_layer = QgsVectorLayer(
                '{}|layerid=0'.format(dest_file_name), 'test', 'ogr')
            f = next(created_layer.getFeatures(QgsFeatureRequest()))
            g = f.geometry()
            wkt = g.asWkt()
            expWkt = 'PointZ (1 2 3)'
            self.assertTrue(
                compareWkt(expWkt, wkt),
                "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n"
                % (expWkt, wkt))

            # also try saving out the shapefile version again, as an extra test
            # this tests that saving a layer with z WITHOUT explicitly telling the writer to keep z values,
            # will stay retain the z values
            dest_file_name = os.path.join(
                str(QDir.tempPath()),
                'point_{}_copy.shp'.format(QgsWkbTypes.displayString(t)))
            crs = QgsCoordinateReferenceSystem()
            crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
            write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
                created_layer, dest_file_name, 'utf-8', crs, 'ESRI Shapefile')
            self.assertEqual(write_result, QgsVectorFileWriter.NoError,
                             error_message)

            # Open result and check
            created_layer_from_shp = QgsVectorLayer(
                '{}|layerid=0'.format(dest_file_name), 'test', 'ogr')
            f = next(created_layer_from_shp.getFeatures(QgsFeatureRequest()))
            g = f.geometry()
            wkt = g.asWkt()
            self.assertTrue(
                compareWkt(expWkt, wkt),
                "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n"
                % (expWkt, wkt))
Example #59
0
    def processAlgorithm(self, feedback):
        layerA = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT))
        layerB = dataobjects.getObjectFromUri(
            self.getParameterValue(self.OVERLAY))

        geomType = QgsWkbTypes.multiType(layerA.wkbType())
        fields = vector.combineVectorFields(layerA, layerB)
        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fields, geomType, layerA.crs())

        featB = QgsFeature()
        outFeat = QgsFeature()

        indexA = vector.spatialindex(layerB)
        indexB = vector.spatialindex(layerA)

        featuresA = vector.features(layerA)
        featuresB = vector.features(layerB)

        total = 100.0 / (len(featuresA) * len(featuresB))
        count = 0

        for featA in featuresA:
            geom = featA.geometry()
            diffGeom = QgsGeometry(geom)
            attrs = featA.attributes()
            intersects = indexA.intersects(geom.boundingBox())
            request = QgsFeatureRequest().setFilterFids(
                intersects).setSubsetOfAttributes([])
            for featB in layerB.getFeatures(request):
                tmpGeom = featB.geometry()
                if diffGeom.intersects(tmpGeom):
                    diffGeom = QgsGeometry(diffGeom.difference(tmpGeom))

            try:
                outFeat.setGeometry(diffGeom)
                outFeat.setAttributes(attrs)
                writer.addFeature(outFeat)
            except:
                ProcessingLog.addToLog(
                    ProcessingLog.LOG_WARNING,
                    self.
                    tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                       ))
                continue

            count += 1
            feedback.setProgress(int(count * total))

        length = len(layerA.fields())

        for featA in featuresB:
            geom = featA.geometry()
            diffGeom = QgsGeometry(geom)
            attrs = featA.attributes()
            attrs = [NULL] * length + attrs
            intersects = indexB.intersects(geom.boundingBox())
            request = QgsFeatureRequest().setFilterFids(
                intersects).setSubsetOfAttributes([])
            for featB in layerA.getFeatures(request):
                tmpGeom = featB.geometry()
                if diffGeom.intersects(tmpGeom):
                    diffGeom = QgsGeometry(diffGeom.difference(tmpGeom))

            try:
                outFeat.setGeometry(diffGeom)
                outFeat.setAttributes(attrs)
                writer.addFeature(outFeat)
            except:
                ProcessingLog.addToLog(
                    ProcessingLog.LOG_WARNING,
                    self.
                    tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                       ))
                continue

            count += 1
            feedback.setProgress(int(count * total))

        del writer
Example #60
-2
    def prepareAlgorithm(self, parameters, context, feedback):
        self.geometry_type = self.parameterAsEnum(parameters, self.OUTPUT_GEOMETRY, context)
        self.wkb_type = None
        if self.geometry_type == 0:
            self.wkb_type = QgsWkbTypes.Polygon
        elif self.geometry_type == 1:
            self.wkb_type = QgsWkbTypes.LineString
        else:
            self.wkb_type = QgsWkbTypes.Point
        if self.parameterAsBool(parameters, self.WITH_Z, context):
            self.wkb_type = QgsWkbTypes.addZ(self.wkb_type)
        if self.parameterAsBool(parameters, self.WITH_M, context):
            self.wkb_type = QgsWkbTypes.addM(self.wkb_type)

        self.expression = QgsExpression(self.parameterAsString(parameters, self.EXPRESSION, context))
        if self.expression.hasParserError():
            feedback.reportError(self.expression.parserErrorString())
            return False

        self.expression_context = self.createExpressionContext(parameters, context)

        if not self.expression.prepare(self.expression_context):
            feedback.reportErro(
                self.tr('Evaluation error: {0}').format(self.expression.evalErrorString()))
            return False

        return True