def mergeLines(self, line_a, line_b, layer):
     """
     Merge 2 lines of the same layer (it is assumed that they share the same set od attributes - except for ID and geometry).
     In case sets are different, the set of attributes from line_a will be kept. If geometries don't touch, method is not applicable.
     :param line_a: (QgsFeature) main line of merging process.
     :param line_b: (QgsFeature) line to be merged to line_a.
     :param layer: (QgsVectorLayer) layer containing given lines.
     :return: (bool) True if method runs OK or False, if lines do not touch.
     """
     # check if original layer is a multipart
     isMulti = QgsWKBTypes.isMultiType(int(layer.wkbType()))
     # retrieve lines geometries
     geometry_a = line_a.geometry()
     geometry_b = line_b.geometry()
     # checking the spatial predicate touches
     if geometry_a.touches(geometry_b):
         # this generates a multi geometry
         geometry_a = geometry_a.combine(geometry_b)
         # this make a single line string if the multi geometries are neighbors
         geometry_a = geometry_a.mergeLines()
         if isMulti:
             # making a "single" multi geometry (EDGV standard)
             geometry_a.convertToMultiType()
         # updating feature
         line_a.setGeometry(geometry_a)
         # remove the aggregated line to avoid overlapping
         layer.deleteFeature(line_b.id())
         # updating layer
         layer.updateFeature(line_a)
         return True
     return False
 def getFeatureNodes(self, layer, feature, geomType=None):
     """
     Inverts the flow from a given feature. THE GIVEN FEATURE IS ALTERED. Standard behaviour is to not
     refresh canvas map.
     :param layer: layer containing the target feature for flipping.
     :param feature: feature to be flipped.
     :param geomType: if layer geometry type is not given, it'll calculate it (0,1 or 2).
     :returns: feature as of a list of points (nodes).
     """
     if not geomType:
         geomType = layer.geometryType()
     # getting whether geometry is multipart or not
     isMulti = QgsWKBTypes.isMultiType(int(layer.wkbType()))
     geom = feature.geometry()
     if geomType == 0:
         if isMulti:
             nodes = geom.asMultiPoint()       
         else:
             nodes = geom.asPoint()              
     elif geomType == 1:
         if isMulti:
             nodes = geom.asMultiPolyline()
         else:
             nodes = geom.asPolyline()     
     elif geomType == 2:
         if isMulti:
             nodes = geom.asMultiPolygon()           
         else:
             nodes = geom.asPolygon()
     return nodes
Exemple #3
0
 def getFeatureNodes(self, layer, feature, geomType=None):
     """
     Inverts the flow from a given feature. THE GIVEN FEATURE IS ALTERED. Standard behaviour is to not
     refresh canvas map.
     :param layer: layer containing the target feature for flipping.
     :param feature: feature to be flipped.
     :param geomType: if layer geometry type is not given, it'll calculate it (0,1 or 2).
     :returns: feature as of a list of points (nodes).
     """
     if not geomType:
         geomType = layer.geometryType()
     # getting whether geometry is multipart or not
     isMulti = QgsWKBTypes.isMultiType(int(layer.wkbType()))
     geom = feature.geometry()
     if geomType == 0:
         if isMulti:
             nodes = geom.asMultiPoint()
         else:
             nodes = geom.asPoint()
     elif geomType == 1:
         if isMulti:
             nodes = geom.asMultiPolyline()
         else:
             nodes = geom.asPolyline()
     elif geomType == 2:
         if isMulti:
             nodes = geom.asMultiPolygon()
         else:
             nodes = geom.asPolygon()
     return nodes
Exemple #4
0
    def mergeLines(self, line_a, line_b, layer):
        """
        Merge 2 lines of the same layer (it is assumed that they share the same set od attributes - except for ID and geometry).
        In case sets are different, the set of geometry of line_a will be kept. If geometries don't touch, method is not applicable.
        :param line_a: (QgsFeature) main line of merging process.
        :param line_b: (QgsFeature) line to be merged to line_a.
        :param layer: (QgsVectorLayer) layer containing given lines.
        :return: (bool) True if method runs OK or False, if lines do not touch.
        """
        # check if original layer is a multipart
        isMulti = QgsWKBTypes.isMultiType(int(layer.wkbType()))
        # retrieve lines geometries
        geometry_a = line_a.geometry()
        geometry_b = line_b.geometry()
        # checking the spatial predicate touches
        if geometry_a.touches(geometry_b):
            # this generates a multi geometry
            geometry_a = geometry_a.combine(geometry_b)
            # this make a single line string if the multi geometries are neighbors
            geometry_a = geometry_a.mergeLines()
            if isMulti:
                # making a "single" multi geometry (EDGV standard)
                geometry_a.convertToMultiType()
            # updating feature
            line_a.setGeometry(geometry_a)
            # remove the aggregated line to avoid overlapping
            layer.deleteFeature(line_b.id())
            # updating layer
            layer.updateFeature(line_a)
            return True

        return False
Exemple #5
0
    def __init__(self, table, parent=None):
        TableDataModel.__init__(self, table, parent)

        self.layer = None

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

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

        self.fetchedFrom = 0
        self.fetchedCount = len(self.resdata)
Exemple #6
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())
        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())
                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 #7
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
 def flipFeature(self, layer, feature, geomType=None, refreshCanvas=False):
     """
     Inverts the flow from a given feature. THE GIVEN FEATURE IS ALTERED. Standard behaviour is to not
     refresh canvas map.
     :param layer: layer containing the target feature for flipping.
     :param feature: feature to be flipped.
     :param geomType: if layer geometry type is not given, it'll calculate it (0,1 or 2)
     :param refreshCanvas: indicates whether the canvas should be refreshed after flipping feature.
     :returns: flipped feature as of [layer, feature, geometry_type].
     """
     if not geomType:
         geomType = layer.geometryType()
     # getting whether geometry is multipart or not
     isMulti = QgsWKBTypes.isMultiType(int(layer.wkbType()))
     geom = feature.geometry()
     if geomType == 0:
         if isMulti:
             nodes = geom.asMultiPoint()
             # inverting the point list by parts
             for idx, part in enumerate(nodes):
                 nodes[idx] = part[::-1]
             # setting flipped geometry
             flippedFeatureGeom = QgsGeometry.fromMultiPoint(nodes)                
         else:
             # inverting the point list
             nodes = geom.asPoint()
             nodes = nodes[::-1]
             flippedFeatureGeom = QgsGeometry.fromPoint(nodes)                
     elif geomType == 1:
         if isMulti:
             nodes = geom.asMultiPolyline()
             for idx, part in enumerate(nodes):
                 nodes[idx] = part[::-1]
             flippedFeatureGeom = QgsGeometry.fromMultiPolyline(nodes)
         else:
             nodes = geom.asPolyline()
             nodes = nodes[::-1]
             flippedFeatureGeom = QgsGeometry.fromPolyline(nodes)         
     elif geomType == 2:
         if isMulti:
             nodes = geom.asMultiPolygon()                
             for idx, part in enumerate(nodes):
                 nodes[idx] = part[::-1]
             flippedFeatureGeom = QgsGeometry.fromMultiPolygon(nodes)                
         else:
             nodes = geom.asPolygon()
             nodes = nodes[::-1]
             flippedFeatureGeom = QgsGeometry.fromPolygon(nodes)
     # setting feature geometry to the flipped one
     # feature.setGeometry(flippedFeatureGeom)
     # layer.updateFeature(feature)
     layer.changeGeometry(feature.id(), flippedFeatureGeom)
     if refreshCanvas:
         self.iface.mapCanvas().refresh()
     return [layer, feature, geomType]
