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
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
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)
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
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]
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
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
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
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'))
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)
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
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
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'))
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
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
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
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()
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
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)
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
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)
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)
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
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
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
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
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)