def processAlgorithm(self, progress):
        polyLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.POLYGONS))
        pointLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.POINTS))
        fieldName = self.getParameterValue(self.FIELD)
        fieldIdx = pointLayer.fieldNameIndex(self.getParameterValue(self.WEIGHT))

        polyProvider = polyLayer.dataProvider()
        fields = polyProvider.fields()
        fields.append(QgsField(fieldName, QVariant.Int))

        (idxCount, fieldList) = vector.findOrCreateField(polyLayer,
                                                         polyLayer.pendingFields(), fieldName)

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fields.toList(), polyProvider.geometryType(), polyProvider.crs())

        spatialIndex = vector.spatialindex(pointLayer)

        ftPoint = QgsFeature()
        outFeat = QgsFeature()
        geom = QgsGeometry()

        features = vector.features(polyLayer)
        total = 100.0 / len(features)
        for current, ftPoly in enumerate(features):
            geom = ftPoly.geometry()
            engine = QgsGeometry.createGeometryEngine(geom.geometry())
            engine.prepareGeometry()

            attrs = ftPoly.attributes()

            count = 0
            points = spatialIndex.intersects(geom.boundingBox())
            if len(points) > 0:
                progress.setText(unicode(len(points)))
                request = QgsFeatureRequest().setFilterFids(points)
                fit = pointLayer.getFeatures(request)
                ftPoint = QgsFeature()
                while fit.nextFeature(ftPoint):
                    tmpGeom = QgsGeometry(ftPoint.geometry())
                    if engine.contains(tmpGeom.geometry()):
                        weight = unicode(ftPoint.attributes()[fieldIdx])
                        try:
                            count += float(weight)
                        except:
                            # Ignore fields with non-numeric values
                            pass

            outFeat.setGeometry(geom)
            if idxCount == len(attrs):
                attrs.append(count)
            else:
                attrs[idxCount] = count
            outFeat.setAttributes(attrs)
            writer.addFeature(outFeat)

            progress.setPercentage(int(current * total))

        del writer
    def processAlgorithm(self, progress):
        polyLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.POLYGONS))
        pointLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.POINTS))
        fieldName = self.getParameterValue(self.FIELD)
        classFieldName = self.getParameterValue(self.CLASSFIELD)

        polyProvider = polyLayer.dataProvider()
        fields = polyProvider.fields()
        fields.append(QgsField(fieldName, QVariant.Int))

        classFieldIndex = pointLayer.fieldNameIndex(classFieldName)
        (idxCount, fieldList) = vector.findOrCreateField(polyLayer,
                                                         polyLayer.pendingFields(), fieldName)

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fields.toList(), polyProvider.geometryType(), polyProvider.crs())

        spatialIndex = vector.spatialindex(pointLayer)

        ftPoint = QgsFeature()
        outFeat = QgsFeature()
        geom = QgsGeometry()

        current = 0

        features = vector.features(polyLayer)
        total = 100.0 / float(len(features))
        for ftPoly in features:
            geom = ftPoly.geometry()
            engine = QgsGeometry.createGeometryEngine(geom.geometry())
            engine.prepareGeometry()

            attrs = ftPoly.attributes()

            classes = set()
            points = spatialIndex.intersects(geom.boundingBox())
            if len(points) > 0:
                request = QgsFeatureRequest().setFilterFids(points)
                fit = pointLayer.getFeatures(request)
                ftPoint = QgsFeature()
                while fit.nextFeature(ftPoint):
                    tmpGeom = QgsGeometry(ftPoint.geometry())
                    if engine.contains(tmpGeom.geometry()):
                        clazz = ftPoint.attributes()[classFieldIndex]
                        if clazz not in classes:
                            classes.add(clazz)

            outFeat.setGeometry(geom)
            if idxCount == len(attrs):
                attrs.append(len(classes))
            else:
                attrs[idxCount] = len(classes)
            outFeat.setAttributes(attrs)
            writer.addFeature(outFeat)

            current += 1
            progress.setPercentage(current / total)

        del writer
    def processAlgorithm(self, parameters, context, feedback):
        polyLayer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.POLYGONS), context)
        pointLayer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.POINTS), context)
        fieldName = self.getParameterValue(self.FIELD)
        fieldIdx = pointLayer.fields().lookupField(self.getParameterValue(self.WEIGHT))

        fields = polyLayer.fields()
        fields.append(QgsField(fieldName, QVariant.Int))

        (idxCount, fieldList) = vector.findOrCreateField(polyLayer,
                                                         polyLayer.fields(), fieldName)

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, polyLayer.wkbType(),
                                                                     polyLayer.crs(), context)

        spatialIndex = QgsProcessingUtils.createSpatialIndex(pointLayer, context)

        ftPoint = QgsFeature()
        outFeat = QgsFeature()
        geom = QgsGeometry()

        features = QgsProcessingUtils.getFeatures(polyLayer, context)
        total = 100.0 / QgsProcessingUtils.featureCount(polyLayer, context)
        for current, ftPoly in enumerate(features):
            geom = ftPoly.geometry()
            engine = QgsGeometry.createGeometryEngine(geom.geometry())
            engine.prepareGeometry()

            attrs = ftPoly.attributes()

            count = 0
            points = spatialIndex.intersects(geom.boundingBox())
            if len(points) > 0:
                feedback.setProgressText(str(len(points)))
                request = QgsFeatureRequest().setFilterFids(points).setSubsetOfAttributes([fieldIdx])
                fit = pointLayer.getFeatures(request)
                ftPoint = QgsFeature()
                while fit.nextFeature(ftPoint):
                    tmpGeom = QgsGeometry(ftPoint.geometry())
                    if engine.contains(tmpGeom.geometry()):
                        weight = str(ftPoint.attributes()[fieldIdx])
                        try:
                            count += float(weight)
                        except:
                            # Ignore fields with non-numeric values
                            pass

            outFeat.setGeometry(geom)
            if idxCount == len(attrs):
                attrs.append(count)
            else:
                attrs[idxCount] = count
            outFeat.setAttributes(attrs)
            writer.addFeature(outFeat)

            feedback.setProgress(int(current * total))

        del writer
Exemple #4
0
    def processAlgorithm(self, parameters, context, feedback):
        polyLayer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.POLYGONS), context)
        pointLayer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.POINTS), context)
        fieldName = self.getParameterValue(self.FIELD)
        classFieldName = self.getParameterValue(self.CLASSFIELD)

        fields = polyLayer.fields()
        fields.append(QgsField(fieldName, QVariant.Int))

        classFieldIndex = pointLayer.fields().lookupField(classFieldName)
        (idxCount, fieldList) = vector.findOrCreateField(polyLayer,
                                                         polyLayer.fields(), fieldName)

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, polyLayer.wkbType(),
                                                                     polyLayer.crs(), context)

        spatialIndex = QgsProcessingUtils.createSpatialIndex(pointLayer, context)

        ftPoint = QgsFeature()
        outFeat = QgsFeature()
        geom = QgsGeometry()

        features = QgsProcessingUtils.getFeatures(polyLayer, context)
        total = 100.0 / polyLayer.featureCount() if polyLayer.featureCount() else 0
        for current, ftPoly in enumerate(features):
            geom = ftPoly.geometry()
            engine = QgsGeometry.createGeometryEngine(geom.geometry())
            engine.prepareGeometry()

            attrs = ftPoly.attributes()

            classes = set()
            points = spatialIndex.intersects(geom.boundingBox())
            if len(points) > 0:
                request = QgsFeatureRequest().setFilterFids(points).setSubsetOfAttributes([classFieldIndex])
                fit = pointLayer.getFeatures(request)
                ftPoint = QgsFeature()
                while fit.nextFeature(ftPoint):
                    tmpGeom = QgsGeometry(ftPoint.geometry())
                    if engine.contains(tmpGeom.geometry()):
                        clazz = ftPoint.attributes()[classFieldIndex]
                        if clazz not in classes:
                            classes.add(clazz)

            outFeat.setGeometry(geom)
            if idxCount == len(attrs):
                attrs.append(len(classes))
            else:
                attrs[idxCount] = len(classes)
            outFeat.setAttributes(attrs)
            writer.addFeature(outFeat, QgsFeatureSink.FastInsert)

            feedback.setProgress(int(current * total))

        del writer
Exemple #5
0
    def processAlgorithm(self, feedback):
        extent = str(self.getParameterValue(self.EXTENT)).split(',')

        spacing = float(self.getParameterValue(self.SPACING))
        inset = float(self.getParameterValue(self.INSET))
        randomize = self.getParameterValue(self.RANDOMIZE)
        isSpacing = self.getParameterValue(self.IS_SPACING)
        crsId = self.getParameterValue(self.CRS)
        crs = QgsCoordinateReferenceSystem()
        crs.createFromUserInput(crsId)

        extent = QgsRectangle(float(extent[0]), float(extent[2]),
                              float(extent[1]), float(extent[3]))

        fields = QgsFields()
        fields.append(QgsField('id', QVariant.Int, '', 10, 0))

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fields, QgsWkbTypes.Point, crs)

        if randomize:
            seed()

        area = extent.width() * extent.height()
        if isSpacing:
            pSpacing = spacing
        else:
            pSpacing = sqrt(area / spacing)

        f = QgsFeature()
        f.initAttributes(1)
        f.setFields(fields)

        count = 0
        total = 100.0 / (area / pSpacing)
        y = extent.yMaximum() - inset

        extent_geom = QgsGeometry.fromRect(extent)
        extent_engine = QgsGeometry.createGeometryEngine(extent_geom.geometry())
        extent_engine.prepareGeometry()

        while y >= extent.yMinimum():
            x = extent.xMinimum() + inset
            while x <= extent.xMaximum():
                if randomize:
                    geom = QgsGeometry().fromPoint(QgsPoint(
                        uniform(x - (pSpacing / 2.0), x + (pSpacing / 2.0)),
                        uniform(y - (pSpacing / 2.0), y + (pSpacing / 2.0))))
                else:
                    geom = QgsGeometry().fromPoint(QgsPoint(x, y))

                if extent_engine.intersects(geom.geometry()):
                    f.setAttribute('id', count)
                    f.setGeometry(geom)
                    writer.addFeature(f)
                    x += pSpacing
                    count += 1
                    feedback.setProgress(int(count * total))
            y = y - pSpacing
        del writer
Exemple #6
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_LAYER))

        if layer.geometryType() == QGis.Line:
            output_wkb = QGis.WKBMultiPoint
        elif layer.geometryType() == QGis.Polygon:
            output_wkb = QGis.WKBLineString

        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
            if input_feature.constGeometry():
                input_geometry = QgsGeometry(input_feature.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
Exemple #7
0
    def processAlgorithm(self, parameters, context, feedback):
        extent = self.parameterAsExtent(parameters, self.EXTENT, context)

        spacing = self.parameterAsDouble(parameters, self.SPACING, context)
        inset = self.parameterAsDouble(parameters, self.INSET, context)
        randomize = self.parameterAsBool(parameters, self.RANDOMIZE, context)
        isSpacing = self.parameterAsBool(parameters, self.IS_SPACING, context)
        crs = self.parameterAsCrs(parameters, self.CRS, context)

        fields = QgsFields()
        fields.append(QgsField('id', QVariant.Int, '', 10, 0))

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               fields, QgsWkbTypes.Point, crs)

        if randomize:
            seed()

        area = extent.width() * extent.height()
        if isSpacing:
            pSpacing = spacing
        else:
            pSpacing = sqrt(area / spacing)

        f = QgsFeature()
        f.initAttributes(1)
        f.setFields(fields)

        count = 0
        total = 100.0 / (area / pSpacing)
        y = extent.yMaximum() - inset

        extent_geom = QgsGeometry.fromRect(extent)
        extent_engine = QgsGeometry.createGeometryEngine(extent_geom.geometry())
        extent_engine.prepareGeometry()

        while y >= extent.yMinimum():
            x = extent.xMinimum() + inset
            while x <= extent.xMaximum():
                if feedback.isCanceled():
                    break

                if randomize:
                    geom = QgsGeometry().fromPoint(QgsPointXY(
                        uniform(x - (pSpacing / 2.0), x + (pSpacing / 2.0)),
                        uniform(y - (pSpacing / 2.0), y + (pSpacing / 2.0))))
                else:
                    geom = QgsGeometry().fromPoint(QgsPointXY(x, y))

                if extent_engine.intersects(geom.geometry()):
                    f.setAttribute('id', count)
                    f.setGeometry(geom)
                    sink.addFeature(f, QgsFeatureSink.FastInsert)
                    x += pSpacing
                    count += 1
                    feedback.setProgress(int(count * total))
            y = y - pSpacing

        return {self.OUTPUT: dest_id}
Exemple #8
0
def smart_clip(layer_to_clip, mask_layer, callback=None):
    """Smart clip a vector layer with another.

    Issue https://github.com/inasafe/inasafe/issues/3186

    :param layer_to_clip: The vector layer to clip.
    :type layer_to_clip: QgsVectorLayer

    :param mask_layer: The vector layer to use for clipping.
    :type mask_layer: QgsVectorLayer

    :param callback: A function to all to indicate progress. The function
        should accept params 'current' (int), 'maximum' (int) and 'step' (str).
        Defaults to None.
    :type callback: function

    :return: The clip vector layer.
    :rtype: QgsVectorLayer

    .. versionadded:: 4.0
    """
    output_layer_name = smart_clip_steps['output_layer_name']
    processing_step = smart_clip_steps['step_name']

    writer = create_memory_layer(
        output_layer_name,
        layer_to_clip.geometryType(),
        layer_to_clip.crs(),
        layer_to_clip.fields()
    )
    writer.startEditing()

    # first build up a list of clip geometries
    request = QgsFeatureRequest().setSubsetOfAttributes([])
    iterator = mask_layer.getFeatures(request)
    feature = next(iterator)
    geometries = QgsGeometry(feature.geometry())

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

    extent = mask_layer.extent()

    for feature in layer_to_clip.getFeatures(QgsFeatureRequest(extent)):

        if engine.intersects(feature.geometry().geometry()):
            out_feat = QgsFeature()
            out_feat.setGeometry(feature.geometry())
            out_feat.setAttributes(feature.attributes())
            writer.addFeature(out_feat)

    writer.commitChanges()

    writer.keywords = layer_to_clip.keywords.copy()
    writer.keywords['title'] = output_layer_name
    check_layer(writer)
    return writer
Exemple #9
0
    def processAlgorithm(self, parameters, context, feedback):
        vlayer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context)
        output = self.getOutputFromName(self.OUTPUT)
        if self.getParameterValue(self.FIELDS):
            fields = vlayer.fields()
        else:
            fields = QgsFields()
        if self.getParameterValue(self.GEOMETRY):
            fieldsCount = fields.count()
            fields.append(QgsField('area', QVariant.Double, 'double', 16, 2))
            fields.append(QgsField('perimeter', QVariant.Double,
                                   'double', 16, 2))
        allLinesList = []
        features = QgsProcessingUtils.getFeatures(vlayer, context, QgsFeatureRequest().setSubsetOfAttributes([]))
        feedback.pushInfo(self.tr('Processing lines...'))
        total = 40.0 / QgsProcessingUtils.featureCount(vlayer, context)
        for current, inFeat in enumerate(features):
            if inFeat.geometry():
                allLinesList.append(inFeat.geometry())
            feedback.setProgress(int(current * total))

        feedback.setProgress(40)

        feedback.pushInfo(self.tr('Noding lines...'))
        allLines = QgsGeometry.unaryUnion(allLinesList)

        feedback.setProgress(45)
        feedback.pushInfo(self.tr('Polygonizing...'))
        polygons = QgsGeometry.polygonize([allLines])
        if polygons.isEmpty():
            raise GeoAlgorithmExecutionException(self.tr('No polygons were created!'))
        feedback.setProgress(50)

        feedback.pushInfo('Saving polygons...')
        writer = output.getVectorWriter(fields, QgsWkbTypes.Polygon, vlayer.crs(), context)
        total = 50.0 / polygons.geometry().numGeometries()
        for i in range(polygons.geometry().numGeometries()):
            outFeat = QgsFeature()
            geom = QgsGeometry(polygons.geometry().geometryN(i).clone())
            outFeat.setGeometry(geom)
            if self.getParameterValue(self.GEOMETRY):
                outFeat.setAttributes([None] * fieldsCount + [geom.geometry().area(),
                                                              geom.geometry().perimeter()])
            writer.addFeature(outFeat, QgsFeatureSink.FastInsert)
            feedback.setProgress(50 + int(current * total))
        del writer