Exemple #9
0
 def flipFeature(self, layer, feature, geomType=None, refreshCanvas=False):
     """
     Inverts the flow from a given feature. THE GIVEN FEATURE IS ALTERED. Standard behaviour is to not
     refresh canvas map.
     :param layer: layer containing the target feature for flipping.
     :param feature: feature to be flipped.
     :param geomType: if layer geometry type is not given, it'll calculate it (0,1 or 2)
     :param refreshCanvas: indicates whether the canvas should be refreshed after flipping feature.
     :returns: flipped feature as of [layer, feature, geometry_type].
     """
     if not geomType:
         geomType = layer.geometryType()
     # getting whether geometry is multipart or not
     isMulti = QgsWKBTypes.isMultiType(int(layer.wkbType()))
     geom = feature.geometry()
     if geomType == 0:
         if isMulti:
             nodes = geom.asMultiPoint()
             # inverting the point list by parts
             for idx, part in enumerate(nodes):
                 nodes[idx] = part[::-1]
             # setting flipped geometry
             flippedFeatureGeom = QgsGeometry.fromMultiPoint(nodes)
         else:
             # inverting the point list
             nodes = geom.asPoint()
             nodes = nodes[::-1]
             flippedFeatureGeom = QgsGeometry.fromPoint(nodes)
     elif geomType == 1:
         if isMulti:
             nodes = geom.asMultiPolyline()
             for idx, part in enumerate(nodes):
                 nodes[idx] = part[::-1]
             flippedFeatureGeom = QgsGeometry.fromMultiPolyline(nodes)
         else:
             nodes = geom.asPolyline()
             nodes = nodes[::-1]
             flippedFeatureGeom = QgsGeometry.fromPolyline(nodes)
     elif geomType == 2:
         if isMulti:
             nodes = geom.asMultiPolygon()
             for idx, part in enumerate(nodes):
                 nodes[idx] = part[::-1]
             flippedFeatureGeom = QgsGeometry.fromMultiPolygon(nodes)
         else:
             nodes = geom.asPolygon()
             nodes = nodes[::-1]
             flippedFeatureGeom = QgsGeometry.fromPolygon(nodes)
     # setting feature geometry to the flipped one
     # feature.setGeometry(flippedFeatureGeom)
     # layer.updateFeature(feature)
     layer.changeGeometry(feature.id(), flippedFeatureGeom)
     if refreshCanvas:
         self.iface.mapCanvas().refresh()
     return [layer, feature, geomType]
Exemple #10
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 #11
0
    def processAlgorithm(self, progress):
        layerA = dataobjects.getObjectFromUri(
            self.getParameterValue(Difference.INPUT))
        layerB = dataobjects.getObjectFromUri(
            self.getParameterValue(Difference.OVERLAY))
        ignoreInvalid = self.getParameterValue(Difference.IGNORE_INVALID)

        geomType = QgsWKBTypes.multiType(QGis.fromOldWkbType(layerA.wkbType()))
        writer = self.getOutputFromName(
            Difference.OUTPUT).getVectorWriter(layerA.pendingFields(),
                                               geomType,
                                               layerA.crs())

        outFeat = QgsFeature()
        index = vector.spatialindex(layerB)
        selectionA = vector.features(layerA)
        total = 100.0 / len(selectionA) if len(selectionA) > 0 else 1
        for current, inFeatA in enumerate(selectionA):
            add = True
            geom = QgsGeometry(inFeatA.geometry())
            diff_geom = QgsGeometry(geom)
            attrs = inFeatA.attributes()
            intersections = index.intersects(geom.boundingBox())
            for i in intersections:
                request = QgsFeatureRequest().setFilterFid(i)
                inFeatB = layerB.getFeatures(request).next()
                tmpGeom = QgsGeometry(inFeatB.geometry())
                if diff_geom.intersects(tmpGeom):
                    diff_geom = QgsGeometry(diff_geom.difference(tmpGeom))
                    if diff_geom.isGeosEmpty():
                        ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
                                               self.tr('Feature with NULL geometry found.'))
                    if not diff_geom.isGeosValid():
                        if ignoreInvalid:
                            ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                                   self.tr('GEOS geoprocessing error: One or more input features have invalid geometry.'))
                            add = False
                        else:
                            raise GeoAlgorithmExecutionException(self.tr('Features with invalid geometries found. Please fix these errors or specify the "Ignore invalid input features" flag'))
                        break

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

            progress.setPercentage(int(current * total))

        del writer
    def createUnifiedLineLayer(self, layerList, onlySelected=False):
        """
        For each layer in layerList, transforms it into lines if lyrType 
        is polygon and adds features into layerList.
        Duplicates can happen in this process.
        """
        srid = layerList[0].crs().authid().split(':')[-1]
        coverage = self.iface.addVectorLayer(
            "{0}?crs=epsg:{1}".format('Linestring', srid), "coverage_lines",
            "memory")
        provider = coverage.dataProvider()
        coverage.startEditing()
        coverage.beginEditCommand('Creating coverage lines layer')

        self.localProgress = ProgressWidget(
            1,
            len(layerList) - 1,
            self.tr('Building unified layers with  ') +
            ', '.join([i.name() for i in layerList]) + '.',
            parent=self.iface.mapCanvas())
        addFeatureList = []
        for lyr in layerList:
            isPolygon = True if lyr.dataProvider().geometryType() in [
                QGis.WKBPolygon, QGis.WKBMultiPolygon
            ] else False
            isMulti = QgsWKBTypes.isMultiType(int(lyr.wkbType()))
            featureIterator = lyr.getFeatures(
            ) if not onlySelected else lyr.selectedFeatures()
            for feature in featureIterator:
                geom = feature.geometry()
                if geom:
                    parts = geom.asGeometryCollection()
                    if parts:
                        for part in parts:
                            if isPolygon:
                                linestrings = part.asPolygon()
                                for line in linestrings:
                                    newfeat = QgsFeature(
                                        coverage.pendingFields())
                                    newfeat.setGeometry(
                                        QgsGeometry.fromPolyline(line))
                                    addFeatureList.append(newfeat)
                            else:
                                newfeat = QgsFeature(coverage.pendingFields())
                                newfeat.setGeometry(part)
                                addFeatureList.append(newfeat)
            self.localProgress.step()
        coverage.addFeatures(addFeatureList, True)
        coverage.endEditCommand()
        coverage.commitChanges()
        return coverage
Exemple #13
0
 def identifyAllNodes(self, networkLayer):
     """
     Identifies all nodes from a given layer (or selected features of it). The result is returned as a dict of dict.
     :param networkLayer: target layer to which nodes identification is required.
     :return: { node_id : { start : [feature_which_starts_with_node], end : feature_which_ends_with_node } }.
     """
     nodeDict = dict()
     isMulti = QgsWKBTypes.isMultiType(int(networkLayer.wkbType()))
     if self.parameters['Only Selected']:
         features = networkLayer.selectedFeatures()
     else:
         features = [feat for feat in networkLayer.getFeatures()]
     for feat in features:
         nodes = self.DsgGeometryHandler.getFeatureNodes(networkLayer, feat)
         if nodes:
             if isMulti:
                 if len(nodes) > 1:
                     # if feat is multipart and has more than one part, a flag should be raised
                     continue  # CHANGE TO RAISE FLAG
                 elif len(nodes) == 0:
                     # if no part is found, skip feature
                     continue
                 else:
                     # if feat is multipart, "nodes" is a list of list
                     nodes = nodes[0]
             # initial node
             pInit, pEnd = nodes[0], nodes[-1]
             # filling starting node information into dictionary
             if pInit not in nodeDict:
                 # if the point is not already started into dictionary, it creates a new item
                 nodeDict[pInit] = {'start': [], 'end': []}
             if feat not in nodeDict[pInit]['start']:
                 nodeDict[pInit]['start'].append(feat)
             # filling ending node information into dictionary
             if pEnd not in nodeDict:
                 nodeDict[pEnd] = {'start': [], 'end': []}
             if feat not in nodeDict[pEnd]['end']:
                 nodeDict[pEnd]['end'].append(feat)
     return nodeDict