Exemple #10
0
    def processAlgorithm(self, progress):
        vlayerA = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT))
        vlayerB = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT2))
        vproviderA = vlayerA.dataProvider()

        fields = vector.combineVectorFields(vlayerA, vlayerB)
        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fields, vproviderA.geometryType(), vproviderA.crs()
        )
        inFeatA = QgsFeature()
        inFeatB = QgsFeature()
        outFeat = QgsFeature()
        index = vector.spatialindex(vlayerB)
        nElement = 0
        selectionA = vector.features(vlayerA)
        nFeat = len(selectionA)
        for inFeatA in selectionA:
            nElement += 1
            progress.setPercentage(nElement / float(nFeat) * 100)
            geom = QgsGeometry(inFeatA.geometry())
            atMapA = inFeatA.attributes()
            intersects = index.intersects(geom.boundingBox())
            for i in intersects:
                request = QgsFeatureRequest().setFilterFid(i)
                inFeatB = vlayerB.getFeatures(request).next()
                tmpGeom = QgsGeometry(inFeatB.geometry())
                try:
                    if geom.intersects(tmpGeom):
                        atMapB = inFeatB.attributes()
                        int_geom = QgsGeometry(geom.intersection(tmpGeom))
                        if (
                            int_geom.wkbType() == QGis.WKBUnknown
                            or QgsWKBTypes.flatType(int_geom.geometry().wkbType()) == QgsWKBTypes.GeometryCollection
                        ):
                            int_com = geom.combine(tmpGeom)
                            int_sym = geom.symDifference(tmpGeom)
                            int_geom = QgsGeometry(int_com.difference(int_sym))
                        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
                except:
                    break

        del writer
Exemple #11
0
    def processAlgorithm(self, progress):
        vlayerA = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT))
        vlayerB = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT2))
        vproviderA = vlayerA.dataProvider()

        geomType = vproviderA.geometryType()
        if geomType in GEOM_25D:
            raise GeoAlgorithmExecutionException(
                self.tr('Input layer has unsupported geometry type {}').format(geomType))

        fields = vector.combineVectorFields(vlayerA, vlayerB)
        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields,
                                                                     geomType, vproviderA.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 = QgsGeometry(inFeatA.geometry())
            atMapA = inFeatA.attributes()
            intersects = index.intersects(geom.boundingBox())
            for i in intersects:
                request = QgsFeatureRequest().setFilterFid(i)
                inFeatB = vlayerB.getFeatures(request).next()
                tmpGeom = QgsGeometry(inFeatB.geometry())
                if geom.intersects(tmpGeom):
                    atMapB = inFeatB.attributes()
                    int_geom = QgsGeometry(geom.intersection(tmpGeom))
                    if int_geom.wkbType() == QGis.WKBUnknown or QgsWKBTypes.flatType(int_geom.geometry().wkbType()) == QgsWKBTypes.GeometryCollection:
                        int_com = geom.combine(tmpGeom)
                        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.'))
                        break
                    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
Exemple #12
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)

        extent = self.parameterAsExtent(parameters, self.TARGET_AREA, context)
        target_crs = self.parameterAsCrs(parameters, self.TARGET_AREA_CRS, context)

        target_geom = QgsGeometry.fromRect(extent)

        fields = QgsFields()
        fields.append(QgsField('auth_id', QVariant.String, '', 20))

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               fields, QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem())

        # make intersection tests nice and fast
        engine = QgsGeometry.createGeometryEngine(target_geom.geometry())
        engine.prepareGeometry()

        layer_bounds = QgsGeometry.fromRect(source.sourceExtent())

        crses_to_check = QgsCoordinateReferenceSystem.validSrsIds()
        total = 100.0 / len(crses_to_check)

        found_results = 0

        for current, srs_id in enumerate(crses_to_check):
            if feedback.isCanceled():
                break

            candidate_crs = QgsCoordinateReferenceSystem.fromSrsId(srs_id)
            if not candidate_crs.isValid():
                continue

            transform_candidate = QgsCoordinateTransform(candidate_crs, target_crs)
            transformed_bounds = QgsGeometry(layer_bounds)
            try:
                if not transformed_bounds.transform(transform_candidate) == 0:
                    continue
            except:
                continue

            if engine.intersects(transformed_bounds.geometry()):
                feedback.pushInfo(self.tr('Found candidate CRS: {}').format(candidate_crs.authid()))
                f = QgsFeature(fields)
                f.setAttributes([candidate_crs.authid()])
                sink.addFeature(f, QgsFeatureSink.FastInsert)
                found_results += 1

            feedback.setProgress(int(current * total))

        if found_results == 0:
            feedback.reportError(self.tr('No matching projections found'))

        return {self.OUTPUT: dest_id}
Exemple #13
0
    def processAlgorithm(self, feedback):
        polyLayer = dataobjects.getLayerFromString(self.getParameterValue(self.POLYGONS))
        pointLayer = dataobjects.getLayerFromString(self.getParameterValue(self.POINTS))
        fieldName = self.getParameterValue(self.FIELD)

        fields = polyLayer.fields()
        fields.append(QgsField(fieldName, QVariant.Int))

        (idxCount, fieldList) = vector.findOrCreateField(polyLayer,
                                                         polyLayer.fields(), fieldName)

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fields.toList(), polyLayer.wkbType(), polyLayer.crs())

        spatialIndex = vector.spatialindex(pointLayer)

        ftPoly = QgsFeature()
        ftPoint = QgsFeature()
        outFeat = QgsFeature()
        geom = QgsGeometry()

        features = vector.features(polyLayer)
        total = 100.0 / len(features)
        for current, ftPoly in enumerate(features):
            geom = ftPoly.geometry()
            engine = QgsGeometry.createGeometryEngine(geom.geometry())
            engine.prepareGeometry()

            attrs = ftPoly.attributes()

            count = 0
            points = spatialIndex.intersects(geom.boundingBox())
            if len(points) > 0:
                request = QgsFeatureRequest().setFilterFids(points).setSubsetOfAttributes([])
                fit = pointLayer.getFeatures(request)
                ftPoint = QgsFeature()
                while fit.nextFeature(ftPoint):
                    tmpGeom = ftPoint.geometry()
                    if engine.contains(tmpGeom.geometry()):
                        count += 1

            outFeat.setGeometry(geom)
            if idxCount == len(attrs):
                attrs.append(count)
            else:
                attrs[idxCount] = count
            outFeat.setAttributes(attrs)
            writer.addFeature(outFeat)

            feedback.setProgress(int(current * total))

        del writer
Exemple #14
0
    def processAlgorithm(self, parameters, context, feedback):
        layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)

        extent = self.getParameterValue(self.TARGET_AREA).split(',')
        if not extent:
            extent = QgsProcessingUtils.combineLayerExtents([layer])
        target_crs = QgsCoordinateReferenceSystem(self.getParameterValue(self.TARGET_AREA_CRS))

        target_geom = QgsGeometry.fromRect(QgsRectangle(float(extent[0]), float(extent[2]),
                                                        float(extent[1]), float(extent[3])))

        output_file = self.getOutputValue(self.OUTPUT_HTML_FILE)

        # make intersection tests nice and fast
        engine = QgsGeometry.createGeometryEngine(target_geom.geometry())
        engine.prepareGeometry()

        layer_bounds = QgsGeometry.fromRect(layer.extent())

        results = []

        for srs_id in QgsCoordinateReferenceSystem.validSrsIds():
            candidate_crs = QgsCoordinateReferenceSystem.fromSrsId(srs_id)
            if not candidate_crs.isValid():
                continue

            transform_candidate = QgsCoordinateTransform(candidate_crs, target_crs)
            transformed_bounds = QgsGeometry(layer_bounds)
            try:
                if not transformed_bounds.transform(transform_candidate) == 0:
                    continue
            except:
                continue

            if engine.intersects(transformed_bounds.geometry()):
                results.append(candidate_crs.authid())

        self.createHTML(output_file, results)
Exemple #15
0
    def processAlgorithm(self, progress):
        vlayerA = dataobjects.getObjectFromUri(
            self.getParameterValue(Union.INPUT))
        vlayerB = dataobjects.getObjectFromUri(
            self.getParameterValue(Union.INPUT2))
        GEOS_EXCEPT = True
        FEATURE_EXCEPT = True
        vproviderA = vlayerA.dataProvider()

        fields = vector.combineVectorFields(vlayerA, vlayerB)
        names = [field.name() for field in fields]
        ProcessingLog.addToLog(ProcessingLog.LOG_INFO, unicode(names))
        writer = self.getOutputFromName(Union.OUTPUT).getVectorWriter(
            fields, vproviderA.geometryType(), vproviderA.crs())
        inFeatA = QgsFeature()
        inFeatB = QgsFeature()
        outFeat = QgsFeature()
        indexA = vector.spatialindex(vlayerB)
        indexB = vector.spatialindex(vlayerA)

        count = 0
        nElement = 0
        featuresA = vector.features(vlayerA)
        nFeat = len(featuresA)
        for inFeatA in featuresA:
            progress.setPercentage(nElement / float(nFeat) * 50)
            nElement += 1
            lstIntersectingB = []
            geom = QgsGeometry(inFeatA.geometry())
            atMapA = inFeatA.attributes()
            intersects = indexA.intersects(geom.boundingBox())
            if len(intersects) < 1:
                try:
                    outFeat.setGeometry(geom)
                    outFeat.setAttributes(atMapA)
                    writer.addFeature(outFeat)
                except:
                    # This really shouldn't happen, as we haven't
                    # edited the input geom at all
                    raise GeoAlgorithmExecutionException(
                        self.tr('Feature exception while computing union'))
            else:
                for id in intersects:
                    count += 1
                    request = QgsFeatureRequest().setFilterFid(id)
                    inFeatB = vlayerB.getFeatures(request).next()
                    atMapB = inFeatB.attributes()
                    tmpGeom = QgsGeometry(inFeatB.geometry())

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

                        if int_geom is None:
                            # There was a problem creating the intersection
                            raise GeoAlgorithmExecutionException(
                                self.tr('Geometry exception while computing '
                                        'intersection'))
                        else:
                            int_geom = QgsGeometry(int_geom)

                        if int_geom.wkbType(
                        ) == QGis.WKBUnknown 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:
                            outFeat.setGeometry(int_geom)
                            attrs = []
                            attrs.extend(atMapA)
                            attrs.extend(atMapB)
                            outFeat.setAttributes(attrs)
                            writer.addFeature(outFeat)
                        except Exception as err:
                            raise GeoAlgorithmExecutionException(
                                self.tr(
                                    'Feature exception while computing union'))

                try:
                    # the remaining bit of inFeatA'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() == 0 or QgsWKBTypes.flatType(
                            int_geom.geometry().wkbType(
                            )) == QgsWKBTypes.GeometryCollection:
                        temp_list = diff_geom.asGeometryCollection()
                        for i in temp_list:
                            if i.type() == geom.type():
                                diff_geom = QgsGeometry(i)
                    outFeat.setGeometry(diff_geom)
                    outFeat.setAttributes(atMapA)
                    writer.addFeature(outFeat)
                except Exception as err:
                    raise GeoAlgorithmExecutionException(
                        self.tr('Feature exception while computing union'))

        length = len(vproviderA.fields())

        featuresA = vector.features(vlayerB)
        nFeat = len(featuresA)
        for inFeatA in featuresA:
            progress.setPercentage(nElement / float(nFeat) * 100)
            add = False
            geom = QgsGeometry(inFeatA.geometry())
            diff_geom = QgsGeometry(geom)
            atMap = [None] * length
            atMap.extend(inFeatA.attributes())
            intersects = indexB.intersects(geom.boundingBox())

            if len(intersects) < 1:
                try:
                    outFeat.setGeometry(geom)
                    outFeat.setAttributes(atMap)
                    writer.addFeature(outFeat)
                except Exception as err:
                    raise GeoAlgorithmExecutionException(
                        self.tr('Feature exception while computing union'))
            else:
                for id in intersects:
                    request = QgsFeatureRequest().setFilterFid(id)
                    inFeatB = vlayerA.getFeatures(request).next()
                    atMapB = inFeatB.attributes()
                    tmpGeom = QgsGeometry(inFeatB.geometry())
                    try:
                        if diff_geom.intersects(tmpGeom):
                            add = True
                            diff_geom = QgsGeometry(
                                diff_geom.difference(tmpGeom))
                        else:
                            # Ihis only happends if the bounding box
                            # intersects, but the geometry doesn't
                            outFeat.setGeometry(diff_geom)
                            outFeat.setAttributes(atMap)
                            writer.addFeature(outFeat)
                    except Exception as err:
                        raise GeoAlgorithmExecutionException(
                            self.
                            tr('Geometry exception while computing intersection'
                               ))

            if add:
                try:
                    outFeat.setGeometry(diff_geom)
                    outFeat.setAttributes(atMap)
                    writer.addFeature(outFeat)
                except Exception as err:
                    raise err
                    FEATURE_EXCEPT = False
            nElement += 1

        del writer
        if not GEOS_EXCEPT:
            ProcessingLog.addToLog(
                ProcessingLog.LOG_WARNING,
                self.tr('Geometry exception while computing intersection'))
        if not FEATURE_EXCEPT:
            ProcessingLog.addToLog(
                ProcessingLog.LOG_WARNING,
                self.tr('Feature exception while computing intersection'))
Exemple #16
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())), 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())
            request.setSubsetOfAttributes(field_indices_b)

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

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

                tmpGeom = featB.geometry()
                if engine.intersects(tmpGeom.geometry()):
                    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.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 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}
Exemple #17
0
    def processAlgorithm(self, progress):
        lineLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.LINES))
        polyLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.POLYGONS))
        lengthFieldName = self.getParameterValue(self.LEN_FIELD)
        countFieldName = self.getParameterValue(self.COUNT_FIELD)

        (idxLength, fieldList) = vector.findOrCreateField(polyLayer,
                                                          polyLayer.fields(), lengthFieldName)
        (idxCount, fieldList) = vector.findOrCreateField(polyLayer, fieldList,
                                                         countFieldName)

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fieldList.toList(), polyLayer.wkbType(), polyLayer.crs())

        spatialIndex = vector.spatialindex(lineLayer)

        ftLine = QgsFeature()
        ftPoly = QgsFeature()
        outFeat = QgsFeature()
        inGeom = QgsGeometry()
        outGeom = QgsGeometry()
        distArea = QgsDistanceArea()

        features = vector.features(polyLayer)
        total = 100.0 / len(features)
        hasIntersections = False
        for current, ftPoly in enumerate(features):
            inGeom = ftPoly.geometry()
            attrs = ftPoly.attributes()
            count = 0
            length = 0
            hasIntersections = False
            lines = spatialIndex.intersects(inGeom.boundingBox())
            engine = None
            if len(lines) > 0:
                hasIntersections = True
                # use prepared geometries for faster intersection tests
                engine = QgsGeometry.createGeometryEngine(inGeom.geometry())
                engine.prepareGeometry()

            if hasIntersections:
                request = QgsFeatureRequest().setFilterFids(lines).setSubsetOfAttributes([])
                for ftLine in lineLayer.getFeatures(request):
                    tmpGeom = ftLine.geometry()
                    if engine.intersects(tmpGeom.geometry()):
                        outGeom = inGeom.intersection(tmpGeom)
                        length += distArea.measureLength(outGeom)
                        count += 1

            outFeat.setGeometry(inGeom)
            if idxLength == len(attrs):
                attrs.append(length)
            else:
                attrs[idxLength] = length
            if idxCount == len(attrs):
                attrs.append(count)
            else:
                attrs[idxCount] = count
            outFeat.setAttributes(attrs)
            writer.addFeature(outFeat)

            progress.setPercentage(int(current * total))

        del writer
Exemple #18
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())]

        fieldListB = vector.testForUniqueness(fieldListA, fieldListB)
        for b in fieldListB:
            fieldListA.append(b)

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

        outFeat = QgsFeature()
        indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())), 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())
            request.setSubsetOfAttributes(field_indices_b)

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

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

                tmpGeom = featB.geometry()
                if engine.intersects(tmpGeom.geometry()):
                    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.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 QgsProcessingException(
                            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)
                            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}
Exemple #19
0
def union(union_a, union_b, callback=None):
    """Union of two vector layers.

    Issue https://github.com/inasafe/inasafe/issues/3186

    Note : This algorithm is copied from :
    https://github.com/qgis/QGIS/blob/master/python/plugins/processing/algs/
    qgis/Union.py

    :param union_a: The vector layer for the union.
    :type union_a: QgsVectorLayer

    :param union_b: The vector layer for the union.
    :type union_b: QgsVectorLayer

    :param callback: A function to all to indicate progress. The function
        should accept params 'current' (int), 'maximum' (int) and 'step' (str).
        Defaults to None.
    :type callback: function

    :return: The clip vector layer.
    :rtype: QgsVectorLayer

    .. versionadded:: 4.0
    """
    output_layer_name = union_steps['output_layer_name']
    processing_step = union_steps['step_name']
    output_layer_name = output_layer_name % (
        union_a.keywords['layer_purpose'],
        union_b.keywords['layer_purpose']
    )

    fields = union_a.fields()
    fields.extend(union_b.fields())

    writer = create_memory_layer(
        output_layer_name,
        union_a.geometryType(),
        union_a.crs(),
        fields
    )
    keywords_union_1 = union_a.keywords
    keywords_union_2 = union_b.keywords
    inasafe_fields_union_1 = keywords_union_1['inasafe_fields']
    inasafe_fields_union_2 = keywords_union_2['inasafe_fields']
    inasafe_fields = inasafe_fields_union_1
    inasafe_fields.update(inasafe_fields_union_2)

    # use to avoid modifying original source
    writer.keywords = dict(union_a.keywords)
    writer.keywords['inasafe_fields'] = inasafe_fields
    writer.keywords['title'] = output_layer_name
    writer.keywords['layer_purpose'] = 'aggregate_hazard'
    writer.keywords['hazard_keywords'] = keywords_union_1.copy()
    writer.keywords['aggregation_keywords'] = keywords_union_2.copy()
    skip_field = inasafe_fields_union_2[aggregation_id_field['key']]
    not_null_field_index = writer.fieldNameIndex(skip_field)

    writer.startEditing()

    # Begin copy/paste from Processing plugin.
    # Please follow their code as their code is optimized.
    # The code below is not following our coding standards because we want to
    # be able to track any diffs from QGIS easily.

    index_a = create_spatial_index(union_b)
    index_b = create_spatial_index(union_a)

    count = 0
    n_element = 0
    # Todo fix callback
    # nFeat = len(union_a.getFeatures())
    for in_feat_a in union_a.getFeatures():
        # progress.setPercentage(nElement / float(nFeat) * 50)
        n_element += 1
        list_intersecting_b = []
        geom = geometry_checker(in_feat_a.geometry())
        at_map_a = in_feat_a.attributes()
        intersects = index_a.intersects(geom.boundingBox())
        if len(intersects) < 1:
            try:
                _write_feature(at_map_a, geom, writer, not_null_field_index)
            except:
                # This really shouldn't happen, as we haven't
                # edited the input geom at all
                LOGGER.debug(
                    tr('Feature geometry error: One or more output features '
                       'ignored due to invalid geometry.'))
        else:
            request = QgsFeatureRequest().setFilterFids(intersects)

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

            for in_feat_b in union_b.getFeatures(request):
                count += 1

                at_map_b = in_feat_b.attributes()
                tmp_geom = geometry_checker(in_feat_b.geometry())

                if engine.intersects(tmp_geom.geometry()):
                    int_geom = geometry_checker(geom.intersection(tmp_geom))
                    list_intersecting_b.append(QgsGeometry(tmp_geom))

                    if not int_geom:
                        # There was a problem creating the intersection
                        # LOGGER.debug(
                        #     tr('GEOS geoprocessing error: One or more input '
                        #        'features have invalid geometry.'))
                        pass
                        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 geometry types
                        temp_list = int_geom.asGeometryCollection()
                        for i in temp_list:
                            if i.type() == geom.type():
                                int_geom = QgsGeometry(geometry_checker(i))
                                try:
                                    _write_feature(
                                        at_map_a + at_map_b,
                                        int_geom,
                                        writer,
                                        not_null_field_index,
                                    )
                                except:
                                    LOGGER.debug(
                                        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 int_geom.wkbType() in wkb_type_groups[
                            wkb_type_groups[int_geom.wkbType()]]:
                            try:
                                _write_feature(
                                    at_map_a + at_map_b,
                                    int_geom,
                                    writer,
                                    not_null_field_index)
                            except:
                                LOGGER.debug(
                                    tr('Feature geometry error: One or more '
                                       'output features ignored due to '
                                       'invalid geometry.'))

            # the remaining bit of inFeatA's geometry
            # if there is nothing left, this will just silently fail and we
            # are good
            diff_geom = QgsGeometry(geom)
            if len(list_intersecting_b) != 0:
                int_b = QgsGeometry.unaryUnion(list_intersecting_b)
                diff_geom = geometry_checker(diff_geom.difference(int_b))
                if diff_geom is None or \
                    diff_geom.isGeosEmpty() or not diff_geom.isGeosValid():
                    # LOGGER.debug(
                    #     tr('GEOS geoprocessing error: One or more input '
                    #        'features have invalid geometry.'))
                    pass

            if diff_geom is not None and (
                            diff_geom.wkbType() == 0 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(geometry_checker(i))
            try:
                _write_feature(
                    at_map_a,
                    diff_geom,
                    writer,
                    not_null_field_index)
            except:
                LOGGER.debug(
                    tr('Feature geometry error: One or more output features '
                       'ignored due to invalid geometry.'))

    length = len(union_a.fields())
    at_map_a = [None] * length

    # nFeat = len(union_b.getFeatures())
    for in_feat_a in union_b.getFeatures():
        # progress.setPercentage(nElement / float(nFeat) * 100)
        add = False
        geom = geometry_checker(in_feat_a.geometry())
        atMap = [None] * length
        atMap.extend(in_feat_a.attributes())
        intersects = index_b.intersects(geom.boundingBox())
        lstIntersectingA = []

        for id in intersects:
            request = QgsFeatureRequest().setFilterFid(id)
            inFeatB = union_a.getFeatures(request).next()
            atMapB = inFeatB.attributes()
            tmpGeom = QgsGeometry(geometry_checker(inFeatB.geometry()))

            if geom.intersects(tmpGeom):
                lstIntersectingA.append(tmpGeom)

        if len(lstIntersectingA) == 0:
            res_geom = geom
        else:
            intA = QgsGeometry.unaryUnion(lstIntersectingA)
            res_geom = geom.difference(intA)
            if res_geom is None:
                # LOGGER.debug(
                #    tr('GEOS geoprocessing error: One or more input features '
                #        'have null geometry.'))
                pass
                continue  # maybe it is better to fail like @gustry
                # does below ....
            if res_geom.isGeosEmpty() or not res_geom.isGeosValid():
                # LOGGER.debug(
                #    tr('GEOS geoprocessing error: One or more input features '
                #        'have invalid geometry.'))
                pass

        try:
            _write_feature(atMap, res_geom, writer, not_null_field_index)
        except:
            # LOGGER.debug(
            #     tr('Feature geometry error: One or more output features '
            #        'ignored due to invalid geometry.'))
            pass

        n_element += 1

    # End of copy/paste from processing

    writer.commitChanges()

    fill_hazard_class(writer)

    check_layer(writer)
    return writer
Exemple #20
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
Exemple #21
0
    def processAlgorithm(self, progress):
        layerA = dataobjects.getObjectFromUri(
            self.getParameterValue(Clip.INPUT))
        layerB = dataobjects.getObjectFromUri(
            self.getParameterValue(Clip.OVERLAY))

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            layerA.pendingFields(),
            layerA.dataProvider().geometryType(),
            layerA.dataProvider().crs())

        inFeatA = QgsFeature()
        inFeatB = QgsFeature()
        outFeat = QgsFeature()

        index = vector.spatialindex(layerB)

        selectionA = vector.features(layerA)

        current = 0
        total = 100.0 / float(len(selectionA))

        for inFeatA in selectionA:
            geom = QgsGeometry(inFeatA.geometry())
            attrs = inFeatA.attributes()
            intersects = index.intersects(geom.boundingBox())
            first = True
            found = False
            if len(intersects) > 0:
                for i in intersects:
                    layerB.getFeatures(
                        QgsFeatureRequest().setFilterFid(i)).nextFeature(
                            inFeatB)
                    tmpGeom = QgsGeometry(inFeatB.geometry())
                    if tmpGeom.intersects(geom):
                        found = True
                        if first:
                            outFeat.setGeometry(QgsGeometry(tmpGeom))
                            first = False
                        else:
                            try:
                                cur_geom = QgsGeometry(outFeat.geometry())
                                new_geom = QgsGeometry(
                                    cur_geom.combine(tmpGeom))
                                outFeat.setGeometry(QgsGeometry(new_geom))
                            except:
                                ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                                       self.tr('GEOS geoprocessing error: One or '
                                                               'more input features have invalid '
                                                               'geometry.'))
                                break
                if found:
                    try:
                        cur_geom = QgsGeometry(outFeat.geometry())
                        new_geom = QgsGeometry(geom.intersection(cur_geom))
                        if new_geom.wkbType() == QGis.WKBUnknown or QgsWKBTypes.flatType(new_geom.geometry().wkbType()) == QgsWKBTypes.GeometryCollection:
                            int_com = QgsGeometry(geom.combine(cur_geom))
                            int_sym = QgsGeometry(geom.symDifference(cur_geom))
                            new_geom = QgsGeometry(int_com.difference(int_sym))
                        try:
                            outFeat.setGeometry(new_geom)
                            outFeat.setAttributes(attrs)
                            writer.addFeature(outFeat)
                        except:
                            ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                                   self.tr('Feature geometry error: One or more '
                                                           'output features ignored due to '
                                                           'invalid geometry.'))
                            continue
                    except:
                        ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                               self.tr('GEOS geoprocessing error: One or more '
                                                       'input features have invalid geometry.'))
                        continue

            current += 1
            progress.setPercentage(int(current * total))

        del writer
Exemple #22
0
def intersection(source, mask, callback=None):
    """Intersect two layers.

    Issue https://github.com/inasafe/inasafe/issues/3186

    Note : This algorithm is copied from :
    https://github.com/qgis/QGIS/blob/master/python/plugins/processing/algs/
    qgis/Intersection.py

    :param source: The vector layer to clip.
    :type source: QgsVectorLayer

    :param mask: The vector layer to use for clipping.
    :type mask: QgsVectorLayer

    :param callback: A function to all to indicate progress. The function
        should accept params 'current' (int), 'maximum' (int) and 'step' (str).
        Defaults to None.
    :type callback: function

    :return: The clip vector layer.
    :rtype: QgsVectorLayer

    .. versionadded:: 4.0
    """
    output_layer_name = intersection_steps['output_layer_name']
    output_layer_name = output_layer_name % (source.keywords['layer_purpose'])
    processing_step = intersection_steps['step_name']

    fields = source.fields()
    fields.extend(mask.fields())

    writer = create_memory_layer(output_layer_name, source.geometryType(),
                                 source.crs(), fields)

    writer.startEditing()

    # Begin copy/paste from Processing plugin.
    # Please follow their code as their code is optimized.
    # The code below is not following our coding standards because we want to
    # be able to track any diffs from QGIS easily.

    out_feature = QgsFeature()
    index = create_spatial_index(mask)

    # Todo callback
    # total = 100.0 / len(selectionA)

    for current, in_feature in enumerate(source.getFeatures()):
        # progress.setPercentage(int(current * total))
        geom = in_feature.geometry()
        attributes = in_feature.attributes()
        intersects = index.intersects(geom.boundingBox())
        for i in intersects:
            request = QgsFeatureRequest().setFilterFid(i)
            feature_mask = next(mask.getFeatures(request))
            tmp_geom = feature_mask.geometry()
            if geom.intersects(tmp_geom):
                mask_attributes = feature_mask.attributes()
                int_geom = QgsGeometry(geom.intersection(tmp_geom))
                if int_geom.wkbType() == QgsWKBTypes.Unknown\
                        or QgsWKBTypes.flatType(
                        int_geom.geometry().wkbType()) ==\
                                QgsWKBTypes.GeometryCollection:
                    int_com = geom.combine(tmp_geom)
                    int_geom = QgsGeometry()
                    if int_com:
                        int_sym = geom.symDifference(tmp_geom)
                        int_geom = QgsGeometry(int_com.difference(int_sym))
                if int_geom.isGeosEmpty() or not int_geom.isGeosValid():
                    # LOGGER.debug(
                    #     tr('GEOS geoprocessing error: One or more input '
                    #        'features have invalid geometry.'))
                    pass
                try:
                    geom_types = wkb_type_groups[wkb_type_groups[
                        int_geom.wkbType()]]
                    if int_geom.wkbType() in geom_types:
                        if int_geom.type() == source.geometryType():
                            # We got some features which have not the same
                            # kind of geometry. We want to skip them.
                            out_feature.setGeometry(int_geom)
                            attrs = []
                            attrs.extend(attributes)
                            attrs.extend(mask_attributes)
                            out_feature.setAttributes(attrs)
                            writer.addFeature(out_feature)
                except:
                    LOGGER.debug(
                        tr('Feature geometry error: One or more output '
                           'features ignored due to invalid geometry.'))
                    continue

    # End copy/paste from Processing plugin.
    writer.commitChanges()

    writer.keywords = dict(source.keywords)
    writer.keywords['title'] = output_layer_name
    writer.keywords['layer_purpose'] = layer_purpose_exposure_summary['key']
    writer.keywords['inasafe_fields'] = dict(source.keywords['inasafe_fields'])
    writer.keywords['inasafe_fields'].update(mask.keywords['inasafe_fields'])
    writer.keywords['hazard_keywords'] = dict(mask.keywords['hazard_keywords'])
    writer.keywords['exposure_keywords'] = dict(source.keywords)
    writer.keywords['aggregation_keywords'] = dict(
        mask.keywords['aggregation_keywords'])

    check_layer(writer)
    return writer