Exemple #14
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 #15
0
    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)
        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
    def run(self):
        """Run method that performs all the real work"""

        self.remove_result_layers(remove_all=True, delete_source=True)

        layers = self.iface.legendInterface().layers()
        if not layers:
            print_log(
                "Tool afgebroken! Geen layers gevonden. Voeg eerst layers toe",
                "e", self.iface)
            return
        layer_points, layer_lines, layer_polygons = [], [], []
        if b_QgsWKBTypes:
            for i, layer in enumerate(layers):
                if hasattr(layer, "wkbType"):
                    # qgis.core.QgsWKBTypes.displayString(int(vl.wkbType()))
                    if "point" in QgsWKBTypes.displayString(
                            int(layer.wkbType())).lower():  ## QGis.WKBPoint:
                        layer_points.append(layer)
                    elif "line" in QgsWKBTypes.displayString(
                            int(layer.wkbType())).lower(
                            ):  ##QGis.WKBLineString:
                        layer_lines.append(layer)
                    elif "polygon" in QgsWKBTypes.displayString(
                            int(layer.wkbType())).lower():  ##QGis.WKBPolygon:
                        layer_polygons.append(layer)
                    else:
                        pass

        else:
            print_log(
                "ImportError for QgsWKBTypes. Kan geen geometrie herkennen voor layer inputs. \
                        Controleer of juiste layers zijn geselecteerd of upgrade QGIS.",
                "w", self.iface)
            layer_points = layer_lines = layer_polygons = layers

        self.dlg.comboBox_1.clear()
        self.dlg.comboBox_2.clear()
        self.dlg.comboBox_3.clear()
        self.dlg.comboBox_4.clear()
        self.dlg.comboBox_5.clear()
        self.dlg.comboBox_6.clear()
        self.dlg.comboBox_7.clear()
        self.dlg.comboBox_1.addItems([
            i.name() for i in self.move_to_front(layer_points, "punt")
        ])  # knooppunt
        self.dlg.comboBox_2.addItems([
            i.name() for i in self.move_to_front(layer_lines, "lijn")
        ])  # afvoerrelatie
        self.dlg.comboBox_3.addItems([
            i.name() for i in self.move_to_front(layer_points, "BAG")
        ])  # drinkwater BAG
        self.dlg.comboBox_4.addItems(
            [i.name() for i in self.move_to_front(layer_points, "VE")])  # VE's
        self.dlg.comboBox_5.addItems([
            i.name() for i in self.move_to_front(layer_polygons, "RIGO")
        ])  # plancap
        self.dlg.comboBox_6.addItems([
            i.name() for i in self.move_to_front(layer_polygons, "opp")
        ])  # verhard opp
        self.dlg.comboBox_7.addItems([
            i.name() for i in self.move_to_front(layer_polygons, "bemaling")
        ])  # bemalingsgebieden

        # show the dialog
        self.dlg.show()
        # Run the dialog event loop
        result = self.dlg.exec_()
        # See if OK was pressed
        if result:

            ##QgsMessageLog.logMessage("sel_index = {}".format(sel_index, level=QgsMessageLog.INFO))
            ##QgsMessageLog.logMessage("layer_index 4 = {}".format(self.move_to_front(layer_points, "VE")[self.dlg.comboBox_4.currentIndex()].name()), level=QgsMessageLog.INFO)
            ##QgsMessageLog.logMessage("layer4 = {}".format([i.name() for i in l4]), level=QgsMessageLog.INFO)

            sel_layers = [
                self.move_to_front(layer_points,
                                   "punt")[self.dlg.comboBox_1.currentIndex()],
                self.move_to_front(layer_lines,
                                   "lijn")[self.dlg.comboBox_2.currentIndex()],
                self.move_to_front(layer_points,
                                   "BAG")[self.dlg.comboBox_3.currentIndex()],
                self.move_to_front(layer_points,
                                   "VE")[self.dlg.comboBox_4.currentIndex()],
                self.move_to_front(layer_polygons,
                                   "RIGO")[self.dlg.comboBox_5.currentIndex()],
                self.move_to_front(layer_polygons,
                                   "opp")[self.dlg.comboBox_6.currentIndex()],
                self.move_to_front(
                    layer_polygons,
                    "bemaling")[self.dlg.comboBox_7.currentIndex()],
            ]

            # refresh input layers, werkt niet... voorlopig dan maar handmatig weggooien.
            ##sel_layernames = [layer.name() for layer in sel_layers]
            ##self.remove_result_layers(settings.l_result_layers_all)
            ##sel_layers = []
            ##layers = self.iface.legendInterface().layers()
            ##for layer in layers:
            ##    if layer.name() in sel_layernames:
            ##        sel_layers.append(layer)

            gdb = self.dlg.lineEdit.text()
            if not gdb or not os.path.exists(gdb):
                print_log(
                    "Script afgebroken! Geen geldige output map opgegeven ({}...)"
                    .format(gdb), "e", self.iface)
                return

            qgis_warnings_log = settings.qgis_warnings_log
            with open(qgis_warnings_log, 'w') as logfile:
                import time
                logfile.write('{level}: date {time}'.format(
                    level="INFO", time=time.asctime()))

            blokje_log("Veld-info ophalen...", "i")
            INP_FIELDS_XLS = settings.INP_FIELDS_XLS
            INP_FIELDS_CSV = settings.INP_FIELDS_CSV
            try:
                from xlrd import open_workbook
                d_velden = get_d_velden(INP_FIELDS_XLS, 0, open_workbook)
            except ImportError:  # for compatibility with iMac
                print_log(
                    "import error 'xlrd': inp_fields.csv wordt gebruikt als input in plaats van inp_fields.xls!",
                    "w", self.iface)
                d_velden = get_d_velden_csv(INP_FIELDS_CSV)
            for fld in d_velden:
                print_log("{}\n{}".format(fld, d_velden[fld]), "d")

            ##self.iface.messageBar().pushMessage("titel", "Start module 1", QgsMessageBar.INFO, duration=5)
            m1.main(self.iface, sel_layers, gdb, d_velden)
            ##self.iface.messageBar().pushMessage("titel", "Start module 2", QgsMessageBar.INFO, duration=5)
            m2.main(self.iface, sel_layers, gdb, d_velden)

            self.remove_result_layers(remove_all=False, delete_source=False)

            ##self.iface.mainWindow().statusBar().showMessage("dit is de mainWindow")
            warnings = []
            with open(qgis_warnings_log, 'r') as log_file:
                for line in log_file.readlines():
                    if "WARNING" in line:
                        warnings.append(line)

            msg = QMessageBox()
            if len(warnings) > 0:
                msg.setIcon(QMessageBox.Warning)
                msg.setWindowTitle("Script completed")
                msg.setText(
                    "{} warnings were encountered when running script".format(
                        len(warnings)))
                msg.setInformativeText(
                    "For more information see details below or view log panel")
                msg.setDetailedText("The details are as follows:")
                msg.setDetailedText("\n".join(warnings))
                # for line in warnings:
                #     msg.setDetailedText(line)
            else:
                msg.setIcon(QMessageBox.Information)
                msg.setWindowTitle("Script completed")
                msg.setText(
                    "No problems were encountered when running script!")
            retval = msg.exec_()
            ##QMessageBox.information(msg, "Info", "Script completed!")
            QgsMessageLog.logMessage("Script completed!",
                                     level=QgsMessageLog.INFO)