Exemple #23
0
    def processAlgorithm(self, progress):
        extent = str(self.getParameterValue(self.EXTENT)).split(',')

        spacing = float(self.getParameterValue(self.SPACING))
        inset = float(self.getParameterValue(self.INSET))
        randomize = self.getParameterValue(self.RANDOMIZE)
        isSpacing = self.getParameterValue(self.IS_SPACING)

        extent = QgsRectangle(float(extent[0]), float(extent[2]),
                              float(extent[1]), float(extent[3]))

        fields = QgsFields()
        fields.append(QgsField('id', QVariant.Int, '', 10, 0))
        mapCRS = iface.mapCanvas().mapSettings().destinationCrs()

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fields, QgsWkbTypes.Point, mapCRS)

        if randomize:
            seed()

        area = extent.width() * extent.height()
        if isSpacing:
            pSpacing = spacing
        else:
            pSpacing = sqrt(area / spacing)

        f = QgsFeature()
        f.initAttributes(1)
        f.setFields(fields)

        count = 0
        total = 100.0 / (area / pSpacing)
        y = extent.yMaximum() - inset

        extent_geom = QgsGeometry.fromRect(extent)
        extent_engine = QgsGeometry.createGeometryEngine(
            extent_geom.geometry())
        extent_engine.prepareGeometry()

        while y >= extent.yMinimum():
            x = extent.xMinimum() + inset
            while x <= extent.xMaximum():
                if randomize:
                    geom = QgsGeometry().fromPoint(
                        QgsPoint(
                            uniform(x - (pSpacing / 2.0),
                                    x + (pSpacing / 2.0)),
                            uniform(y - (pSpacing / 2.0),
                                    y + (pSpacing / 2.0))))
                else:
                    geom = QgsGeometry().fromPoint(QgsPoint(x, y))

                if extent_engine.intersects(geom.geometry()):
                    f.setAttribute('id', count)
                    f.setGeometry(geom)
                    writer.addFeature(f)
                    x += pSpacing
                    count += 1
                    progress.setPercentage(int(count * total))
            y = y - pSpacing
        del writer
Exemple #24
0
    def processAlgorithm(self, 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 / QgsProcessingUtils.featureCount(vlayerA, context)
        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)
                    except:
                        raise GeoAlgorithmExecutionException(
                            self.tr('Feature geometry error: One or more '
                                    'output features ignored due to invalid '
                                    'geometry.'))

        del writer
Exemple #25
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        fieldName = self.parameterAsString(parameters, self.FIELD, context)
        useField = bool(fieldName)

        field_index = None
        f = QgsField('value', QVariant.String, '', 255)
        if useField:
            field_index = source.fields().lookupField(fieldName)
            fType = source.fields()[field_index].type()
            if fType in [
                    QVariant.Int, QVariant.UInt, QVariant.LongLong,
                    QVariant.ULongLong
            ]:
                f.setType(fType)
                f.setLength(20)
            elif fType == QVariant.Double:
                f.setType(QVariant.Double)
                f.setLength(20)
                f.setPrecision(6)
            else:
                f.setType(QVariant.String)
                f.setLength(255)

        fields = QgsFields()
        fields.append(QgsField('id', QVariant.Int, '', 20))
        fields.append(f)
        fields.append(QgsField('area', QVariant.Double, '', 20, 6))
        fields.append(QgsField('perim', QVariant.Double, '', 20, 6))

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

        outFeat = QgsFeature()
        outGeom = QgsGeometry()

        fid = 0
        val = None
        if useField:
            unique = source.uniqueValues(field_index)
            current = 0
            total = 100.0 / (source.featureCount() *
                             len(unique)) if source.featureCount() else 1
            for i in unique:
                if feedback.isCanceled():
                    break

                first = True
                hull = []
                features = source.getFeatures(
                    QgsFeatureRequest().setSubsetOfAttributes([field_index]))
                for f in features:
                    if feedback.isCanceled():
                        break

                    idVar = f.attributes()[field_index]
                    if str(idVar).strip() == str(i).strip():
                        if first:
                            val = idVar
                            first = False

                        inGeom = f.geometry()
                        points = vector.extractPoints(inGeom)
                        hull.extend(points)
                    current += 1
                    feedback.setProgress(int(current * total))

                if len(hull) >= 3:
                    tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull))
                    try:
                        outGeom = tmpGeom.convexHull()
                        if outGeom:
                            area = outGeom.geometry().area()
                            perim = outGeom.geometry().perimeter()
                        else:
                            area = NULL
                            perim = NULL
                        outFeat.setGeometry(outGeom)
                        outFeat.setAttributes([fid, val, area, perim])
                        sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
                    except:
                        raise QgsProcessingException(
                            self.tr('Exception while computing convex hull'))
                fid += 1
        else:
            hull = []
            total = 100.0 / source.featureCount() if source.featureCount(
            ) else 1
            features = source.getFeatures(
                QgsFeatureRequest().setSubsetOfAttributes([]))
            for current, f in enumerate(features):
                if feedback.isCanceled():
                    break

                inGeom = f.geometry()
                points = vector.extractPoints(inGeom)
                hull.extend(points)
                feedback.setProgress(int(current * total))

            tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull))
            try:
                outGeom = tmpGeom.convexHull()
                if outGeom:
                    area = outGeom.geometry().area()
                    perim = outGeom.geometry().perimeter()
                else:
                    area = NULL
                    perim = NULL
                outFeat.setGeometry(outGeom)
                outFeat.setAttributes([0, 'all', area, perim])
                sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
            except:
                raise QgsProcessingException(
                    self.tr('Exception while computing convex hull'))

        return {self.OUTPUT: dest_id}
Exemple #26
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())

        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:
                    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:
                                        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 int_geom.wkbType() in wkbTypeGroups[
                                    wkbTypeGroups[int_geom.wkbType()]]:
                                try:
                                    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:
                    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:
                    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
                            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:
                    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}
    def processAlgorithm(self, progress):
        polyLayer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.POLYGONS))
        pointLayer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.POINTS))
        fieldName = self.getParameterValue(self.FIELD)
        fieldIdx = pointLayer.fields().lookupField(
            self.getParameterValue(self.WEIGHT))

        fields = polyLayer.fields()
        fields.append(QgsField(fieldName, QVariant.Int))

        (idxCount,
         fieldList) = vector.findOrCreateField(polyLayer, polyLayer.fields(),
                                               fieldName)

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fields.toList(), polyLayer.wkbType(), polyLayer.crs())

        spatialIndex = vector.spatialindex(pointLayer)

        ftPoint = QgsFeature()
        outFeat = QgsFeature()
        geom = QgsGeometry()

        features = vector.features(polyLayer)
        total = 100.0 / len(features)
        for current, ftPoly in enumerate(features):
            geom = ftPoly.geometry()
            engine = QgsGeometry.createGeometryEngine(geom.geometry())
            engine.prepareGeometry()

            attrs = ftPoly.attributes()

            count = 0
            points = spatialIndex.intersects(geom.boundingBox())
            if len(points) > 0:
                progress.setText(str(len(points)))
                request = QgsFeatureRequest().setFilterFids(
                    points).setSubsetOfAttributes([fieldIdx])
                fit = pointLayer.getFeatures(request)
                ftPoint = QgsFeature()
                while fit.nextFeature(ftPoint):
                    tmpGeom = QgsGeometry(ftPoint.geometry())
                    if engine.contains(tmpGeom.geometry()):
                        weight = str(ftPoint.attributes()[fieldIdx])
                        try:
                            count += float(weight)
                        except:
                            # Ignore fields with non-numeric values
                            pass

            outFeat.setGeometry(geom)
            if idxCount == len(attrs):
                attrs.append(count)
            else:
                attrs[idxCount] = count
            outFeat.setAttributes(attrs)
            writer.addFeature(outFeat)

            progress.setPercentage(int(current * total))

        del writer
Exemple #28
0
    def processAlgorithm(self, progress):
        vlayerA = dataobjects.getObjectFromUri(self.getParameterValue(Union.INPUT))
        vlayerB = dataobjects.getObjectFromUri(self.getParameterValue(Union.INPUT2))
        GEOS_EXCEPT = True
        FEATURE_EXCEPT = True
        vproviderA = vlayerA.dataProvider()

        fields = vector.combineVectorFields(vlayerA, vlayerB)
        names = [field.name() for field in fields]
        ProcessingLog.addToLog(ProcessingLog.LOG_INFO, unicode(names))
        writer = self.getOutputFromName(Union.OUTPUT).getVectorWriter(fields,
                                                                      vproviderA.geometryType(), vproviderA.crs())
        inFeatA = QgsFeature()
        inFeatB = QgsFeature()
        outFeat = QgsFeature()
        indexA = vector.spatialindex(vlayerB)
        indexB = vector.spatialindex(vlayerA)

        count = 0
        nElement = 0
        featuresA = vector.features(vlayerA)
        nFeat = len(featuresA)
        for inFeatA in featuresA:
            progress.setPercentage(nElement / float(nFeat) * 50)
            nElement += 1
            lstIntersectingB = []
            geom = QgsGeometry(inFeatA.geometry())
            atMapA = inFeatA.attributes()
            intersects = indexA.intersects(geom.boundingBox())
            if len(intersects) < 1:
                try:
                    outFeat.setGeometry(geom)
                    outFeat.setAttributes(atMapA)
                    writer.addFeature(outFeat)
                except:
                    # This really shouldn't happen, as we haven't
                    # edited the input geom at all
                    raise GeoAlgorithmExecutionException(
                        self.tr('Feature exception while computing union'))
            else:
                for id in intersects:
                    count += 1
                    request = QgsFeatureRequest().setFilterFid(id)
                    inFeatB = vlayerB.getFeatures(request).next()
                    atMapB = inFeatB.attributes()
                    tmpGeom = QgsGeometry(inFeatB.geometry())

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

                        if int_geom is None:
                           # There was a problem creating the intersection
                            raise GeoAlgorithmExecutionException(
                                self.tr('Geometry exception while computing '
                                        'intersection'))
                        else:
                            int_geom = QgsGeometry(int_geom)

                        if int_geom.wkbType() == QGis.WKBUnknown 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:
                            outFeat.setGeometry(int_geom)
                            attrs = []
                            attrs.extend(atMapA)
                            attrs.extend(atMapB)
                            outFeat.setAttributes(attrs)
                            writer.addFeature(outFeat)
                        except Exception as err:
                            raise GeoAlgorithmExecutionException(
                                self.tr('Feature exception while computing union'))

                try:
                    # the remaining bit of inFeatA'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() == 0 or QgsWKBTypes.flatType(int_geom.geometry().wkbType()) == QgsWKBTypes.GeometryCollection:
                        temp_list = diff_geom.asGeometryCollection()
                        for i in temp_list:
                            if i.type() == geom.type():
                                diff_geom = QgsGeometry(i)
                    outFeat.setGeometry(diff_geom)
                    outFeat.setAttributes(atMapA)
                    writer.addFeature(outFeat)
                except Exception as err:
                    raise GeoAlgorithmExecutionException(
                        self.tr('Feature exception while computing union'))

        length = len(vproviderA.fields())

        featuresA = vector.features(vlayerB)
        nFeat = len(featuresA)
        for inFeatA in featuresA:
            progress.setPercentage(nElement / float(nFeat) * 100)
            add = False
            geom = QgsGeometry(inFeatA.geometry())
            diff_geom = QgsGeometry(geom)
            atMap = [None] * length
            atMap.extend(inFeatA.attributes())
            intersects = indexB.intersects(geom.boundingBox())

            if len(intersects) < 1:
                try:
                    outFeat.setGeometry(geom)
                    outFeat.setAttributes(atMap)
                    writer.addFeature(outFeat)
                except Exception as err:
                    raise GeoAlgorithmExecutionException(
                        self.tr('Feature exception while computing union'))
            else:
                for id in intersects:
                    request = QgsFeatureRequest().setFilterFid(id)
                    inFeatB = vlayerA.getFeatures(request).next()
                    atMapB = inFeatB.attributes()
                    tmpGeom = QgsGeometry(inFeatB.geometry())
                    try:
                        if diff_geom.intersects(tmpGeom):
                            add = True
                            diff_geom = QgsGeometry(
                                diff_geom.difference(tmpGeom))
                        else:
                            # Ihis only happends if the bounding box
                            # intersects, but the geometry doesn't
                            outFeat.setGeometry(diff_geom)
                            outFeat.setAttributes(atMap)
                            writer.addFeature(outFeat)
                    except Exception as err:
                        raise GeoAlgorithmExecutionException(
                            self.tr('Geometry exception while computing intersection'))

            if add:
                try:
                    outFeat.setGeometry(diff_geom)
                    outFeat.setAttributes(atMap)
                    writer.addFeature(outFeat)
                except Exception as err:
                    raise err
                    FEATURE_EXCEPT = False
            nElement += 1

        del writer
        if not GEOS_EXCEPT:
            ProcessingLog.addToLog(ProcessingLog.LOG_WARNING,
                                   self.tr('Geometry exception while computing intersection'))
        if not FEATURE_EXCEPT:
            ProcessingLog.addToLog(ProcessingLog.LOG_WARNING,
                                   self.tr('Feature exception while computing intersection'))
Exemple #29
0
    def processAlgorithm(self, progress):
        layerA = dataobjects.getObjectFromUri(
            self.getParameterValue(Clip.INPUT))
        layerB = dataobjects.getObjectFromUri(
            self.getParameterValue(Clip.OVERLAY))

        geomType = layerA.dataProvider().geometryType()
        if geomType in GEOM_25D:
            raise GeoAlgorithmExecutionException(
                self.tr('Input layer has unsupported geometry type {}').format(geomType))

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            layerA.pendingFields(),
            layerA.dataProvider().geometryType(),
            layerA.dataProvider().crs())

        inFeatA = QgsFeature()
        inFeatB = QgsFeature()
        outFeat = QgsFeature()

        index = vector.spatialindex(layerB)

        selectionA = vector.features(layerA)

        total = 100.0 / len(selectionA)

        for current, inFeatA in enumerate(selectionA):
            geom = QgsGeometry(inFeatA.geometry())
            attrs = inFeatA.attributes()
            intersects = index.intersects(geom.boundingBox())
            first = True
            found = False
            if len(intersects) > 0:
                for i in intersects:
                    layerB.getFeatures(
                        QgsFeatureRequest().setFilterFid(i)).nextFeature(
                            inFeatB)
                    tmpGeom = QgsGeometry(inFeatB.geometry())
                    if tmpGeom.intersects(geom):
                        found = True
                        if first:
                            outFeat.setGeometry(QgsGeometry(tmpGeom))
                            first = False
                        else:
                            cur_geom = QgsGeometry(outFeat.geometry())
                            new_geom = QgsGeometry(cur_geom.combine(tmpGeom))
                            if new_geom.isGeosEmpty() or not new_geom.isGeosValid():
                                ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                                       self.tr('GEOS geoprocessing error: One or '
                                                               'more input features have invalid '
                                                               'geometry.'))
                                break

                            outFeat.setGeometry(QgsGeometry(new_geom))
                if found:
                    cur_geom = QgsGeometry(outFeat.geometry())
                    new_geom = QgsGeometry(geom.intersection(cur_geom))
                    if new_geom.wkbType() == QGis.WKBUnknown or QgsWKBTypes.flatType(new_geom.geometry().wkbType()) == QgsWKBTypes.GeometryCollection:
                        int_com = QgsGeometry(geom.combine(cur_geom))
                        int_sym = QgsGeometry(geom.symDifference(cur_geom))
                        new_geom = QgsGeometry(int_com.difference(int_sym))
                        if new_geom.isGeosEmpty() or not new_geom.isGeosValid():
                            ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                                   self.tr('GEOS geoprocessing error: One or more '
                                                           'input features have invalid geometry.'))
                            continue
                    try:
                        outFeat.setGeometry(new_geom)
                        outFeat.setAttributes(attrs)
                        writer.addFeature(outFeat)
                    except:
                        ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                               self.tr('Feature geometry error: One or more '
                                                       'output features ignored due to '
                                                       'invalid geometry.'))
                        continue

            progress.setPercentage(int(current * total))

        del writer
Exemple #30
0
def intersection(source, mask, callback=None):
    """Intersect two layers.

    Issue https://github.com/inasafe/inasafe/issues/3186

    Note : This algorithm is copied from :
    https://github.com/qgis/QGIS/blob/master/python/plugins/processing/algs/
    qgis/Intersection.py

    :param source: The vector layer to clip.
    :type source: QgsVectorLayer

    :param mask: The vector layer to use for clipping.
    :type mask: QgsVectorLayer

    :param callback: A function to all to indicate progress. The function
        should accept params 'current' (int), 'maximum' (int) and 'step' (str).
        Defaults to None.
    :type callback: function

    :return: The clip vector layer.
    :rtype: QgsVectorLayer

    .. versionadded:: 4.0
    """
    output_layer_name = intersection_steps['output_layer_name']
    output_layer_name = output_layer_name % (
        source.keywords['layer_purpose'])
    processing_step = intersection_steps['step_name']

    fields = source.fields()
    fields.extend(mask.fields())

    writer = create_memory_layer(
        output_layer_name,
        source.geometryType(),
        source.crs(),
        fields
    )

    writer.startEditing()

    # Begin copy/paste from Processing plugin.
    # Please follow their code as their code is optimized.
    # The code below is not following our coding standards because we want to
    # be able to track any diffs from QGIS easily.

    out_feature = QgsFeature()
    index = create_spatial_index(mask)

    # Todo callback
    # total = 100.0 / len(selectionA)

    for current, in_feature in enumerate(source.getFeatures()):
        # progress.setPercentage(int(current * total))
        geom = in_feature.geometry()
        attributes = in_feature.attributes()
        intersects = index.intersects(geom.boundingBox())
        for i in intersects:
            request = QgsFeatureRequest().setFilterFid(i)
            feature_mask = next(mask.getFeatures(request))
            tmp_geom = feature_mask.geometry()
            if geom.intersects(tmp_geom):
                mask_attributes = feature_mask.attributes()
                int_geom = QgsGeometry(geom.intersection(tmp_geom))
                if int_geom.wkbType() == QgsWKBTypes.Unknown\
                        or QgsWKBTypes.flatType(
                        int_geom.geometry().wkbType()) ==\
                                QgsWKBTypes.GeometryCollection:
                    int_com = geom.combine(tmp_geom)
                    int_geom = QgsGeometry()
                    if int_com:
                        int_sym = geom.symDifference(tmp_geom)
                        int_geom = QgsGeometry(int_com.difference(int_sym))
                if int_geom.isGeosEmpty() or not int_geom.isGeosValid():
                    # LOGGER.debug(
                    #     tr('GEOS geoprocessing error: One or more input '
                    #        'features have invalid geometry.'))
                    pass
                try:
                    geom_types = wkb_type_groups[
                        wkb_type_groups[int_geom.wkbType()]]
                    if int_geom.wkbType() in geom_types:
                        if int_geom.type() == source.geometryType():
                            # We got some features which have not the same
                            # kind of geometry. We want to skip them.
                            out_feature.setGeometry(int_geom)
                            attrs = []
                            attrs.extend(attributes)
                            attrs.extend(mask_attributes)
                            out_feature.setAttributes(attrs)
                            writer.addFeature(out_feature)
                except:
                    LOGGER.debug(
                        tr('Feature geometry error: One or more output '
                           'features ignored due to invalid geometry.'))
                    continue

    # End copy/paste from Processing plugin.
    writer.commitChanges()

    writer.keywords = dict(source.keywords)
    writer.keywords['title'] = output_layer_name
    writer.keywords['layer_purpose'] = layer_purpose_exposure_summary['key']
    writer.keywords['inasafe_fields'] = dict(source.keywords['inasafe_fields'])
    writer.keywords['inasafe_fields'].update(mask.keywords['inasafe_fields'])
    writer.keywords['hazard_keywords'] = dict(mask.keywords['hazard_keywords'])
    writer.keywords['exposure_keywords'] = dict(source.keywords)
    writer.keywords['aggregation_keywords'] = dict(
        mask.keywords['aggregation_keywords'])

    check_layer(writer)
    return writer
Exemple #31
0
    def processAlgorithm(self, feedback):
        vlayerA = dataobjects.getObjectFromUri(
            self.getParameterValue(Union.INPUT))
        vlayerB = dataobjects.getObjectFromUri(
            self.getParameterValue(Union.INPUT2))

        geomType = vlayerA.wkbType()
        fields = vector.combineVectorFields(vlayerA, vlayerB)
        writer = self.getOutputFromName(Union.OUTPUT).getVectorWriter(
            fields, geomType, vlayerA.crs())
        inFeatA = QgsFeature()
        inFeatB = QgsFeature()
        outFeat = QgsFeature()
        indexA = vector.spatialindex(vlayerB)
        indexB = vector.spatialindex(vlayerA)

        count = 0
        nElement = 0
        featuresA = vector.features(vlayerA)
        nFeat = len(featuresA)
        for inFeatA in featuresA:
            feedback.setProgress(nElement / float(nFeat) * 50)
            nElement += 1
            lstIntersectingB = []
            geom = inFeatA.geometry()
            atMapA = inFeatA.attributes()
            intersects = indexA.intersects(geom.boundingBox())
            if len(intersects) < 1:
                try:
                    outFeat.setGeometry(geom)
                    outFeat.setAttributes(atMapA)
                    writer.addFeature(outFeat)
                except:
                    # This really shouldn't happen, as we haven't
                    # edited the input geom at all
                    ProcessingLog.addToLog(
                        ProcessingLog.LOG_INFO,
                        self.
                        tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                           ))
            else:
                request = QgsFeatureRequest().setFilterFids(intersects)

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

                for inFeatB in vlayerB.getFeatures(request):
                    count += 1

                    atMapB = inFeatB.attributes()
                    tmpGeom = inFeatB.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
                            ProcessingLog.addToLog(
                                ProcessingLog.LOG_INFO,
                                self.
                                tr('GEOS geoprocessing error: One or more input features have 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:
                                        outFeat.setGeometry(int_geom)
                                        outFeat.setAttributes(atMapA + atMapB)
                                        writer.addFeature(outFeat)
                                    except:
                                        ProcessingLog.addToLog(
                                            ProcessingLog.LOG_INFO,
                                            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 int_geom.wkbType() in wkbTypeGroups[
                                    wkbTypeGroups[int_geom.wkbType()]]:
                                try:
                                    outFeat.setGeometry(int_geom)
                                    outFeat.setAttributes(atMapA + atMapB)
                                    writer.addFeature(outFeat)
                                except:
                                    ProcessingLog.addToLog(
                                        ProcessingLog.LOG_INFO,
                                        self.
                                        tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                                           ))

                # the remaining bit of inFeatA'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() == 0 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:
                    outFeat.setGeometry(diff_geom)
                    outFeat.setAttributes(atMapA)
                    writer.addFeature(outFeat)
                except:
                    ProcessingLog.addToLog(
                        ProcessingLog.LOG_INFO,
                        self.
                        tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                           ))

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

        featuresA = vector.features(vlayerB)
        nFeat = len(featuresA)
        for inFeatA in featuresA:
            feedback.setProgress(nElement / float(nFeat) * 100)
            add = False
            geom = inFeatA.geometry()
            diff_geom = QgsGeometry(geom)
            atMap = [None] * length
            atMap.extend(inFeatA.attributes())
            intersects = indexB.intersects(geom.boundingBox())

            if len(intersects) < 1:
                try:
                    outFeat.setGeometry(geom)
                    outFeat.setAttributes(atMap)
                    writer.addFeature(outFeat)
                except:
                    ProcessingLog.addToLog(
                        ProcessingLog.LOG_INFO,
                        self.
                        tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                           ))
            else:
                request = QgsFeatureRequest().setFilterFids(intersects)

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

                for inFeatB in vlayerA.getFeatures(request):
                    atMapB = inFeatB.attributes()
                    tmpGeom = inFeatB.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
                            outFeat.setGeometry(diff_geom)
                            outFeat.setAttributes(atMap)
                            writer.addFeature(outFeat)
                        except:
                            ProcessingLog.addToLog(
                                ProcessingLog.LOG_INFO,
                                self.
                                tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                                   ))

            if add:
                try:
                    outFeat.setGeometry(diff_geom)
                    outFeat.setAttributes(atMap)
                    writer.addFeature(outFeat)
                except:
                    ProcessingLog.addToLog(
                        ProcessingLog.LOG_INFO,
                        self.
                        tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                           ))
            nElement += 1

        del writer
class GeometryHighlightItem(QgsMapCanvasItem):
    # Code ported from QGIS QgsHighlight

    def __init__(self, mapCanvas, geometry, layer):
        super(GeometryHighlightItem, self).__init__(mapCanvas)

        self._mapCanvas = None  # QgsMapCanvas
        self._geometry = None  # QgsGeometry()
        self._brush = QBrush()
        self._pen = QPen()

        self._mapCanvas = mapCanvas
        if not geometry or not isinstance(geometry, QgsGeometry) or geometry.isEmpty() or not geometry.isGeosValid():
            return
        self._geometry = QgsGeometry(geometry)  # Force deep copy
        self.setLineColor(Application.highlightLineColor())
        self.setFillColor(Application.highlightFillColor())
        if (layer and self._mapCanvas.mapSettings().hasCrsTransformEnabled()):
            ct = self._mapCanvas.mapSettings().layerTransform(layer)
            if ct:
                self._geometry.transform(ct)
        self.updateRect()
        self.update()

    def remove(self):
        self._mapCanvas.scene().removeItem(self)

    def setLineWidth(self, width):
        self._pen.setWidth(width)

    def setLineColor(self, color):
        lineColor = QColor(color)
        lineColor.setAlpha(255)
        self._pen.setColor(lineColor)

    def setFillColor(self, fillColor):
        self._brush.setColor(fillColor)
        self._brush.setStyle(Qt.SolidPattern)

    def updatePosition(self):
        pass

    # protected:
    def paint(self, painter, option=None, widget=None):  # Override
        if not self._geometry:
            return

        painter.setPen(self._pen)
        painter.setBrush(self._brush)

        wkbType = self._geometry.wkbType()
        if wkbType == QGis.WKBPoint or wkbType == QGis.WKBPoint25D:
            self._paintPoint(painter, self._geometry.geometry())
        elif wkbType == QGis.WKBMultiPoint or wkbType == QGis.WKBMultiPoint25D:
            for point in self._geometry.geometry():
                self._paintPoint(painter, point)
        elif wkbType == QGis.WKBLineString or wkbType == QGis.WKBLineString25D:
            self._paintLine(painter, self._geometry.geometry())
        elif wkbType == QGis.WKBMultiLineString or wkbType == QGis.WKBMultiLineString25D:
            for line in self._geometry.geometry():
                self._paintLine(painter, line)
        elif wkbType == QGis.WKBPolygon or wkbType == QGis.WKBPolygon25D:
            self._paintPolygon(painter, self._geometry.geometry())
        elif wkbType == QGis.WKBMultiPolygon or wkbType == QGis.WKBMultiPolygon25D:
            for polygon in self._geometry.geometry():
                self._paintPolygon(painter, polygon)

    def updateRect(self):
        if self._geometry:
            r = self._geometry.boundingBox()
            if r.isEmpty():
                d = self._mapCanvas.extent().width() * 0.005
                r.setXMinimum(r.xMinimum() - d)
                r.setYMinimum(r.yMinimum() - d)
                r.setXMaximum(r.xMaximum() + d)
                r.setYMaximum(r.yMaximum() + d)
            self.setRect(r)
            self.setVisible(True)
        else:
            self.setRect(QgsRectangle())

    # private:

    def _paintPoint(self, painter, point):
        painter.drawEllipse(self.toCanvasCoordinates(point) - self.pos(), 2, 2)

    def _paintLine(self, painter, line):
        polyline = QPolygonF()
        for point in line:
            polyline.append(self.toCanvasCoordinates(point) - self.pos())
        painter.drawPolyline(polyline)

    def _paintPolygon(self, painter, polygon):
        path = QPainterPath()
        for line in polygon:
            ring = QPolygonF()
            for point in line:
                cur = self.toCanvasCoordinates(point) - self.pos()
                ring.append(cur)
            ring.append(ring[0])
            path.addPolygon(ring)
        painter.drawPath(path)
Exemple #33
0
    def processAlgorithm(self, parameters, context, feedback):
        extent = self.parameterAsExtent(parameters, self.EXTENT, context)

        spacing = self.parameterAsDouble(parameters, self.SPACING, context)
        inset = self.parameterAsDouble(parameters, self.INSET, context)
        randomize = self.parameterAsBool(parameters, self.RANDOMIZE, context)
        isSpacing = self.parameterAsBool(parameters, self.IS_SPACING, context)
        crs = self.parameterAsCrs(parameters, self.CRS, context)

        fields = QgsFields()
        fields.append(QgsField('id', QVariant.Int, '', 10, 0))

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, fields,
                                               QgsWkbTypes.Point, crs)

        if randomize:
            seed()

        area = extent.width() * extent.height()
        if isSpacing:
            pSpacing = spacing
        else:
            pSpacing = sqrt(area / spacing)

        f = QgsFeature()
        f.initAttributes(1)
        f.setFields(fields)

        count = 0
        total = 100.0 / (area / pSpacing)
        y = extent.yMaximum() - inset

        extent_geom = QgsGeometry.fromRect(extent)
        extent_engine = QgsGeometry.createGeometryEngine(
            extent_geom.geometry())
        extent_engine.prepareGeometry()

        while y >= extent.yMinimum():
            x = extent.xMinimum() + inset
            while x <= extent.xMaximum():
                if feedback.isCanceled():
                    break

                if randomize:
                    geom = QgsGeometry().fromPoint(
                        QgsPointXY(
                            uniform(x - (pSpacing / 2.0),
                                    x + (pSpacing / 2.0)),
                            uniform(y - (pSpacing / 2.0),
                                    y + (pSpacing / 2.0))))
                else:
                    geom = QgsGeometry().fromPoint(QgsPointXY(x, y))

                if extent_engine.intersects(geom.geometry()):
                    f.setAttribute('id', count)
                    f.setGeometry(geom)
                    sink.addFeature(f, QgsFeatureSink.FastInsert)
                    x += pSpacing
                    count += 1
                    feedback.setProgress(int(count * total))
            y = y - pSpacing

        return {self.OUTPUT: dest_id}