Exemple #17
0
    def processAlgorithm(self, progress):
        source_layer = dataobjects.getObjectFromUri(
            self.getParameterValue(Clip.INPUT))
        mask_layer = dataobjects.getObjectFromUri(
            self.getParameterValue(Clip.OVERLAY))

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            source_layer.fields(),
            QgsWKBTypes.multiType(QGis.fromOldWkbType(source_layer.wkbType())),
            source_layer.crs())

        # first build up a list of clip geometries
        clip_geoms = []
        for maskFeat in vector.features(mask_layer, QgsFeatureRequest().setSubsetOfAttributes([])):
            clip_geoms.append(QgsGeometry(maskFeat.constGeometry()))

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

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

        tested_feature_ids = set()

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

            if not input_features:
                continue

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

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

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

                tested_feature_ids.add(in_feat.id())

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

                if not engine.contains(in_feat.constGeometry().geometry()):
                    cur_geom = QgsGeometry(in_feat.constGeometry())
                    new_geom = combined_clip_geom.intersection(cur_geom)
                    if new_geom.wkbType() == QGis.WKBUnknown or QgsWKBTypes.flatType(new_geom.geometry().wkbType()) == QgsWKBTypes.GeometryCollection:
                        int_com = in_feat.constGeometry().combine(new_geom)
                        int_sym = in_feat.constGeometry().symDifference(new_geom)
                        if not int_com or not int_sym:
                            ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                                   self.tr('GEOS geoprocessing error: One or more '
                                                           'input features have invalid geometry.'))
                        else:
                            new_geom = 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.'))
                else:
                    # clip geometry totally contains feature geometry, so no need to perform intersection
                    new_geom = QgsGeometry(in_feat.constGeometry())

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

                if single_clip_feature:
                    progress.setPercentage(int(current * total))

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

        del writer