Exemple #34
0
    def processAlgorithm(self, progress):
        vlayerA = dataobjects.getObjectFromUri(
            self.getParameterValue(Union.INPUT))
        vlayerB = dataobjects.getObjectFromUri(
            self.getParameterValue(Union.INPUT2))

        vproviderA = vlayerA.dataProvider()

        geomType = vproviderA.geometryType()
        if geomType in GEOM_25D:
            raise GeoAlgorithmExecutionException(
                self.tr('Input layer does not support 2.5D type geometry ({}).'
                        ).format(QgsWKBTypes.displayString(geomType)))

        fields = vector.combineVectorFields(vlayerA, vlayerB)
        writer = self.getOutputFromName(Union.OUTPUT).getVectorWriter(
            fields, geomType, vproviderA.crs())
        inFeatA = QgsFeature()
        inFeatB = QgsFeature()
        outFeat = QgsFeature()
        indexA = vector.spatialindex(vlayerB)
        indexB = vector.spatialindex(vlayerA)

        count = 0
        nElement = 0
        featuresA = vector.features(vlayerA)
        nFeat = len(featuresA)
        for inFeatA in featuresA:
            progress.setPercentage(nElement / float(nFeat) * 50)
            nElement += 1
            lstIntersectingB = []
            geom = QgsGeometry(inFeatA.geometry())
            atMapA = inFeatA.attributes()
            intersects = indexA.intersects(geom.boundingBox())
            if len(intersects) < 1:
                try:
                    outFeat.setGeometry(geom)
                    outFeat.setAttributes(atMapA)
                    writer.addFeature(outFeat)
                except:
                    # This really shouldn't happen, as we haven't
                    # edited the input geom at all
                    ProcessingLog.addToLog(
                        ProcessingLog.LOG_INFO,
                        self.
                        tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                           ))
            else:
                for id in intersects:
                    count += 1
                    request = QgsFeatureRequest().setFilterFid(id)
                    inFeatB = vlayerB.getFeatures(request).next()
                    atMapB = inFeatB.attributes()
                    tmpGeom = QgsGeometry(inFeatB.geometry())

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

                        if int_geom is None:
                            # There was a problem creating the intersection
                            ProcessingLog.addToLog(
                                ProcessingLog.LOG_INFO,
                                self.
                                tr('GEOS geoprocessing error: One or more input features have invalid geometry.'
                                   ))
                            int_geom = QgsGeometry()
                        else:
                            int_geom = QgsGeometry(int_geom)

                        if int_geom.wkbType(
                        ) == QGis.WKBUnknown 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:
                                        outFeat.setGeometry(int_geom)
                                        outFeat.setAttributes(atMapA + atMapB)
                                        writer.addFeature(outFeat)
                                    except:
                                        ProcessingLog.addToLog(
                                            ProcessingLog.LOG_INFO,
                                            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 int_geom.wkbType() in wkbTypeGroups[
                                    wkbTypeGroups[int_geom.wkbType()]]:
                                try:
                                    outFeat.setGeometry(int_geom)
                                    outFeat.setAttributes(atMapA + atMapB)
                                    writer.addFeature(outFeat)
                                except:
                                    ProcessingLog.addToLog(
                                        ProcessingLog.LOG_INFO,
                                        self.
                                        tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                                           ))

                # the remaining bit of inFeatA'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.isGeosEmpty() or not diff_geom.isGeosValid():
                        ProcessingLog.addToLog(
                            ProcessingLog.LOG_ERROR,
                            self.
                            tr('GEOS geoprocessing error: One or more input features have invalid geometry.'
                               ))

                if diff_geom.wkbType() == 0 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:
                    outFeat.setGeometry(diff_geom)
                    outFeat.setAttributes(atMapA)
                    writer.addFeature(outFeat)
                except:
                    ProcessingLog.addToLog(
                        ProcessingLog.LOG_INFO,
                        self.
                        tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                           ))

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

        featuresA = vector.features(vlayerB)
        nFeat = len(featuresA)
        for inFeatA in featuresA:
            progress.setPercentage(nElement / float(nFeat) * 100)
            add = False
            geom = QgsGeometry(inFeatA.geometry())
            diff_geom = QgsGeometry(geom)
            atMap = [None] * length
            atMap.extend(inFeatA.attributes())
            intersects = indexB.intersects(geom.boundingBox())

            if len(intersects) < 1:
                try:
                    outFeat.setGeometry(geom)
                    outFeat.setAttributes(atMap)
                    writer.addFeature(outFeat)
                except:
                    ProcessingLog.addToLog(
                        ProcessingLog.LOG_INFO,
                        self.
                        tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                           ))
            else:
                for id in intersects:
                    request = QgsFeatureRequest().setFilterFid(id)
                    inFeatB = vlayerA.getFeatures(request).next()
                    atMapB = inFeatB.attributes()
                    tmpGeom = QgsGeometry(inFeatB.geometry())

                    if diff_geom.intersects(tmpGeom):
                        add = True
                        diff_geom = QgsGeometry(diff_geom.difference(tmpGeom))
                        if diff_geom.isGeosEmpty(
                        ) or not diff_geom.isGeosValid():
                            ProcessingLog.addToLog(
                                ProcessingLog.LOG_ERROR,
                                self.
                                tr('GEOS geoprocessing error: One or more input features have invalid geometry.'
                                   ))
                    else:
                        try:
                            # Ihis only happends if the bounding box
                            # intersects, but the geometry doesn't
                            outFeat.setGeometry(diff_geom)
                            outFeat.setAttributes(atMap)
                            writer.addFeature(outFeat)
                        except:
                            ProcessingLog.addToLog(
                                ProcessingLog.LOG_INFO,
                                self.
                                tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                                   ))

            if add:
                try:
                    outFeat.setGeometry(diff_geom)
                    outFeat.setAttributes(atMap)
                    writer.addFeature(outFeat)
                except:
                    ProcessingLog.addToLog(
                        ProcessingLog.LOG_INFO,
                        self.
                        tr('Feature geometry error: One or more output features ignored due to invalid geometry.'
                           ))
            nElement += 1

        del writer
Exemple #35
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        fieldName = self.parameterAsString(parameters, self.FIELD, context)
        useField = bool(fieldName)

        field_index = None
        f = QgsField('value', QVariant.String, '', 255)
        if useField:
            field_index = source.fields().lookupField(fieldName)
            fType = source.fields()[field_index].type()
            if fType in [QVariant.Int, QVariant.UInt, QVariant.LongLong, QVariant.ULongLong]:
                f.setType(fType)
                f.setLength(20)
            elif fType == QVariant.Double:
                f.setType(QVariant.Double)
                f.setLength(20)
                f.setPrecision(6)
            else:
                f.setType(QVariant.String)
                f.setLength(255)

        fields = QgsFields()
        fields.append(QgsField('id', QVariant.Int, '', 20))
        fields.append(f)
        fields.append(QgsField('area', QVariant.Double, '', 20, 6))
        fields.append(QgsField('perim', QVariant.Double, '', 20, 6))

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

        outFeat = QgsFeature()
        outGeom = QgsGeometry()

        fid = 0
        val = None
        if useField:
            unique = source.uniqueValues(field_index)
            current = 0
            total = 100.0 / (source.featureCount() * len(unique)) if source.featureCount() else 1
            for i in unique:
                if feedback.isCanceled():
                    break

                first = True
                hull = []
                features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([field_index]))
                for f in features:
                    if feedback.isCanceled():
                        break

                    idVar = f.attributes()[field_index]
                    if str(idVar).strip() == str(i).strip():
                        if first:
                            val = idVar
                            first = False

                        inGeom = f.geometry()
                        points = vector.extractPoints(inGeom)
                        hull.extend(points)
                    current += 1
                    feedback.setProgress(int(current * total))

                if len(hull) >= 3:
                    tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull))
                    try:
                        outGeom = tmpGeom.convexHull()
                        if outGeom:
                            area = outGeom.geometry().area()
                            perim = outGeom.geometry().perimeter()
                        else:
                            area = NULL
                            perim = NULL
                        outFeat.setGeometry(outGeom)
                        outFeat.setAttributes([fid, val, area, perim])
                        sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
                    except:
                        raise QgsProcessingException(
                            self.tr('Exception while computing convex hull'))
                fid += 1
        else:
            hull = []
            total = 100.0 / source.featureCount() if source.featureCount() else 1
            features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]))
            for current, f in enumerate(features):
                if feedback.isCanceled():
                    break

                inGeom = f.geometry()
                points = vector.extractPoints(inGeom)
                hull.extend(points)
                feedback.setProgress(int(current * total))

            tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull))
            try:
                outGeom = tmpGeom.convexHull()
                if outGeom:
                    area = outGeom.geometry().area()
                    perim = outGeom.geometry().perimeter()
                else:
                    area = NULL
                    perim = NULL
                outFeat.setGeometry(outGeom)
                outFeat.setAttributes([0, 'all', area, perim])
                sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
            except:
                raise QgsProcessingException(
                    self.tr('Exception while computing convex hull'))

        return {self.OUTPUT: dest_id}
    def processAlgorithm(self, progress):
        vlayerA = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT))
        vlayerB = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT2))
        ignoreNull = self.getParameterValue(Intersection.IGNORE_NULL)

        geomType = QgsWKBTypes.multiType(QGis.fromOldWkbType(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) if len(selectionA) > 0 else 1
        for current, inFeatA in enumerate(selectionA):
            progress.setPercentage(int(current * total))
            geom = inFeatA.geometry()
            if not geom:
                if ignoreNull:
                    continue
                else:
                    raise GeoAlgorithmExecutionException(
                        self.tr('Input layer A contains NULL geometries. '
                                'Please check "Ignore NULL geometries" '
                                'if you want to run this algorithm anyway.'))
            if not geom.isGeosValid():
                raise GeoAlgorithmExecutionException(
                    self.tr('Input layer A contains invalid geometries '
                            '(feature {}). Unable to complete intersection '
                            'algorithm.'.format(inFeatA.id())))
            atMapA = inFeatA.attributes()
            intersects = index.intersects(geom.boundingBox())
            for inFeatB in vlayerB.getFeatures(QgsFeatureRequest().setFilterFids(intersects)):
                tmpGeom = QgsGeometry(inFeatB.geometry())
                if not geom:
                    if ignoreNull:
                        continue
                    else:
                        raise GeoAlgorithmExecutionException(
                            self.tr('Input layer B contains NULL geometries. '
                                    'Please check "Ignore NULL geometries" '
                                    'if you want to run this algorithm anyway.'))
                if not geom.isGeosValid():
                    raise GeoAlgorithmExecutionException(
                        self.tr('Input layer B contains invalid geometries '
                                '(feature {}). Unable to complete intersection '
                                'algorithm.'.format(inFeatB.id())))

                if geom.intersects(tmpGeom):
                    atMapB = inFeatB.attributes()
                    int_geom = QgsGeometry(geom.intersection(tmpGeom))
                    if int_geom.wkbType() == QGis.WKBUnknown or QgsWKBTypes.flatType(int_geom.geometry().wkbType()) == QgsWKBTypes.GeometryCollection:
                        int_com = geom.combine(tmpGeom)
                        int_geom = QgsGeometry()
                        if int_com is not None:
                            int_sym = geom.symDifference(tmpGeom)
                            if int_sym:
                                diff_geom = int_com.difference(int_sym)
                                int_geom = QgsGeometry(diff_geom)

                    if int_geom.isGeosEmpty() 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)
                    except:
                        raise GeoAlgorithmExecutionException(
                            self.tr('Feature geometry error: one or '
                                    'more output features ignored due '
                                    'to invalid geometry.'))

        del writer
Exemple #37
0
    def processAlgorithm(self, parameters, context, feedback):
        vlayerA = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(Union.INPUT), context)
        vlayerB = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(Union.INPUT2), context)

        geomType = vlayerA.wkbType()
        fields = vector.combineFields(vlayerA.fields(), vlayerB.fields())
        writer = self.getOutputFromName(Union.OUTPUT).getVectorWriter(fields, geomType, vlayerA.crs(), context)
        inFeatA = QgsFeature()
        inFeatB = QgsFeature()
        outFeat = QgsFeature()
        indexA = QgsProcessingUtils.createSpatialIndex(vlayerB, context)
        indexB = QgsProcessingUtils.createSpatialIndex(vlayerA, context)

        count = 0
        nElement = 0
        featuresA = QgsProcessingUtils.getFeatures(vlayerA, context)
        nFeat = QgsProcessingUtils.featureCount(vlayerA, context)
        for inFeatA in featuresA:
            feedback.setProgress(nElement / float(nFeat) * 50)
            nElement += 1
            lstIntersectingB = []
            geom = inFeatA.geometry()
            atMapA = inFeatA.attributes()
            intersects = indexA.intersects(geom.boundingBox())
            if len(intersects) < 1:
                try:
                    outFeat.setGeometry(geom)
                    outFeat.setAttributes(atMapA)
                    writer.addFeature(outFeat, QgsFeatureSink.FastInsert)
                except:
                    # This really shouldn't happen, as we haven't
                    # edited the input geom at all
                    QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'),
                                             self.tr('Processing'), QgsMessageLog.INFO)
            else:
                request = QgsFeatureRequest().setFilterFids(intersects)

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

                for inFeatB in vlayerB.getFeatures(request):
                    count += 1

                    atMapB = inFeatB.attributes()
                    tmpGeom = inFeatB.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
                            QgsMessageLog.logMessage(self.tr('GEOS geoprocessing error: One or more input features have invalid geometry.'),
                                                     self.tr('Processing'), QgsMessageLog.INFO)
                            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:
                                        outFeat.setGeometry(int_geom)
                                        outFeat.setAttributes(atMapA + atMapB)
                                        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.INFO)
                        else:
                            # Geometry list: prevents writing error
                            # in geometries of different types
                            # produced by the intersection
                            # fix #3549
                            if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]:
                                try:
                                    outFeat.setGeometry(int_geom)
                                    outFeat.setAttributes(atMapA + atMapB)
                                    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.INFO)

                # the remaining bit of inFeatA'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() == 0 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:
                    outFeat.setGeometry(diff_geom)
                    outFeat.setAttributes(atMapA)
                    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.INFO)

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

        featuresA = QgsProcessingUtils.getFeatures(vlayerB, context)
        nFeat = QgsProcessingUtils.featureCount(vlayerB, context)
        for inFeatA in featuresA:
            feedback.setProgress(nElement / float(nFeat) * 100)
            add = False
            geom = inFeatA.geometry()
            diff_geom = QgsGeometry(geom)
            atMap = [None] * length
            atMap.extend(inFeatA.attributes())
            intersects = indexB.intersects(geom.boundingBox())

            if len(intersects) < 1:
                try:
                    outFeat.setGeometry(geom)
                    outFeat.setAttributes(atMap)
                    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.INFO)
            else:
                request = QgsFeatureRequest().setFilterFids(intersects)

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

                for inFeatB in vlayerA.getFeatures(request):
                    atMapB = inFeatB.attributes()
                    tmpGeom = inFeatB.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
                            outFeat.setGeometry(diff_geom)
                            outFeat.setAttributes(atMap)
                            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.INFO)

            if add:
                try:
                    outFeat.setGeometry(diff_geom)
                    outFeat.setAttributes(atMap)
                    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.INFO)
            nElement += 1

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

        geomType = vlayerA.wkbType()
        fields = vector.combineVectorFields(vlayerA, vlayerB)
        writer = self.getOutputFromName(Union.OUTPUT).getVectorWriter(fields, geomType, vlayerA.crs())
        inFeatA = QgsFeature()
        inFeatB = QgsFeature()
        outFeat = QgsFeature()
        indexA = vector.spatialindex(vlayerB)
        indexB = vector.spatialindex(vlayerA)

        count = 0
        nElement = 0
        featuresA = vector.features(vlayerA)
        nFeat = len(featuresA)
        for inFeatA in featuresA:
            progress.setPercentage(nElement / float(nFeat) * 50)
            nElement += 1
            lstIntersectingB = []
            geom = inFeatA.geometry()
            atMapA = inFeatA.attributes()
            intersects = indexA.intersects(geom.boundingBox())
            if len(intersects) < 1:
                try:
                    outFeat.setGeometry(geom)
                    outFeat.setAttributes(atMapA)
                    writer.addFeature(outFeat)
                except:
                    # This really shouldn't happen, as we haven't
                    # edited the input geom at all
                    ProcessingLog.addToLog(
                        ProcessingLog.LOG_INFO,
                        self.tr("Feature geometry error: One or more output features ignored due to invalid geometry."),
                    )
            else:
                request = QgsFeatureRequest().setFilterFids(intersects)

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

                for inFeatB in vlayerB.getFeatures(request):
                    count += 1

                    atMapB = inFeatB.attributes()
                    tmpGeom = inFeatB.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
                            ProcessingLog.addToLog(
                                ProcessingLog.LOG_INFO,
                                self.tr("GEOS geoprocessing error: One or more input features have 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:
                                        outFeat.setGeometry(int_geom)
                                        outFeat.setAttributes(atMapA + atMapB)
                                        writer.addFeature(outFeat)
                                    except:
                                        ProcessingLog.addToLog(
                                            ProcessingLog.LOG_INFO,
                                            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 int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]:
                                try:
                                    outFeat.setGeometry(int_geom)
                                    outFeat.setAttributes(atMapA + atMapB)
                                    writer.addFeature(outFeat)
                                except:
                                    ProcessingLog.addToLog(
                                        ProcessingLog.LOG_INFO,
                                        self.tr(
                                            "Feature geometry error: One or more output features ignored due to invalid geometry."
                                        ),
                                    )

                # the remaining bit of inFeatA'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.isGeosEmpty() or not diff_geom.isGeosValid():
                        ProcessingLog.addToLog(
                            ProcessingLog.LOG_ERROR,
                            self.tr("GEOS geoprocessing error: One or more input features have invalid geometry."),
                        )

                if (
                    diff_geom.wkbType() == 0
                    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:
                    outFeat.setGeometry(diff_geom)
                    outFeat.setAttributes(atMapA)
                    writer.addFeature(outFeat)
                except:
                    ProcessingLog.addToLog(
                        ProcessingLog.LOG_INFO,
                        self.tr("Feature geometry error: One or more output features ignored due to invalid geometry."),
                    )

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

        featuresA = vector.features(vlayerB)
        nFeat = len(featuresA)
        for inFeatA in featuresA:
            progress.setPercentage(nElement / float(nFeat) * 100)
            add = False
            geom = inFeatA.geometry()
            diff_geom = QgsGeometry(geom)
            atMap = [None] * length
            atMap.extend(inFeatA.attributes())
            intersects = indexB.intersects(geom.boundingBox())

            if len(intersects) < 1:
                try:
                    outFeat.setGeometry(geom)
                    outFeat.setAttributes(atMap)
                    writer.addFeature(outFeat)
                except:
                    ProcessingLog.addToLog(
                        ProcessingLog.LOG_INFO,
                        self.tr("Feature geometry error: One or more output features ignored due to invalid geometry."),
                    )
            else:
                request = QgsFeatureRequest().setFilterFids(intersects)

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

                for inFeatB in vlayerA.getFeatures(request):
                    atMapB = inFeatB.attributes()
                    tmpGeom = inFeatB.geometry()

                    if engine.intersects(tmpGeom.geometry()):
                        add = True
                        diff_geom = QgsGeometry(diff_geom.difference(tmpGeom))
                        if diff_geom.isGeosEmpty() or not diff_geom.isGeosValid():
                            ProcessingLog.addToLog(
                                ProcessingLog.LOG_ERROR,
                                self.tr("GEOS geoprocessing error: One or more input features have invalid geometry."),
                            )
                    else:
                        try:
                            # Ihis only happends if the bounding box
                            # intersects, but the geometry doesn't
                            outFeat.setGeometry(diff_geom)
                            outFeat.setAttributes(atMap)
                            writer.addFeature(outFeat)
                        except:
                            ProcessingLog.addToLog(
                                ProcessingLog.LOG_INFO,
                                self.tr(
                                    "Feature geometry error: One or more output features ignored due to invalid geometry."
                                ),
                            )

            if add:
                try:
                    outFeat.setGeometry(diff_geom)
                    outFeat.setAttributes(atMap)
                    writer.addFeature(outFeat)
                except:
                    ProcessingLog.addToLog(
                        ProcessingLog.LOG_INFO,
                        self.tr("Feature geometry error: One or more output features ignored due to invalid geometry."),
                    )
            nElement += 1

        del writer
    def processAlgorithm(self, progress):
        polyLayer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.POLYGONS))
        pointLayer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.POINTS))
        fieldName = self.getParameterValue(self.FIELD)
        classFieldName = self.getParameterValue(self.CLASSFIELD)

        polyProvider = polyLayer.dataProvider()
        fields = polyProvider.fields()
        fields.append(QgsField(fieldName, QVariant.Int))

        classFieldIndex = pointLayer.fieldNameIndex(classFieldName)
        (idxCount,
         fieldList) = vector.findOrCreateField(polyLayer,
                                               polyLayer.pendingFields(),
                                               fieldName)

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fields.toList(), polyProvider.geometryType(), polyProvider.crs())

        spatialIndex = vector.spatialindex(pointLayer)

        ftPoint = QgsFeature()
        outFeat = QgsFeature()
        geom = QgsGeometry()

        current = 0

        features = vector.features(polyLayer)
        total = 100.0 / float(len(features))
        for ftPoly in features:
            geom = ftPoly.geometry()
            engine = QgsGeometry.createGeometryEngine(geom.geometry())
            engine.prepareGeometry()

            attrs = ftPoly.attributes()

            classes = set()
            points = spatialIndex.intersects(geom.boundingBox())
            if len(points) > 0:
                request = QgsFeatureRequest().setFilterFids(points)
                fit = pointLayer.getFeatures(request)
                ftPoint = QgsFeature()
                while fit.nextFeature(ftPoint):
                    tmpGeom = QgsGeometry(ftPoint.geometry())
                    if engine.contains(tmpGeom.geometry()):
                        clazz = ftPoint.attributes()[classFieldIndex]
                        if clazz not in classes:
                            classes.add(clazz)

            outFeat.setGeometry(geom)
            if idxCount == len(attrs):
                attrs.append(len(classes))
            else:
                attrs[idxCount] = len(classes)
            outFeat.setAttributes(attrs)
            writer.addFeature(outFeat)

            current += 1
            progress.setPercentage(current / total)

        del writer
Exemple #40
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
Exemple #41
0
def union(union_a, union_b, callback=None):
    """Union of two vector layers.

    Issue https://github.com/inasafe/inasafe/issues/3186

    Note : This algorithm is copied from :
    https://github.com/qgis/QGIS/blob/master/python/plugins/processing/algs/
    qgis/Union.py

    :param union_a: The vector layer for the union.
    :type union_a: QgsVectorLayer

    :param union_b: The vector layer for the union.
    :type union_b: QgsVectorLayer

    :param callback: A function to all to indicate progress. The function
        should accept params 'current' (int), 'maximum' (int) and 'step' (str).
        Defaults to None.
    :type callback: function

    :return: The clip vector layer.
    :rtype: QgsVectorLayer

    .. versionadded:: 4.0
    """
    output_layer_name = union_steps['output_layer_name']
    processing_step = union_steps['step_name']
    output_layer_name = output_layer_name % (union_a.keywords['layer_purpose'],
                                             union_b.keywords['layer_purpose'])

    fields = union_a.fields()
    fields.extend(union_b.fields())

    writer = create_memory_layer(output_layer_name, union_a.geometryType(),
                                 union_a.crs(), fields)
    keywords_union_1 = union_a.keywords
    keywords_union_2 = union_b.keywords
    inasafe_fields_union_1 = keywords_union_1['inasafe_fields']
    inasafe_fields_union_2 = keywords_union_2['inasafe_fields']
    inasafe_fields = inasafe_fields_union_1
    inasafe_fields.update(inasafe_fields_union_2)

    # use to avoid modifying original source
    writer.keywords = dict(union_a.keywords)
    writer.keywords['inasafe_fields'] = inasafe_fields
    writer.keywords['title'] = output_layer_name
    writer.keywords['layer_purpose'] = 'aggregate_hazard'
    writer.keywords['hazard_keywords'] = keywords_union_1.copy()
    writer.keywords['aggregation_keywords'] = keywords_union_2.copy()
    skip_field = inasafe_fields_union_2[aggregation_id_field['key']]
    not_null_field_index = writer.fieldNameIndex(skip_field)

    writer.startEditing()

    # Begin copy/paste from Processing plugin.
    # Please follow their code as their code is optimized.
    # The code below is not following our coding standards because we want to
    # be able to track any diffs from QGIS easily.

    index_a = create_spatial_index(union_b)
    index_b = create_spatial_index(union_a)

    count = 0
    n_element = 0
    # Todo fix callback
    # nFeat = len(union_a.getFeatures())
    for in_feat_a in union_a.getFeatures():
        # progress.setPercentage(nElement / float(nFeat) * 50)
        n_element += 1
        list_intersecting_b = []
        geom = geometry_checker(in_feat_a.geometry())
        at_map_a = in_feat_a.attributes()
        intersects = index_a.intersects(geom.boundingBox())
        if len(intersects) < 1:
            try:
                _write_feature(at_map_a, geom, writer, not_null_field_index)
            except:
                # This really shouldn't happen, as we haven't
                # edited the input geom at all
                LOGGER.debug(
                    tr('Feature geometry error: One or more output features '
                       'ignored due to invalid geometry.'))
        else:
            request = QgsFeatureRequest().setFilterFids(intersects)

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

            for in_feat_b in union_b.getFeatures(request):
                count += 1

                at_map_b = in_feat_b.attributes()
                tmp_geom = geometry_checker(in_feat_b.geometry())

                if engine.intersects(tmp_geom.geometry()):
                    int_geom = geometry_checker(geom.intersection(tmp_geom))
                    list_intersecting_b.append(QgsGeometry(tmp_geom))

                    if not int_geom:
                        # There was a problem creating the intersection
                        # LOGGER.debug(
                        #     tr('GEOS geoprocessing error: One or more input '
                        #        'features have invalid geometry.'))
                        pass
                        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 geometry types
                        temp_list = int_geom.asGeometryCollection()
                        for i in temp_list:
                            if i.type() == geom.type():
                                int_geom = QgsGeometry(geometry_checker(i))
                                try:
                                    _write_feature(
                                        at_map_a + at_map_b,
                                        int_geom,
                                        writer,
                                        not_null_field_index,
                                    )
                                except:
                                    LOGGER.debug(
                                        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 int_geom.wkbType() in wkb_type_groups[
                                wkb_type_groups[int_geom.wkbType()]]:
                            try:
                                _write_feature(at_map_a + at_map_b, int_geom,
                                               writer, not_null_field_index)
                            except:
                                LOGGER.debug(
                                    tr('Feature geometry error: One or more '
                                       'output features ignored due to '
                                       'invalid geometry.'))

            # the remaining bit of inFeatA's geometry
            # if there is nothing left, this will just silently fail and we
            # are good
            diff_geom = QgsGeometry(geom)
            if len(list_intersecting_b) != 0:
                int_b = QgsGeometry.unaryUnion(list_intersecting_b)
                diff_geom = geometry_checker(diff_geom.difference(int_b))
                if diff_geom is None or \
                    diff_geom.isGeosEmpty() or not diff_geom.isGeosValid():
                    # LOGGER.debug(
                    #     tr('GEOS geoprocessing error: One or more input '
                    #        'features have invalid geometry.'))
                    pass

            if diff_geom is not None and (diff_geom.wkbType() == 0
                                          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(geometry_checker(i))
            try:
                _write_feature(at_map_a, diff_geom, writer,
                               not_null_field_index)
            except:
                LOGGER.debug(
                    tr('Feature geometry error: One or more output features '
                       'ignored due to invalid geometry.'))

    length = len(union_a.fields())
    at_map_a = [None] * length

    # nFeat = len(union_b.getFeatures())
    for in_feat_a in union_b.getFeatures():
        # progress.setPercentage(nElement / float(nFeat) * 100)
        add = False
        geom = geometry_checker(in_feat_a.geometry())
        atMap = [None] * length
        atMap.extend(in_feat_a.attributes())
        intersects = index_b.intersects(geom.boundingBox())
        lstIntersectingA = []

        for id in intersects:
            request = QgsFeatureRequest().setFilterFid(id)
            inFeatB = union_a.getFeatures(request).next()
            atMapB = inFeatB.attributes()
            tmpGeom = QgsGeometry(geometry_checker(inFeatB.geometry()))

            if geom.intersects(tmpGeom):
                lstIntersectingA.append(tmpGeom)

        if len(lstIntersectingA) == 0:
            res_geom = geom
        else:
            intA = QgsGeometry.unaryUnion(lstIntersectingA)
            res_geom = geom.difference(intA)
            if res_geom is None:
                # LOGGER.debug(
                #    tr('GEOS geoprocessing error: One or more input features '
                #        'have null geometry.'))
                pass
                continue  # maybe it is better to fail like @gustry
                # does below ....
            if res_geom.isGeosEmpty() or not res_geom.isGeosValid():
                # LOGGER.debug(
                #    tr('GEOS geoprocessing error: One or more input features '
                #        'have invalid geometry.'))
                pass

        try:
            _write_feature(atMap, res_geom, writer, not_null_field_index)
        except:
            # LOGGER.debug(
            #     tr('Feature geometry error: One or more output features '
            #        'ignored due to invalid geometry.'))
            pass

        n_element += 1

    # End of copy/paste from processing

    writer.commitChanges()

    fill_hazard_class(writer)

    check_layer(writer)
    return writer
Exemple #42
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(self.getParameterValue(
            self.INPUT))
        method = self.getParameterValue(self.METHOD)

        geometryType = layer.geometryType()
        fields = layer.fields()

        export_z = False
        export_m = False
        if geometryType == QgsWkbTypes.PolygonGeometry:
            areaName = vector.createUniqueFieldName('area', fields)
            fields.append(QgsField(areaName, QVariant.Double))
            perimeterName = vector.createUniqueFieldName('perimeter', fields)
            fields.append(QgsField(perimeterName, QVariant.Double))
        elif geometryType == QgsWkbTypes.LineGeometry:
            lengthName = vector.createUniqueFieldName('length', fields)
            fields.append(QgsField(lengthName, QVariant.Double))
        else:
            xName = vector.createUniqueFieldName('xcoord', fields)
            fields.append(QgsField(xName, QVariant.Double))
            yName = vector.createUniqueFieldName('ycoord', fields)
            fields.append(QgsField(yName, QVariant.Double))
            if QgsWkbTypes.hasZ(layer.wkbType()):
                export_z = True
                zName = vector.createUniqueFieldName('zcoord', fields)
                fields.append(QgsField(zName, QVariant.Double))
            if QgsWkbTypes.hasM(layer.wkbType()):
                export_m = True
                zName = vector.createUniqueFieldName('mvalue', fields)
                fields.append(QgsField(zName, QVariant.Double))

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

        ellips = None
        crs = None
        coordTransform = None

        # Calculate with:
        # 0 - layer CRS
        # 1 - project CRS
        # 2 - ellipsoidal

        if method == 2:
            ellips = QgsProject.instance().readEntry('Measure', '/Ellipsoid',
                                                     'NONE')[0]
            crs = layer.crs().srsid()
        elif method == 1:
            mapCRS = iface.mapCanvas().mapSettings().destinationCrs()
            layCRS = layer.crs()
            coordTransform = QgsCoordinateTransform(layCRS, mapCRS)

        outFeat = QgsFeature()
        inGeom = QgsGeometry()

        outFeat.initAttributes(len(fields))
        outFeat.setFields(fields)

        features = vector.features(layer)
        total = 100.0 / len(features)
        for current, f in enumerate(features):
            inGeom = f.geometry()

            if method == 1:
                inGeom.transform(coordTransform)

            (attr1, attr2) = vector.simpleMeasure(inGeom, method, ellips, crs)

            outFeat.setGeometry(inGeom)
            attrs = f.attributes()
            attrs.append(attr1)
            if attr2 is not None:
                attrs.append(attr2)

            # add point z/m
            if export_z:
                attrs.append(inGeom.geometry().z())
            if export_m:
                attrs.append(inGeom.geometry().m())

            outFeat.setAttributes(attrs)
            writer.addFeature(outFeat)

            progress.setPercentage(int(current * total))

        del writer
Exemple #43
0
    def processAlgorithm(self, parameters, context, feedback):
        polyLayer = QgsProcessingUtils.mapLayerFromString(
            self.getParameterValue(self.POLYGONS), context)
        pointLayer = QgsProcessingUtils.mapLayerFromString(
            self.getParameterValue(self.POINTS), context)
        fieldName = self.getParameterValue(self.FIELD)
        classFieldName = self.getParameterValue(self.CLASSFIELD)

        fields = polyLayer.fields()
        fields.append(QgsField(fieldName, QVariant.Int))

        classFieldIndex = pointLayer.fields().lookupField(classFieldName)
        (idxCount,
         fieldList) = vector.findOrCreateField(polyLayer, polyLayer.fields(),
                                               fieldName)

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fields, polyLayer.wkbType(), polyLayer.crs(), context)

        spatialIndex = QgsProcessingUtils.createSpatialIndex(
            pointLayer, context)

        ftPoint = QgsFeature()
        outFeat = QgsFeature()
        geom = QgsGeometry()

        features = QgsProcessingUtils.getFeatures(polyLayer, context)
        total = 100.0 / polyLayer.featureCount() if polyLayer.featureCount(
        ) else 0
        for current, ftPoly in enumerate(features):
            geom = ftPoly.geometry()
            engine = QgsGeometry.createGeometryEngine(geom.geometry())
            engine.prepareGeometry()

            attrs = ftPoly.attributes()

            classes = set()
            points = spatialIndex.intersects(geom.boundingBox())
            if len(points) > 0:
                request = QgsFeatureRequest().setFilterFids(
                    points).setSubsetOfAttributes([classFieldIndex])
                fit = pointLayer.getFeatures(request)
                ftPoint = QgsFeature()
                while fit.nextFeature(ftPoint):
                    tmpGeom = QgsGeometry(ftPoint.geometry())
                    if engine.contains(tmpGeom.geometry()):
                        clazz = ftPoint.attributes()[classFieldIndex]
                        if clazz not in classes:
                            classes.add(clazz)

            outFeat.setGeometry(geom)
            if idxCount == len(attrs):
                attrs.append(len(classes))
            else:
                attrs[idxCount] = len(classes)
            outFeat.setAttributes(attrs)
            writer.addFeature(outFeat, QgsFeatureSink.FastInsert)

            feedback.setProgress(int(current * total))

        del writer
Exemple #44
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT))
        method = self.getParameterValue(self.METHOD)

        geometryType = layer.geometryType()
        fields = layer.fields()

        export_z = False
        export_m = False
        if geometryType == QgsWkbTypes.PolygonGeometry:
            areaName = vector.createUniqueFieldName('area', fields)
            fields.append(QgsField(areaName, QVariant.Double))
            perimeterName = vector.createUniqueFieldName('perimeter', fields)
            fields.append(QgsField(perimeterName, QVariant.Double))
        elif geometryType == QgsWkbTypes.LineGeometry:
            lengthName = vector.createUniqueFieldName('length', fields)
            fields.append(QgsField(lengthName, QVariant.Double))
        else:
            xName = vector.createUniqueFieldName('xcoord', fields)
            fields.append(QgsField(xName, QVariant.Double))
            yName = vector.createUniqueFieldName('ycoord', fields)
            fields.append(QgsField(yName, QVariant.Double))
            if QgsWkbTypes.hasZ(layer.wkbType()):
                export_z = True
                zName = vector.createUniqueFieldName('zcoord', fields)
                fields.append(QgsField(zName, QVariant.Double))
            if QgsWkbTypes.hasM(layer.wkbType()):
                export_m = True
                zName = vector.createUniqueFieldName('mvalue', fields)
                fields.append(QgsField(zName, QVariant.Double))

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

        ellips = None
        crs = None
        coordTransform = None

        # Calculate with:
        # 0 - layer CRS
        # 1 - project CRS
        # 2 - ellipsoidal

        if method == 2:
            ellips = QgsProject.instance().readEntry('Measure', '/Ellipsoid',
                                                     'NONE')[0]
            crs = layer.crs().srsid()
        elif method == 1:
            mapCRS = iface.mapCanvas().mapSettings().destinationCrs()
            layCRS = layer.crs()
            coordTransform = QgsCoordinateTransform(layCRS, mapCRS)

        outFeat = QgsFeature()
        inGeom = QgsGeometry()

        outFeat.initAttributes(len(fields))
        outFeat.setFields(fields)

        features = vector.features(layer)
        total = 100.0 / len(features)
        for current, f in enumerate(features):
            inGeom = f.geometry()

            if method == 1:
                inGeom.transform(coordTransform)

            (attr1, attr2) = vector.simpleMeasure(inGeom, method, ellips, crs)

            outFeat.setGeometry(inGeom)
            attrs = f.attributes()
            attrs.append(attr1)
            if attr2 is not None:
                attrs.append(attr2)

            # add point z/m
            if export_z:
                attrs.append(inGeom.geometry().z())
            if export_m:
                attrs.append(inGeom.geometry().m())

            outFeat.setAttributes(attrs)
            writer.addFeature(outFeat)

            progress.setPercentage(int(current * total))

        del writer