Exemple #18
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 #19
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 #20
0
def clip(layer_to_clip, mask_layer, callback=None):
    """Clip a vector layer with another.

    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/Clip.py

    :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 = clip_steps['output_layer_name']
    output_layer_name = output_layer_name % (
        layer_to_clip.keywords['layer_purpose'])
    processing_step = 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()

    # 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.

    # first build up a list of clip geometries
    clip_geometries = []
    request = QgsFeatureRequest().setSubsetOfAttributes([])
    for mask_feature in mask_layer.getFeatures(request):
        clip_geometries.append(QgsGeometry(mask_feature.geometry()))

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

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

    tested_feature_ids = set()

    for i, clip_geom in enumerate(clip_geometries):
        request = QgsFeatureRequest().setFilterRect(clip_geom.boundingBox())
        input_features = [f for f in layer_to_clip.getFeatures(request)]

        if not input_features:
            continue

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

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

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

            tested_feature_ids.add(in_feat.id())

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

            if not engine.contains(in_feat.geometry().geometry()):
                cur_geom = in_feat.geometry()
                new_geom = combined_clip_geom.intersection(cur_geom)
                if new_geom.wkbType() == QgsWKBTypes.Unknown \
                        or QgsWKBTypes.flatType(
                            new_geom.geometry().wkbType()) == \
                                QgsWKBTypes.GeometryCollection:
                    int_com = in_feat.geometry().combine(new_geom)
                    int_sym = in_feat.geometry().symDifference(new_geom)
                    if not int_com or not int_sym:
                        # LOGGER.debug(
                        #     tr('GEOS geoprocessing error: One or more input '
                        #        'features have invalid geometry.'))
                        pass
                    else:
                        new_geom = int_com.difference(int_sym)
                        if new_geom.isGeosEmpty()\
                                or not new_geom.isGeosValid():
                            # LOGGER.debug(
                            #     tr('GEOS geoprocessing error: One or more '
                            #        'input features have invalid geometry.'))
                            pass
            else:
                # clip geometry totally contains feature geometry,
                # so no need to perform intersection
                new_geom = in_feat.geometry()

            try:
                out_feat = QgsFeature()
                out_feat.setGeometry(new_geom)
                out_feat.setAttributes(in_feat.attributes())
                if new_geom.type() == layer_to_clip.geometryType():
                    writer.addFeature(out_feat)
            except:
                LOGGER.debug(
                    tr('Feature geometry error: One or more output features '
                       'ignored due to invalid geometry.'))
                continue

            # TODO implement callback
            if single_clip_feature:
                # progress.setPercentage(int(current * total))
                pass

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

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

    writer.keywords = layer_to_clip.keywords.copy()
    writer.keywords['title'] = output_layer_name
    check_layer(writer)
    return writer
Exemple #21
0
    def processAlgorithm(self, progress):
        layerA = dataobjects.getObjectFromUri(
            self.getParameterValue(Difference.INPUT))
        layerB = dataobjects.getObjectFromUri(
            self.getParameterValue(Difference.OVERLAY))
        ignoreInvalid = self.getParameterValue(Difference.IGNORE_INVALID)

        geomType = QgsWKBTypes.multiType(QGis.fromOldWkbType(layerA.wkbType()))
        writer = self.getOutputFromName(Difference.OUTPUT).getVectorWriter(
            layerA.pendingFields(), geomType, layerA.crs())

        outFeat = QgsFeature()
        index = vector.spatialindex(layerB)
        selectionA = vector.features(layerA)
        total = 100.0 / len(selectionA)
        for current, inFeatA in enumerate(selectionA):
            add = True
            geom = QgsGeometry(inFeatA.geometry())
            diff_geom = QgsGeometry(geom)
            attrs = inFeatA.attributes()
            intersections = index.intersects(geom.boundingBox())
            for i in intersections:
                request = QgsFeatureRequest().setFilterFid(i)
                inFeatB = layerB.getFeatures(request).next()
                tmpGeom = QgsGeometry(inFeatB.geometry())
                if diff_geom.intersects(tmpGeom):
                    diff_geom = QgsGeometry(diff_geom.difference(tmpGeom))
                    if diff_geom.isGeosEmpty():
                        ProcessingLog.addToLog(
                            ProcessingLog.LOG_INFO,
                            self.tr('Feature with NULL geometry found.'))
                    if not diff_geom.isGeosValid():
                        if ignoreInvalid:
                            ProcessingLog.addToLog(
                                ProcessingLog.LOG_ERROR,
                                self.
                                tr('GEOS geoprocessing error: One or more input features have invalid geometry.'
                                   ))
                            add = False
                        else:
                            raise GeoAlgorithmExecutionException(
                                self.
                                tr('Features with invalid geometries found. Please fix these errors or specify the "Ignore invalid input features" flag'
                                   ))
                        break

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

            progress.setPercentage(int(current * total))

        del writer
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
    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 #24
0
 def checkIfLineIsDisconnected(self,
                               node,
                               networkLayer,
                               nodeTypeDict,
                               geomType=None):
     """
     Checks whether a waterway beginning node connected to a line disconnected from network.
     :param node: (QgsPoint) point to be classified.
     :param networkLayer: (QgsVectorLayer) network lines layer.
     :param nodeTypeDict: (dict) all current classified nodes and theirs types.
     :param geomType: (int) network layer geometry type code.
     :return: (bool) whether node is connected to a disconnected line 
     """
     if not nodeTypeDict:
         # if there are no classified nodes, method is ineffective
         return False
     # if a line is disconnected from network, then the other end of the line would have to be classified as a waterway beginning as well
     if not geomType:
         geomType = networkLayer.geometryType()
     nextNodes = []
     # to reduce calculation time
     nodePointDict = self.nodeDict[node]
     isMulti = QgsWKBTypes.isMultiType(int(networkLayer.wkbType()))
     # get all other nodes connected to lines connected to "node"
     lines = nodePointDict['start'] + nodePointDict['end']
     if len(lines) > 1:
         # if there is at least one more line connected to node, line is not disconnected
         return False
     # get line nodes
     n = self.DsgGeometryHandler.getFeatureNodes(layer=networkLayer,
                                                 feature=lines[0],
                                                 geomType=geomType)
     if nodePointDict['start']:
         # if line starts at target node, the other extremity is a final node
         if isMulti:
             if n:
                 n = n[0][-1]
         elif n:
             n = n[-1]
     elif nodePointDict['end']:
         # if line starts at target node, the other extremity is a initial node
         if isMulti:
             if n:
                 n = n[0][0]
         elif n:
             n = n[0]
     # if next node is not among the valid ending lines, it may still be connected to a disconnected line if it is a dangle
     # validEnds = [CreateNetworkNodesProcess.Sink, CreateNetworkNodesProcess.DownHillNode, CreateNetworkNodesProcess.NodeNextToWaterBody]
     if n in nodeTypeDict:
         # if both ends are classified as waterway beginning, then both ends are 1st order dangles and line is disconnected.
         return nodeTypeDict[n] in [
             CreateNetworkNodesProcess.WaterwayBegin,
             CreateNetworkNodesProcess.DownHillNode,
             CreateNetworkNodesProcess.UpHillNode,
             CreateNetworkNodesProcess.NodeNextToWaterBody
         ]
         # if nodeTypeDict[n] not in validEnds:
         #     if self.isFirstOrderDangle(node=n, networkLayer=networkLayer, searchRadius=self.parameters[self.tr('Search Radius')]):
         #         # if next node is not a valid network ending node and is a dangle, line is disconnected from network
         #         return False
         #     return True
     # in case next node is not yet classified, method is ineffective
     return False
 def updateOriginalLayerV2(self,
                           pgInputLayer,
                           qgisOutputVector,
                           featureList=None,
                           featureTupleList=None,
                           deleteFeatures=True):
     """
     Updates the original layer using the grass output layer
     pgInputLyr: postgis input layer
     qgisOutputVector: qgis output layer
     Speed up tips: http://nyalldawson.net/2016/10/speeding-up-your-pyqgis-scripts/
     1- Make pgIdList, by querying it with flag QgsFeatureRequest.NoGeometry
     2- Build output dict
     3- Perform operation
     """
     provider = pgInputLayer.dataProvider()
     # getting keyColumn because we want to be generic
     uri = QgsDataSourceURI(pgInputLayer.dataProvider().dataSourceUri())
     keyColumn = uri.keyColumn()
     # starting edition mode
     pgInputLayer.startEditing()
     pgInputLayer.beginEditCommand('Updating layer')
     addList = []
     idsToRemove = []
     inputDict = dict()
     #this is done to work generically with output layers that are implemented different from ours
     isMulti = QgsWKBTypes.isMultiType(int(pgInputLayer.wkbType()))  #
     #making the changes and inserts
     #this request only takes ids to build inputDict
     request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry)
     for feature in pgInputLayer.getFeatures(request):
         inputDict[feature.id()] = dict()
         inputDict[feature.id()]['featList'] = []
         inputDict[feature.id()]['featWithoutGeom'] = feature
     inputDictKeys = inputDict.keys()
     if qgisOutputVector:
         for feat in qgisOutputVector.dataProvider().getFeatures():
             if keyColumn == '':
                 featid = feat.id()
             else:
                 featid = feat[keyColumn]
             if featid in inputDictKeys:  #verificar quando keyColumn = ''
                 inputDict[featid]['featList'].append(feat)
     elif featureTupleList:
         for gfid, gf in featureTupleList:
             if gfid in inputDictKeys and gf[
                     'classname'] == pgInputLayer.name():
                 inputDict[gfid]['featList'].append(gf)
     else:
         for feat in featureList:
             if keyColumn == '':
                 featid = feat.id()
             else:
                 featid = feat[keyColumn]
             if featid in inputDictKeys:
                 inputDict[featid]['featList'].append(feat)
     #finally, do what must be done
     for id in inputDictKeys:
         outFeats = inputDict[id]['featList']
         #starting to make changes
         for i in range(len(outFeats)):
             if i == 0:
                 #let's update this feature
                 newGeom = outFeats[i].geometry()
                 if newGeom:
                     if isMulti:
                         newGeom.convertToMultiType()
                     pgInputLayer.changeGeometry(
                         id, newGeom)  #It is faster according to the api
                 else:
                     if id not in idsToRemove:
                         idsToRemove.append(id)
             else:
                 #for the rest, let's add them
                 newFeat = QgsFeature(inputDict[id]['featWithoutGeom'])
                 newGeom = outFeats[i].geometry()
                 if newGeom:
                     if isMulti and newGeom:
                         newGeom.convertToMultiType()
                     newFeat.setGeometry(newGeom)
                     if keyColumn != '':
                         idx = newFeat.fieldNameIndex(keyColumn)
                         newFeat.setAttribute(idx,
                                              provider.defaultValue(idx))
                     addList.append(newFeat)
                 else:
                     if id not in idsToRemove:
                         idsToRemove.append(id)
         #in the case we don't find features in the output we should mark them to be removed
         if len(outFeats) == 0 and deleteFeatures:
             idsToRemove.append(id)
     #pushing the changes into the edit buffer
     pgInputLayer.addFeatures(addList, True)
     #removing features from the layer.
     pgInputLayer.deleteFeatures(idsToRemove)
     pgInputLayer.endEditCommand()
Exemple #26
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 #27
0
    def __createCtrlLayers(self, requete):
        """
        Création des couches de contrôles
        - selon une requête SQL dans la base de données (choix  ou des contrôle par l'utilisateur)
        - selon une zone géographique définie par l'utilisateur
        :param requete: liste des requêtes
        """

        self.__iface.messageBar().clearWidgets()
        progressMessageBar = self.__iface.messageBar()
        # ajout d'une barre de progression pour voir le chargement progressif des couches
        progress = QProgressBar()
        progress.setMaximum(100)
        progressMessageBar.pushWidget(progress)

        # récupérer la géométrie définie par l'utilisateur pour l'utiliser dans les requêtes SQL
        # conversion en géométrie binaire et dans le bon système de coordonnée)
        self.__crs = self.__iface.mapCanvas().mapSettings().destinationCrs(
        ).postgisSrid()
        # défintion du système de coordonnées en sortie (par défaut 21781), récupérer des paramètres du projets
        bbox = "(SELECT ST_GeomFromText('" + self.geom.exportToWkt(
        ) + "'," + str(self.__crs) + "))"

        # paramètres de la source des couches à ajouter au projet
        uri = QgsDataSourceURI()
        uri.setConnection(self.__db.hostName(), str(self.__db.port()),
                          self.__db.databaseName(), self.__db.userName(),
                          self.__db.password())
        uri.setSrid(str(self.__crs))
        outputLayers = [
        ]  # listes des couches de résultats à charger dans le projet
        styleLayers = []  # listes des styles de couches (fichier qml)
        i = 0
        totalError = 0  # décompte des erreurs détectées (nombre d'objets dans chaque couche)
        for name in requete:
            for q in self.__layerCfgControl.getFeatures(
                    QgsFeatureRequest(int(name))):
                query_fct = q["sql_function"]
                query_fct = query_fct.replace("bbox", bbox)
                geom_type = QgsWKBTypes.parseType(q["geom_type"])
                # récupérer le type de géométrie QGIS "QgsWKBTypes" depuis un type de géométrie WKT Postgis
                uri.setWkbType(geom_type)
                uri.setDataSource('', query_fct, q["geom_name"], "",
                                  q["key_attribute"])
                layer = QgsVectorLayer(uri.uri(), q["layer_name"], "postgres")

                totalError = totalError + layer.featureCount()
                if layer.featureCount() > 0:
                    outputLayers.append(layer)
                    styleLayers.append(str(q["layer_style"]))
            percent = (
                float(i + 1.0) / float(len(requete))
            ) * 100  # Faire évoluer la barre de progression du traitement
            progress.setValue(percent)
            i += 1
        if len(outputLayers) > 0:
            self.__addCtrlLayers(outputLayers, styleLayers)
            self.__iface.messageBar().clearWidgets()
            self.__iface.messageBar().pushMessage(
                "Info",
                QCoreApplication.translate(
                    "VDLTools",
                    "All layers have been charged with success in the projet. |"
                ) + QCoreApplication.translate("VDLTools", "Total errors : ") +
                str(totalError),
                level=QgsMessageBar.INFO,
                duration=10)
        else:
            self.__iface.messageBar().clearWidgets()
            self.__iface.messageBar().pushMessage(
                "Info",
                QCoreApplication.translate(
                    "VDLTools",
                    "Good !! No error detected on the defined area"),
                level=QgsMessageBar.INFO,
                duration=5)
    def run(self):
        """Run method that performs all the real work"""

        self.remove_result_layers(remove_all=True, delete_source=True)

        layers = self.iface.legendInterface().layers()
        if not layers:
            print_log(
                "Tool afgebroken! Geen layers gevonden. Voeg eerst layers toe",
                "e", self.iface)
            return
        layer_points, layer_lines, layer_polygons = [], [], []

        if b_QgsWKBTypes:
            for i, layer in enumerate(layers):
                if hasattr(layer, "wkbType"):
                    # qgis.core.QgsWKBTypes.displayString(int(vl.wkbType()))
                    if "point" in QgsWKBTypes.displayString(
                            int(layer.wkbType())).lower():  ## QGis.WKBPoint:
                        layer_points.append(layer)
                    elif "line" in QgsWKBTypes.displayString(
                            int(layer.wkbType())).lower(
                            ):  ##QGis.WKBLineString:
                        layer_lines.append(layer)
                    elif "polygon" in QgsWKBTypes.displayString(
                            int(layer.wkbType())).lower():  ##QGis.WKBPolygon:
                        layer_polygons.append(layer)
                    else:
                        pass
            layer_1 = layer_points[:]  # more on slicing: https://www.afternerd.com/blog/python-copy-list/
            layer_2 = layer_lines[:]
            layer_3 = layer_points[:]
            layer_4 = layer_points[:]
            layer_5 = layer_polygons[:]
            layer_6 = layer_polygons[:]
            layer_7 = layer_polygons[:]

        else:
            print_log(
                "ImportError for QgsWKBTypes. Kan geen geometrie herkennen voor layer inputs. \
                        Controleer of juiste layers zijn geselecteerd of upgrade QGIS.",
                "w", self.iface)
            layer_points = layer_lines = layer_polygons = layers
            layer_1 = layers[:]
            layer_2 = layers[:]
            layer_3 = layers[:]
            layer_4 = layers[:]
            layer_5 = layers[:]
            layer_6 = layers[:]
            layer_7 = layers[:]

        layer_1 = self.move_to_front(layer_1, keyword_1)
        layer_2 = self.move_to_front(layer_2, keyword_2)
        layer_3 = self.move_to_front(layer_3, keyword_3)
        layer_4 = self.move_to_front(layer_4, keyword_4)
        layer_5 = self.move_to_front(layer_5, keyword_5)
        layer_6 = self.move_to_front(layer_6, keyword_6)
        layer_7 = self.move_to_front(layer_7, keyword_7)

        self.dlg.comboBox_1.clear()
        self.dlg.comboBox_2.clear()
        self.dlg.comboBox_3.clear()
        self.dlg.comboBox_4.clear()
        self.dlg.comboBox_5.clear()
        self.dlg.comboBox_6.clear()
        self.dlg.comboBox_7.clear()
        self.dlg.comboBox_1.addItems([i.name() for i in layer_1])  # knooppunt
        self.dlg.comboBox_2.addItems([i.name()
                                      for i in layer_2])  # afvoerrelatie
        self.dlg.comboBox_3.addItems([i.name()
                                      for i in layer_3])  # drinkwater BAG
        self.dlg.comboBox_4.addItems([i.name() for i in layer_4])  # VE's
        self.dlg.comboBox_5.addItems([i.name() for i in layer_5])  # plancap
        self.dlg.comboBox_6.addItems([i.name()
                                      for i in layer_6])  # verhard opp
        self.dlg.comboBox_7.addItems([i.name()
                                      for i in layer_7])  # bemalingsgebieden
        msg_tooltip = "Kaartlagen met '{}' in naam komen bovenaan de keuzelijst te staan.\
            \nVoor het instellen van een eigen zoekterm: ga naar local_settings.py in de app directory van de plugin."

        self.dlg.comboBox_1.setToolTip(msg_tooltip.format(keyword_1))
        self.dlg.comboBox_2.setToolTip(msg_tooltip.format(keyword_2))
        self.dlg.comboBox_3.setToolTip(msg_tooltip.format(keyword_3))
        self.dlg.comboBox_4.setToolTip(msg_tooltip.format(keyword_4))
        self.dlg.comboBox_5.setToolTip(msg_tooltip.format(keyword_5))
        self.dlg.comboBox_6.setToolTip(msg_tooltip.format(keyword_6))
        self.dlg.comboBox_7.setToolTip(msg_tooltip.format(keyword_7))

        # show the dialog
        self.dlg.show()
        # Run the dialog event loop
        result = self.dlg.exec_()
        # See if OK was pressed
        if result:

            ##QgsMessageLog.logMessage("sel_index = {}".format(sel_index, level=QgsMessageLog.INFO))
            ##QgsMessageLog.logMessage("layer_index 4 = {}".format(self.move_to_front(layer_points, "VE")[self.dlg.comboBox_4.currentIndex()].name()), level=QgsMessageLog.INFO)
            ##QgsMessageLog.logMessage("layer4 = {}".format([i.name() for i in l4]), level=QgsMessageLog.INFO)

            sel_layers = [
                layer_1[self.dlg.comboBox_1.currentIndex()],
                layer_2[self.dlg.comboBox_2.currentIndex()],
                layer_3[self.dlg.comboBox_3.currentIndex()],
                layer_4[self.dlg.comboBox_4.currentIndex()],
                layer_5[self.dlg.comboBox_5.currentIndex()],
                layer_6[self.dlg.comboBox_6.currentIndex()],
                layer_7[self.dlg.comboBox_7.currentIndex()],
            ]

            for i, layer in enumerate(sel_layers):
                print_log("input {}:\t{}".format(i + 1, layer.name()), "i")

            gdb = self.dlg.lineEdit.text()  #
            if not gdb or not os.path.exists(gdb):
                print_log(
                    "Script afgebroken! Geen geldige output map opgegeven ({}...)"
                    .format(gdb), "e", self.iface)
                return

            qgis_warnings_log = settings.qgis_warnings_log
            with open(qgis_warnings_log, 'w') as logfile:
                import time
                logfile.write('{level}: date {time}'.format(
                    level="INFO", time=time.asctime()))

            blokje_log("Veld-info ophalen...", "i")
            INP_FIELDS_XLS = settings.INP_FIELDS_XLS
            INP_FIELDS_CSV = settings.INP_FIELDS_CSV
            try:
                if settings.b_raise_xlrd_import_error:
                    print_log(
                        "b_raise_xlrd_import_error = True (zie local_settings.py)",
                        "w", self.iface)
                    raise ImportError  # for testing csv
                from xlrd import open_workbook
                d_velden = get_d_velden(INP_FIELDS_XLS, 0, open_workbook)
            except ImportError:  # for compatibility with iMac
                print_log(
                    "import error 'xlrd': inp_fields.csv wordt gebruikt als input in plaats van inp_fields.xls",
                    "w", self.iface)
                d_velden = get_d_velden_csv(INP_FIELDS_CSV)
            for fld in d_velden:
                print_log("{}\n{}".format(fld, d_velden[fld]), "d")

            # check for required fields
            vl = sel_layers[0]  # knooppunt
            if vl.fieldNameIndex('VAN_KNOOPN') == -1:
                print_log(
                    "Script afgebroken! Verplicht veld 'VAN_KNOOPN' niet gevonden in kaartlaag '{}'"
                    .format(vl.name()), "e", self.iface)
                return
            vl = sel_layers[1]  # afvoerrelatie
            if vl.fieldNameIndex('VAN_KNOOPN') == -1:
                print_log(
                    "Script afgebroken! Verplicht veld 'VAN_KNOOPN' niet gevonden in kaartlaag '{}'"
                    .format(vl.name()), "e", self.iface)
                return

            # run module 1
            l_K_ONTV_VAN, inp_polygon_layer = m1.main(self.iface, sel_layers,
                                                      gdb, d_velden)

            # run module 2
            m2.main(self.iface, sel_layers, gdb, d_velden, l_K_ONTV_VAN,
                    inp_polygon_layer)

            if settings.b_remove_results_after_run:
                self.remove_result_layers(remove_all=False,
                                          delete_source=False)

            ##self.iface.mainWindow().statusBar().showMessage("dit is de mainWindow")
            warnings = []
            with open(qgis_warnings_log, 'r') as log_file:
                for line in log_file.readlines():
                    if "WARNING" in line:
                        warnings.append(line)

            msg = QMessageBox()
            if len(warnings) > 0:
                msg.setIcon(QMessageBox.Warning)
                msg.setWindowTitle("Script completed")
                msg.setText(
                    "{} warnings were encountered when running script".format(
                        len(warnings)))
                msg.setInformativeText(
                    "For more information see details below or view log panel")
                detailedText = "The details are as follows:"
                detailedText += "\n" + "".join(warnings)
                detailedText += "\nlogfile: {}".format(settings.logFile)
                msg.setDetailedText(detailedText)
                msg.setStyleSheet("QLabel{min-width: 300px;}")
            else:
                msg.setIcon(QMessageBox.Information)
                msg.setWindowTitle("Script completed")
                msg.setText(
                    "No problems were encountered when running script!")
            retval = msg.exec_()
            ##QMessageBox.information(msg, "Info", "Script completed!")
            QgsMessageLog.logMessage("Script completed!",
                                     level=QgsMessageLog.INFO)
Exemple #29
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()
        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 #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 reclassify(self):
     """
     Performs the actual reclassification, moving the geometry to the correct layer along with the specified attributes
     """
     if not self.checkConditions():
         return
     
     somethingMade = False
     reclassifiedFeatures = 0
     
     #button that sent the signal
     self.buttonName = self.sender().text()
     (reclassificationLayer, self.category, self.edgvClass) = self.getLayerFromButton(self.buttonName)
     geomType = reclassificationLayer.geometryType()
     hasMValues =  QgsWKBTypes.hasM(int(reclassificationLayer.wkbType()))    #generic check (not every database is implemented as ours)
     hasZValues =  QgsWKBTypes.hasZ(int(reclassificationLayer.wkbType()))    #
     isMulti = QgsWKBTypes.isMultiType(int(reclassificationLayer.wkbType())) #
     mapLayers = self.iface.mapCanvas().layers()
     crsSrc = QgsCoordinateReferenceSystem(self.widget.crs.authid())
     deleteList = []
     for mapLayer in mapLayers:
         if mapLayer.type() != QgsMapLayer.VectorLayer:
             continue
         
         #iterating over selected features
         featList = []
         mapLayerCrs = mapLayer.crs()
         #creating a coordinate transformer (mapLayerCrs to crsSrc)
         coordinateTransformer = QgsCoordinateTransform(mapLayerCrs, crsSrc)
         for feature in mapLayer.selectedFeatures():
             geomList = []
             geom = feature.geometry()
             if geom.type() != geomType:
                 continue
             if 'geometry' in dir(geom):
                 if not hasMValues:
                     geom.geometry().dropMValue()
                 if not hasZValues:
                     geom.geometry().dropZValue()
             if isMulti and not geom.isMultipart():
                 geom.convertToMultiType()
                 geomList.append(geom)
             elif not isMulti and geom.isMultipart():
                 #deaggregate here
                 parts = geom.asGeometryCollection()
                 for part in parts:
                     part.convertToSingleType()
                     geomList.append(part)
             else:
                 geomList.append(geom)
             for newGeom in geomList:
                 #creating a new feature according to the reclassification layer
                 newFeature = QgsFeature(reclassificationLayer.pendingFields())
                 #transforming the geometry to the correct crs
                 geom.transform(coordinateTransformer)
                 #setting the geometry
                 newFeature.setGeometry(newGeom)
                 #setting the attributes using the reclassification dictionary
                 newFeature = self.setFeatureAttributes(newFeature)
                 #adding the newly created feature to the addition list
                 featList.append(newFeature)
                 somethingMade = True
                 deleteList.append({'originalLyr':mapLayer,'featid':feature.id()})
         #actual feature insertion
         reclassificationLayer.addFeatures(featList, False)
         reclassifiedFeatures += len(featList)
     
     for item in deleteList:
         item['originalLyr'].startEditing()
         item['originalLyr'].deleteFeature(item['featid'])
     
     if somethingMade:
         self.iface.messageBar().pushMessage(self.tr('Information!'), self.tr('{} features reclassified with success!').format(reclassifiedFeatures), level=QgsMessageBar.INFO, duration=3)
Exemple #32
0
    def testWriteShapefileWithZ(self):
        """Check writing geometries with Z dimension to an ESRI shapefile."""

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

        assert ml is not None, 'Provider not initialized'
        assert ml.isValid(), 'Source layer not valid'
        provider = ml.dataProvider()
        assert provider is not None

        ft = QgsFeature()
        ft.setGeometry(QgsGeometry.fromWkt('PointZ (1 2 3)'))
        ft.setAttributes([1])
        res, features = provider.addFeatures([ft])
        assert res
        assert len(features) > 0

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

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

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

            # Open result and check
            created_layer_from_shp = QgsVectorLayer(u'{}|layerid=0'.format(dest_file_name), u'test', u'ogr')
            f = next(created_layer_from_shp.getFeatures(QgsFeatureRequest()))
            g = f.geometry()
            wkt = g.exportToWkt()
            assert compareWkt(expWkt, wkt), "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt)
Exemple #33
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 has unsupported geometry type {}').format(
                    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 #34
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']  # NOQA
    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())

    # nFeat = len(union_b.getFeatures())
    for in_feat_a in union_b.getFeatures():
        # progress.setPercentage(nElement / float(nFeat) * 100)
        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()
            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 #35
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
    def testWriteShapefileWithZ(self):
        """Check writing geometries with Z dimension to an ESRI shapefile."""

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

        assert ml is not None, 'Provider not initialized'
        assert ml.isValid(), 'Source layer not valid'
        provider = ml.dataProvider()
        assert provider is not None

        ft = QgsFeature()
        ft.setGeometry(QgsGeometry.fromWkt('PointZ (1 2 3)'))
        ft.setAttributes([1])
        res, features = provider.addFeatures([ft])
        assert res
        assert len(features) > 0

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

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

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

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

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

        featB = QgsFeature()
        outFeat = QgsFeature()

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

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

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

        for featA in featuresA:
            add = True
            geom = QgsGeometry(featA.geometry())
            diffGeom = QgsGeometry(geom)
            attrs = featA.attributes()
            intersects = indexA.intersects(geom.boundingBox())
            for i in intersects:
                layerB.getFeatures(
                    QgsFeatureRequest().setFilterFid(i)).nextFeature(featB)
                tmpGeom = QgsGeometry(featB.geometry())
                if diffGeom.intersects(tmpGeom):
                    diffGeom = QgsGeometry(diffGeom.difference(tmpGeom))
                    if not diffGeom.isGeosValid():
                        ProcessingLog.addToLog(
                            ProcessingLog.LOG_ERROR,
                            self.tr('GEOS geoprocessing error: One or '
                                    'more input features have invalid '
                                    'geometry.'))
                        add = False
                        break

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

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

        length = len(layerA.fields())

        for featA in featuresB:
            add = True
            geom = QgsGeometry(featA.geometry())
            diffGeom = QgsGeometry(geom)
            attrs = featA.attributes()
            attrs = [NULL] * length + attrs
            intersects = indexB.intersects(geom.boundingBox())
            for i in intersects:
                layerA.getFeatures(
                    QgsFeatureRequest().setFilterFid(i)).nextFeature(featB)
                tmpGeom = QgsGeometry(featB.geometry())
                if diffGeom.intersects(tmpGeom):
                    diffGeom = QgsGeometry(diffGeom.difference(tmpGeom))
                    if not diffGeom.isGeosValid():
                        ProcessingLog.addToLog(
                            ProcessingLog.LOG_ERROR,
                            self.tr('GEOS geoprocessing error: One or '
                                    'more input features have invalid '
                                    'geometry.'))
                        add = False
                        break

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

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

        del writer
Exemple #38
0
def clip(layer_to_clip, mask_layer, callback=None):
    """Clip a vector layer with another.

    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/Clip.py

    :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 = clip_steps['output_layer_name']
    output_layer_name = output_layer_name % (
        layer_to_clip.keywords['layer_purpose'])
    processing_step = 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()

    # 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.

    # first build up a list of clip geometries
    clip_geometries = []
    request = QgsFeatureRequest().setSubsetOfAttributes([])
    for mask_feature in mask_layer.getFeatures(request):
        clip_geometries.append(QgsGeometry(mask_feature.geometry()))

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

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

    tested_feature_ids = set()

    for i, clip_geom in enumerate(clip_geometries):
        request = QgsFeatureRequest().setFilterRect(clip_geom.boundingBox())
        input_features = [f for f in layer_to_clip.getFeatures(request)]

        if not input_features:
            continue

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

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

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

            tested_feature_ids.add(in_feat.id())

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

            if not engine.contains(in_feat.geometry().geometry()):
                cur_geom = in_feat.geometry()
                new_geom = combined_clip_geom.intersection(cur_geom)
                if new_geom.wkbType() == QgsWKBTypes.Unknown \
                        or QgsWKBTypes.flatType(
                            new_geom.geometry().wkbType()) == \
                                QgsWKBTypes.GeometryCollection:
                    int_com = in_feat.geometry().combine(new_geom)
                    int_sym = in_feat.geometry().symDifference(new_geom)
                    if not int_com or not int_sym:
                        # LOGGER.debug(
                        #     tr('GEOS geoprocessing error: One or more input '
                        #        'features have invalid geometry.'))
                        pass
                    else:
                        new_geom = int_com.difference(int_sym)
                        if new_geom.isGeosEmpty()\
                                or not new_geom.isGeosValid():
                            # LOGGER.debug(
                            #     tr('GEOS geoprocessing error: One or more '
                            #        'input features have invalid geometry.'))
                            pass
            else:
                # clip geometry totally contains feature geometry,
                # so no need to perform intersection
                new_geom = in_feat.geometry()

            try:
                out_feat = QgsFeature()
                out_feat.setGeometry(new_geom)
                out_feat.setAttributes(in_feat.attributes())
                writer.addFeature(out_feat)
            except:
                LOGGER.debug(
                    tr('Feature geometry error: One or more output features '
                       'ignored due to invalid geometry.'))
                continue

            # TODO implement callback
            if single_clip_feature:
                # progress.setPercentage(int(current * total))
                pass

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

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

    writer.keywords = layer_to_clip.keywords.copy()
    writer.keywords['title'] = output_layer_name
    check_layer(writer)
    return writer
Exemple #39
0
 def reclassify(self):
     """
     Performs the actual reclassification, moving the geometry to the correct layer along with the specified attributes
     """
     if not self.checkConditions():
         return
     
     somethingMade = False
     reclassifiedFeatures = 0
     
     #button that sent the signal
     self.buttonName = self.sender().text().split(' [')[0]
     (reclassificationLayer, self.category, self.edgvClass) = self.getLayerFromButton(self.buttonName)
     geomType = reclassificationLayer.geometryType()
     hasMValues =  QgsWKBTypes.hasM(int(reclassificationLayer.wkbType()))    #generic check (not every database is implemented as ours)
     hasZValues =  QgsWKBTypes.hasZ(int(reclassificationLayer.wkbType()))    #
     isMulti = QgsWKBTypes.isMultiType(int(reclassificationLayer.wkbType())) #
     mapLayers = self.iface.mapCanvas().layers()
     #we need to get the authid that thefines the ref system of destination layer
     crsSrc = QgsCoordinateReferenceSystem(reclassificationLayer.crs().authid())
     deleteList = []
     for mapLayer in mapLayers:
         if mapLayer.type() != QgsMapLayer.VectorLayer:
             continue
         
         #iterating over selected features
         featList = []
         mapLayerCrs = mapLayer.crs()
         #creating a coordinate transformer (mapLayerCrs to crsSrc)
         coordinateTransformer = QgsCoordinateTransform(mapLayerCrs, crsSrc)
         for feature in mapLayer.selectedFeatures():
             geomList = []
             geom = feature.geometry()
             if geom.type() != geomType:
                 continue
             if 'geometry' in dir(geom):
                 if not hasMValues:
                     geom.geometry().dropMValue()
                 if not hasZValues:
                     geom.geometry().dropZValue()
             if isMulti and not geom.isMultipart():
                 geom.convertToMultiType()
                 geomList.append(geom)
             if not isMulti and geom.isMultipart():
                 #deaggregate here
                 parts = geom.asGeometryCollection()
                 for part in parts:
                     part.convertToSingleType()
                     geomList.append(part)
             else:
                 geomList.append(geom)
             for newGeom in geomList:
                 #creating a new feature according to the reclassification layer
                 newFeature = QgsFeature(reclassificationLayer.pendingFields())
                 #transforming the geometry to the correct crs
                 geom.transform(coordinateTransformer)
                 #setting the geometry
                 newFeature.setGeometry(newGeom)
                 #setting the attributes using the reclassification dictionary
                 newFeature = self.setFeatureAttributes(newFeature, oldFeat = feature)
                 #adding the newly created feature to the addition list
                 featList.append(newFeature)
                 somethingMade = True
                 deleteList.append({'originalLyr':mapLayer,'featid':feature.id()})
         #actual feature insertion
         reclassificationLayer.addFeatures(featList, False)
         reclassifiedFeatures += len(featList)
     
     for item in deleteList:
         item['originalLyr'].startEditing()
         item['originalLyr'].deleteFeature(item['featid'])
     
     if somethingMade:
         self.iface.messageBar().pushMessage(self.tr('Information!'), self.tr('{} features reclassified with success!').format(reclassifiedFeatures), level=QgsMessageBar.INFO, duration=3)