Exemple #45
0
    def processAlgorithm(self, progress):
        lineLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.LINES))
        polyLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.POLYGONS))
        lengthFieldName = self.getParameterValue(self.LEN_FIELD)
        countFieldName = self.getParameterValue(self.COUNT_FIELD)

        (idxLength, fieldList) = vector.findOrCreateField(polyLayer,
                                                          polyLayer.fields(), lengthFieldName)
        (idxCount, fieldList) = vector.findOrCreateField(polyLayer, fieldList,
                                                         countFieldName)

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fieldList.toList(), polyLayer.wkbType(), polyLayer.crs())

        spatialIndex = vector.spatialindex(lineLayer)

        ftLine = QgsFeature()
        ftPoly = QgsFeature()
        outFeat = QgsFeature()
        inGeom = QgsGeometry()
        outGeom = QgsGeometry()
        distArea = QgsDistanceArea()

        features = vector.features(polyLayer)
        total = 100.0 / len(features)
        hasIntersections = False
        for current, ftPoly in enumerate(features):
            inGeom = ftPoly.geometry()
            attrs = ftPoly.attributes()
            count = 0
            length = 0
            hasIntersections = False
            lines = spatialIndex.intersects(inGeom.boundingBox())
            engine = None
            if len(lines) > 0:
                hasIntersections = True
                # use prepared geometries for faster intersection tests
                engine = QgsGeometry.createGeometryEngine(inGeom.geometry())
                engine.prepareGeometry()

            if hasIntersections:
                request = QgsFeatureRequest().setFilterFids(lines).setSubsetOfAttributes([])
                for ftLine in lineLayer.getFeatures(request):
                    tmpGeom = ftLine.geometry()
                    if engine.intersects(tmpGeom.geometry()):
                        outGeom = inGeom.intersection(tmpGeom)
                        length += distArea.measureLength(outGeom)
                        count += 1

            outFeat.setGeometry(inGeom)
            if idxLength == len(attrs):
                attrs.append(length)
            else:
                attrs[idxLength] = length
            if idxCount == len(attrs):
                attrs.append(count)
            else:
                attrs[idxCount] = count
            outFeat.setAttributes(attrs)
            writer.addFeature(outFeat)

            progress.setPercentage(int(current * total))

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

        geomType = vlayerA.wkbType()
        fields = vector.combineVectorFields(vlayerA, vlayerB)
        writer = self.getOutputFromName(Union.OUTPUT).getVectorWriter(fields,
                                                                      geomType,
                                                                      vlayerA.crs())
        inFeatA = QgsFeature()
        inFeatB = QgsFeature()
        outFeat = QgsFeature()
        indexA = vector.spatialindex(vlayerB)
        indexB = vector.spatialindex(vlayerA)

        count = 0
        nElement = 0
        featuresA = vector.features(vlayerA)
        nFeat = len(featuresA) if len(featuresA) > 0 else 1
        for inFeatA in featuresA:
            progress.setPercentage(nElement / float(nFeat) * 50)
            nElement += 1
            lstIntersectingB = []
            geom = QgsGeometry(inFeatA.geometry())
            atMapA = inFeatA.attributes()
            intersects = indexA.intersects(geom.boundingBox())
            if len(intersects) < 1:
                try:
                    outFeat.setGeometry(geom)
                    outFeat.setAttributes(atMapA)
                    writer.addFeature(outFeat)
                except:
                    # This really shouldn't happen, as we haven't
                    # edited the input geom at all
                    ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
                                           self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
            else:
                for id in intersects:
                    count += 1
                    request = QgsFeatureRequest().setFilterFid(id)
                    inFeatB = vlayerB.getFeatures(request).next()
                    atMapB = inFeatB.attributes()
                    tmpGeom = QgsGeometry(inFeatB.geometry())

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

                        if int_geom is None:
                            # There was a problem creating the intersection
                            ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
                                                   self.tr('GEOS geoprocessing error: One or more input features have invalid geometry.'))
                            int_geom = QgsGeometry()
                        else:
                            int_geom = QgsGeometry(int_geom)

                        # TODO: the result may have a different dimension (e.g. intersection of two polygons may result in a single point)
                        # or the result may be a collection of geometries (e.g. intersection of two polygons results in three polygons and one linestring).
                        # We need to filter out all acceptable geometries into a single (possibly multi-part) geometry - and we need
                        # to do it consistently also in the code further below

                        if int_geom.wkbType() == QGis.WKBUnknown 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:
                                        outFeat.setGeometry(int_geom)
                                        outFeat.setAttributes(atMapA + atMapB)
                                        writer.addFeature(outFeat)
                                    except:
                                        ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
                                                               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 int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]:
                                try:
                                    outFeat.setGeometry(int_geom)
                                    outFeat.setAttributes(atMapA + atMapB)
                                    writer.addFeature(outFeat)
                                except:
                                    ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
                                                           self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))

                # the remaining bit of inFeatA'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 is None:
                        ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
                                               self.tr('GEOS geoprocessing error: One or more input features have invalid geometry.'))
                        diff_geom = QgsGeometry()
                    if diff_geom.isGeosEmpty() or not diff_geom.isGeosValid():
                        ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                               self.tr('GEOS geoprocessing error: One or more input features have invalid geometry.'))

                # TODO: correctly handly different output geometry types (see todo above)
                if diff_geom.wkbType() == 0 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:
                    outFeat.setGeometry(diff_geom)
                    outFeat.setAttributes(atMapA)
                    writer.addFeature(outFeat)
                except:
                    ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
                                           self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))

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

        featuresA = vector.features(vlayerB)
        nFeat = len(featuresA) if len(featuresA) else 1
        for inFeatA in featuresA:
            progress.setPercentage(nElement / float(nFeat) * 100)
            add = False
            geom = QgsGeometry(inFeatA.geometry())
            atMap = [None] * length
            atMap.extend(inFeatA.attributes())
            intersects = indexB.intersects(geom.boundingBox())
            lstIntersectingA = []

            for id in intersects:
                request = QgsFeatureRequest().setFilterFid(id)
                inFeatB = vlayerA.getFeatures(request).next()
                atMapB = inFeatB.attributes()
                tmpGeom = QgsGeometry(inFeatB.geometry())

                if geom.intersects(tmpGeom):
                    lstIntersectingA.append(tmpGeom)

            if len(lstIntersectingA) == 0:
                res_geom = geom
            else:
                intA = QgsGeometry.unaryUnion(lstIntersectingA)
                res_geom = geom.difference(intA)
                if res_geom is None:
                    ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
                                           self.tr('GEOS geoprocessing error: One or more input features have invalid geometry.'))
                    res_geom = QgsGeometry()
                if res_geom.isGeosEmpty() or not res_geom.isGeosValid():
                    ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                           self.tr('GEOS geoprocessing error: One or more input features have invalid geometry.'))

            # TODO: correctly handly different output geometry types (see todo above)

            try:
                outFeat.setGeometry(res_geom)
                outFeat.setAttributes(atMap)
                writer.addFeature(outFeat)
            except:
                ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
                                       self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
            nElement += 1

        del writer
Exemple #47
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
Exemple #48
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())

        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:
                    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:
                                        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 int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]:
                                try:
                                    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:
                    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:
                    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
                            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:
                    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}
class GeometryHighlightItem(QgsMapCanvasItem):
    # Code ported from QGIS QgsHighlight

    def __init__(self, mapCanvas, geometry, layer):
        super(GeometryHighlightItem, self).__init__(mapCanvas)

        self._mapCanvas = None  # QgsMapCanvas
        self._geometry = None  # QgsGeometry()
        self._brush = QBrush()
        self._pen = QPen()

        self._mapCanvas = mapCanvas
        if not geometry or not isinstance(geometry,
                                          QgsGeometry) or geometry.isEmpty(
                                          ) or not geometry.isGeosValid():
            return
        self._geometry = QgsGeometry(geometry)  # Force deep copy
        self.setLineColor(Application.highlightLineColor())
        self.setFillColor(Application.highlightFillColor())
        if (layer and self._mapCanvas.mapSettings().hasCrsTransformEnabled()):
            ct = self._mapCanvas.mapSettings().layerTransform(layer)
            if ct:
                self._geometry.transform(ct)
        self.updateRect()
        self.update()

    def remove(self):
        self._mapCanvas.scene().removeItem(self)

    def setLineWidth(self, width):
        self._pen.setWidth(width)

    def setLineColor(self, color):
        lineColor = QColor(color)
        lineColor.setAlpha(255)
        self._pen.setColor(lineColor)

    def setFillColor(self, fillColor):
        self._brush.setColor(fillColor)
        self._brush.setStyle(Qt.SolidPattern)

    def updatePosition(self):
        pass

    # protected:
    def paint(self, painter, option=None, widget=None):  # Override
        if not self._geometry:
            return

        painter.setPen(self._pen)
        painter.setBrush(self._brush)

        wkbType = self._geometry.wkbType()
        if wkbType == QGis.WKBPoint or wkbType == QGis.WKBPoint25D:
            self._paintPoint(painter, self._geometry.geometry())
        elif wkbType == QGis.WKBMultiPoint or wkbType == QGis.WKBMultiPoint25D:
            for point in self._geometry.geometry():
                self._paintPoint(painter, point)
        elif wkbType == QGis.WKBLineString or wkbType == QGis.WKBLineString25D:
            self._paintLine(painter, self._geometry.geometry())
        elif wkbType == QGis.WKBMultiLineString or wkbType == QGis.WKBMultiLineString25D:
            for line in self._geometry.geometry():
                self._paintLine(painter, line)
        elif wkbType == QGis.WKBPolygon or wkbType == QGis.WKBPolygon25D:
            self._paintPolygon(painter, self._geometry.geometry())
        elif wkbType == QGis.WKBMultiPolygon or wkbType == QGis.WKBMultiPolygon25D:
            for polygon in self._geometry.geometry():
                self._paintPolygon(painter, polygon)

    def updateRect(self):
        if self._geometry:
            r = self._geometry.boundingBox()
            if r.isEmpty():
                d = self._mapCanvas.extent().width() * 0.005
                r.setXMinimum(r.xMinimum() - d)
                r.setYMinimum(r.yMinimum() - d)
                r.setXMaximum(r.xMaximum() + d)
                r.setYMaximum(r.yMaximum() + d)
            self.setRect(r)
            self.setVisible(True)
        else:
            self.setRect(QgsRectangle())

    # private:

    def _paintPoint(self, painter, point):
        painter.drawEllipse(self.toCanvasCoordinates(point) - self.pos(), 2, 2)

    def _paintLine(self, painter, line):
        polyline = QPolygonF()
        for point in line:
            polyline.append(self.toCanvasCoordinates(point) - self.pos())
        painter.drawPolyline(polyline)

    def _paintPolygon(self, painter, polygon):
        path = QPainterPath()
        for line in polygon:
            ring = QPolygonF()
            for point in line:
                cur = self.toCanvasCoordinates(point) - self.pos()
                ring.append(cur)
            ring.append(ring[0])
            path.addPolygon(ring)
        painter.drawPath(path)