def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) field_name = self.parameterAsString(parameters, self.FIELD, context) geom_type = QgsWkbTypes.multiType(source.wkbType()) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, source.fields(), geom_type, source.sourceCrs()) index = source.fields().lookupField(field_name) collection_geom = {} collection_attrs = {} features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, feature in enumerate(features): if feedback.isCanceled(): break atMap = feature.attributes() idVar = atMap[index] if idVar in [None, NULL] or not feature.hasGeometry(): sink.addFeature(feature, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) continue key = str(idVar).strip() if key not in collection_geom: collection_geom[key] = [] collection_attrs[key] = atMap inGeom = feature.geometry() collection_geom[key].append(inGeom) feedback.setProgress(int(current * total)) for key, geoms in collection_geom.items(): if feedback.isCanceled(): break feature = QgsFeature() feature.setAttributes(collection_attrs[key]) feature.setGeometry(QgsGeometry.collectGeometry(geoms)) sink.addFeature(feature, QgsFeatureSink.FastInsert) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context) fieldName = self.getParameterValue(self.FIELD) geomType = QgsWkbTypes.multiType(layer.wkbType()) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(layer.fields(), geomType, layer.crs(), context) outFeat = QgsFeature() inGeom = QgsGeometry() index = layer.fields().lookupField(fieldName) collection_geom = {} collection_attrs = {} features = QgsProcessingUtils.getFeatures(layer, context) total = 100.0 / layer.featureCount() if layer.featureCount() else 0 for current, feature in enumerate(features): atMap = feature.attributes() idVar = atMap[index] if idVar in [None, NULL]: outFeat.setAttributes(atMap) outFeat.setGeometry(feature.geometry()) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) continue key = str(idVar).strip() if key not in collection_geom: collection_geom[key] = [] collection_attrs[key] = atMap inGeom = feature.geometry() collection_geom[key].append(inGeom) feedback.setProgress(int(current * total)) for key, geoms in collection_geom.items(): outFeat.setAttributes(collection_attrs[key]) outFeat.setGeometry(QgsGeometry.collectGeometry(geoms)) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) del writer
def convertToPolygon(self, geom): if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry and geom.constGet().nCoordinates() < 3: raise QgsProcessingException( self.tr('Cannot convert from Point to Polygon').format(QgsWkbTypes.displayString(geom.wkbType()))) elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry: # multipoint with at least 3 points # TODO: mega inefficient - needs rework when geometry iterators land # (but at least it doesn't lose Z/M values) points = [] for g in geom.constGet().coordinateSequence(): for r in g: for p in r: points.append(p) linestring = QgsLineString(points) linestring.close() p = QgsPolygon() p.setExteriorRing(linestring) return [QgsGeometry(p)] elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.LineGeometry: if QgsWkbTypes.isMultiType(geom): parts = [] for i in range(geom.constGet().numGeometries()): p = QgsPolygon() linestring = geom.constGet().geometryN(i).clone() linestring.close() p.setExteriorRing(linestring) parts.append(QgsGeometry(p)) return QgsGeometry.collectGeometry(parts) else: # linestring to polygon p = QgsPolygon() linestring = geom.constGet().clone() linestring.close() p.setExteriorRing(linestring) return [QgsGeometry(p)] else: #polygon if QgsWkbTypes.isMultiType(geom): return geom.asGeometryCollection() else: return [geom]
def processAlgorithm(self, context, feedback): layer = QgsProcessingUtils.mapLayerFromString( self.getParameterValue(self.INPUT), context) fieldName = self.getParameterValue(self.FIELD) geomType = QgsWkbTypes.multiType(layer.wkbType()) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( layer.fields(), geomType, layer.crs(), context) outFeat = QgsFeature() inGeom = QgsGeometry() index = layer.fields().lookupField(fieldName) collection_geom = {} collection_attrs = {} features = QgsProcessingUtils.getFeatures(layer, context) total = 100.0 / QgsProcessingUtils.featureCount(layer, context) for current, feature in enumerate(features): atMap = feature.attributes() idVar = atMap[index] key = str(idVar).strip() if key not in collection_geom: collection_geom[key] = [] collection_attrs[key] = atMap inGeom = feature.geometry() collection_geom[key].append(inGeom) feedback.setProgress(int(current * total)) for key, geoms in collection_geom.items(): outFeat.setAttributes(collection_attrs[key]) outFeat.setGeometry(QgsGeometry.collectGeometry(geoms)) writer.addFeature(outFeat) del writer
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri(self.getParameterValue( self.INPUT)) fieldName = self.getParameterValue(self.FIELD) geomType = QgsWkbTypes.multiType(layer.wkbType()) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( layer.fields().toList(), geomType, layer.crs()) outFeat = QgsFeature() inGeom = QgsGeometry() index = layer.fields().lookupField(fieldName) collection_geom = {} collection_attrs = {} features = vector.features(layer) total = 100.0 / len(features) for current, feature in enumerate(features): atMap = feature.attributes() idVar = atMap[index] key = str(idVar).strip() if not key in collection_geom: collection_geom[key] = [] collection_attrs[key] = atMap inGeom = feature.geometry() collection_geom[key].append(inGeom) progress.setPercentage(int(current * total)) for key, geoms in collection_geom.items(): outFeat.setAttributes(collection_attrs[key]) outFeat.setGeometry(QgsGeometry.collectGeometry(geoms)) writer.addFeature(outFeat) del writer
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT)) fieldName = self.getParameterValue(self.FIELD) geomType = QgsWkbTypes.multiType(layer.wkbType()) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( layer.fields().toList(), geomType, layer.crs()) outFeat = QgsFeature() inGeom = QgsGeometry() index = layer.fields().lookupField(fieldName) collection_geom = {} collection_attrs = {} features = vector.features(layer) total = 100.0 / len(features) for current, feature in enumerate(features): atMap = feature.attributes() idVar = atMap[index] key = str(idVar).strip() if not key in collection_geom: collection_geom[key] = [] collection_attrs[key] = atMap inGeom = feature.geometry() collection_geom[key].append(inGeom) progress.setPercentage(int(current * total)) for key, geoms in collection_geom.items(): outFeat.setAttributes(collection_attrs[key]) outFeat.setGeometry(QgsGeometry.collectGeometry(geoms)) writer.addFeature(outFeat) del writer
def get_intersection_polygons(self, polygon_layer, polygon_id, overlapping_id): feature_polygon = polygon_layer.getFeature(polygon_id) feature_overlap = polygon_layer.getFeature(overlapping_id) listGeoms = list() intersection = feature_polygon.geometry().intersection( feature_overlap.geometry()) if intersection.type() == QgsWkbTypes.PolygonGeometry: listGeoms.append(intersection) elif intersection.wkbType() in [ QgsWkbTypes.GeometryCollection, QgsWkbTypes.GeometryCollectionM, QgsWkbTypes.GeometryCollectionZ, QgsWkbTypes.GeometryCollectionZM ]: for part in intersection.asGeometryCollection(): if part.type() == QgsWkbTypes.PolygonGeometry: listGeoms.append(part) return QgsGeometry.collectGeometry( listGeoms) if len(listGeoms) > 0 else None
def get_inner_intersections_between_polygons(self, polygon_layer_1, polygon_layer_2): """ Discard intersections other than inner intersections (i.e., only returns polygon intersections) """ ids = list() list_overlapping = list() request = QgsFeatureRequest().setSubsetOfAttributes([]) dict_features = {feature.id(): feature for feature in polygon_layer_2.getFeatures(request)} index = QgsSpatialIndex(polygon_layer_2) candidate_features = None for feature in polygon_layer_1.getFeatures(request): bbox = feature.geometry().boundingBox() candidates_ids = index.intersects(bbox) candidate_features = [dict_features[candidate_id] for candidate_id in candidates_ids] for candidate_feature in candidate_features: candidate_feature_geo = candidate_feature.geometry() if feature.geometry().intersects(candidate_feature_geo) and not feature.geometry().touches(candidate_feature_geo): intersection = feature.geometry().intersection(candidate_feature_geo) if intersection.type() == QgsWkbTypes.PolygonGeometry and intersection.area() > DEFAULT_POLYGON_AREA_TOLERANCE: ids.append([feature.id(), candidate_feature.id()]) list_overlapping.append(intersection) elif intersection.wkbType() in [QgsWkbTypes.GeometryCollection, QgsWkbTypes.GeometryCollectionM, QgsWkbTypes.GeometryCollectionZ, QgsWkbTypes.GeometryCollectionZM]: for part in intersection.asGeometryCollection(): if part.type() == QgsWkbTypes.PolygonGeometry and intersection.area() > DEFAULT_POLYGON_AREA_TOLERANCE: ids.append([feature.id(), candidate_feature.id()]) list_overlapping.append(part) # free up memory del candidate_features del dict_features gc.collect() return ids, QgsGeometry.collectGeometry(list_overlapping) if len(list_overlapping) > 0 else None
def processAlgorithm(self, progress): layerA = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT_A)) splitLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT_B)) sameLayer = self.getParameterValue(self.INPUT_A) == self.getParameterValue(self.INPUT_B) fieldList = layerA.fields() writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fieldList, QgsWkbTypes.multiType(layerA.wkbType()), layerA.crs()) spatialIndex = QgsSpatialIndex() splitGeoms = {} request = QgsFeatureRequest() request.setSubsetOfAttributes([]) for aSplitFeature in vector.features(splitLayer, request): splitGeoms[aSplitFeature.id()] = aSplitFeature.geometry() spatialIndex.insertFeature(aSplitFeature) # honor the case that user has selection on split layer and has setting "use selection" outFeat = QgsFeature() features = vector.features(layerA) if len(features) == 0: total = 100 else: total = 100.0 / float(len(features)) for current, inFeatA in enumerate(features): inGeom = inFeatA.geometry() attrsA = inFeatA.attributes() outFeat.setAttributes(attrsA) if inGeom.isMultipart(): inGeoms = [] for g in inGeom.asGeometryCollection(): inGeoms.append(g) else: inGeoms = [inGeom] lines = spatialIndex.intersects(inGeom.boundingBox()) if len(lines) > 0: # has intersection of bounding boxes splittingLines = [] engine = QgsGeometry.createGeometryEngine(inGeom.geometry()) engine.prepareGeometry() for i in lines: try: splitGeom = splitGeoms[i] except: continue # check if trying to self-intersect if sameLayer: if inFeatA.id() == i: continue if engine.intersects(splitGeom.geometry()): splittingLines.append(splitGeom) if len(splittingLines) > 0: for splitGeom in splittingLines: splitterPList = None outGeoms = [] split_geom_engine = QgsGeometry.createGeometryEngine(splitGeom.geometry()) split_geom_engine.prepareGeometry() while len(inGeoms) > 0: inGeom = inGeoms.pop() if inGeom.isEmpty(): # this has been encountered and created a run-time error continue if split_geom_engine.intersects(inGeom.geometry()): inPoints = vector.extractPoints(inGeom) if splitterPList == None: splitterPList = vector.extractPoints(splitGeom) try: result, newGeometries, topoTestPoints = inGeom.splitGeometry(splitterPList, False) except: ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, self.tr('Geometry exception while splitting')) result = 1 # splitGeometry: If there are several intersections # between geometry and splitLine, only the first one is considered. if result == 0: # split occurred if inPoints == vector.extractPoints(inGeom): # bug in splitGeometry: sometimes it returns 0 but # the geometry is unchanged outGeoms.append(inGeom) else: inGeoms.append(inGeom) for aNewGeom in newGeometries: inGeoms.append(aNewGeom) else: outGeoms.append(inGeom) else: outGeoms.append(inGeom) inGeoms = outGeoms parts = [] for aGeom in inGeoms: passed = True if QgsWkbTypes.geometryType( aGeom.wkbType() ) == QgsWkbTypes.LineGeometry: numPoints = aGeom.geometry().numPoints() if numPoints <= 2: if numPoints == 2: passed = not aGeom.geometry().isClosed() # tests if vertex 0 = vertex 1 else: passed = False # sometimes splitting results in lines of zero length if passed: parts.append(aGeom) if len(parts) > 0: outFeat.setGeometry(QgsGeometry.collectGeometry(parts)) writer.addFeature(outFeat) progress.setPercentage(int(current * total)) del writer
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) line_source = self.parameterAsSource(parameters, self.LINES, context) sameLayer = parameters[self.INPUT] == parameters[self.LINES] (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, source.fields(), QgsWkbTypes.multiType(source.wkbType()), source.sourceCrs()) spatialIndex = QgsSpatialIndex() splitGeoms = {} request = QgsFeatureRequest() request.setSubsetOfAttributes([]) request.setDestinationCrs(source.sourceCrs()) for aSplitFeature in line_source.getFeatures(request): if feedback.isCanceled(): break splitGeoms[aSplitFeature.id()] = aSplitFeature.geometry() spatialIndex.insertFeature(aSplitFeature) # honor the case that user has selection on split layer and has setting "use selection" outFeat = QgsFeature() features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 100 for current, inFeatA in enumerate(features): if feedback.isCanceled(): break inGeom = inFeatA.geometry() attrsA = inFeatA.attributes() outFeat.setAttributes(attrsA) if inGeom.isMultipart(): inGeoms = [] for g in inGeom.asGeometryCollection(): inGeoms.append(g) else: inGeoms = [inGeom] lines = spatialIndex.intersects(inGeom.boundingBox()) if len(lines) > 0: # has intersection of bounding boxes splittingLines = [] engine = QgsGeometry.createGeometryEngine(inGeom.geometry()) engine.prepareGeometry() for i in lines: try: splitGeom = splitGeoms[i] except: continue # check if trying to self-intersect if sameLayer: if inFeatA.id() == i: continue if engine.intersects(splitGeom.geometry()): splittingLines.append(splitGeom) if len(splittingLines) > 0: for splitGeom in splittingLines: splitterPList = None outGeoms = [] split_geom_engine = QgsGeometry.createGeometryEngine(splitGeom.geometry()) split_geom_engine.prepareGeometry() while len(inGeoms) > 0: if feedback.isCanceled(): break inGeom = inGeoms.pop() if inGeom.isNull(): # this has been encountered and created a run-time error continue if split_geom_engine.intersects(inGeom.geometry()): inPoints = vector.extractPoints(inGeom) if splitterPList is None: splitterPList = vector.extractPoints(splitGeom) try: result, newGeometries, topoTestPoints = inGeom.splitGeometry(splitterPList, False) except: feedback.reportError(self.tr('Geometry exception while splitting')) result = 1 # splitGeometry: If there are several intersections # between geometry and splitLine, only the first one is considered. if result == 0: # split occurred if inPoints == vector.extractPoints(inGeom): # bug in splitGeometry: sometimes it returns 0 but # the geometry is unchanged outGeoms.append(inGeom) else: inGeoms.append(inGeom) for aNewGeom in newGeometries: inGeoms.append(aNewGeom) else: outGeoms.append(inGeom) else: outGeoms.append(inGeom) inGeoms = outGeoms parts = [] for aGeom in inGeoms: if feedback.isCanceled(): break passed = True if QgsWkbTypes.geometryType(aGeom.wkbType()) == QgsWkbTypes.LineGeometry: numPoints = aGeom.geometry().numPoints() if numPoints <= 2: if numPoints == 2: passed = not aGeom.geometry().isClosed() # tests if vertex 0 = vertex 1 else: passed = False # sometimes splitting results in lines of zero length if passed: parts.append(aGeom) if len(parts) > 0: outFeat.setGeometry(QgsGeometry.collectGeometry(parts)) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def get_gaps_in_polygon_layer(self, layer, include_roads): """ Find gaps in a continuous layer in space. Ported/adapted to Python from: https://github.com/qgis/QGIS/blob/2c536307476e205b83d86863b903d7ea9d628f0d/src/plugins/topology/topolTest.cpp#L579-L726 """ request = QgsFeatureRequest().setSubsetOfAttributes([]) features = layer.getFeatures(request) featureCollection = list() for feature in features: if feature.geometry().isEmpty(): continue if not feature.geometry().isGeosValid(): continue if feature.geometry().isMultipart() and feature.geometry().type( ) == QgsWkbTypes.PolygonGeometry: for polygon in feature.geometry().asMultiPolygon(): featureCollection.append( QgsGeometry.fromPolygonXY(polygon)) continue featureCollection.append(feature.geometry()) union_geom = QgsGeometry.unaryUnion(featureCollection) aux_convex_hull = union_geom.convexHull() buffer_extent = QgsGeometry.fromRect(union_geom.boundingBox()).buffer( 2, 3) buffer_diff = buffer_extent.difference( QgsGeometry.fromRect(union_geom.boundingBox())) diff_geoms = buffer_extent.difference(union_geom).difference( buffer_diff) if not diff_geoms: return None feature_error = list() if not diff_geoms.isMultipart(): if include_roads and diff_geoms.touches( union_geom) and diff_geoms.intersects(buffer_diff): print("Unique value and no error") return None for geometry in diff_geoms.asMultiPolygon(): conflict_geom = QgsGeometry.fromPolygonXY(geometry) if not include_roads and conflict_geom.touches( union_geom) and conflict_geom.intersects(buffer_diff): continue if not union_geom.isMultipart() and conflict_geom.touches( union_geom) and conflict_geom.intersects(buffer_diff): continue feature_error.append(conflict_geom) unified_error = QgsGeometry.collectGeometry(feature_error) feature_error.clear() clean_errors = unified_error.intersection(aux_convex_hull) return self.extract_geoms_by_type(clean_errors, [QgsWkbTypes.PolygonGeometry])
def processAlgorithm(self, parameters, context, feedback): layerA = QgsProcessingUtils.mapLayerFromString( self.getParameterValue(self.INPUT_A), context) splitLayer = QgsProcessingUtils.mapLayerFromString( self.getParameterValue(self.INPUT_B), context) sameLayer = self.getParameterValue( self.INPUT_A) == self.getParameterValue(self.INPUT_B) fieldList = layerA.fields() writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fieldList, QgsWkbTypes.multiType(layerA.wkbType()), layerA.crs(), context) spatialIndex = QgsSpatialIndex() splitGeoms = {} request = QgsFeatureRequest() request.setSubsetOfAttributes([]) for aSplitFeature in QgsProcessingUtils.getFeatures( splitLayer, context, request): splitGeoms[aSplitFeature.id()] = aSplitFeature.geometry() spatialIndex.insertFeature(aSplitFeature) # honor the case that user has selection on split layer and has setting "use selection" outFeat = QgsFeature() features = QgsProcessingUtils.getFeatures(layerA, context) if QgsProcessingUtils.featureCount(layerA, context) == 0: total = 100 else: total = 100.0 / layerA.featureCount() if layerA.featureCount( ) else 0 for current, inFeatA in enumerate(features): inGeom = inFeatA.geometry() attrsA = inFeatA.attributes() outFeat.setAttributes(attrsA) if inGeom.isMultipart(): inGeoms = [] for g in inGeom.asGeometryCollection(): inGeoms.append(g) else: inGeoms = [inGeom] lines = spatialIndex.intersects(inGeom.boundingBox()) if len(lines) > 0: # has intersection of bounding boxes splittingLines = [] engine = QgsGeometry.createGeometryEngine(inGeom.geometry()) engine.prepareGeometry() for i in lines: try: splitGeom = splitGeoms[i] except: continue # check if trying to self-intersect if sameLayer: if inFeatA.id() == i: continue if engine.intersects(splitGeom.geometry()): splittingLines.append(splitGeom) if len(splittingLines) > 0: for splitGeom in splittingLines: splitterPList = None outGeoms = [] split_geom_engine = QgsGeometry.createGeometryEngine( splitGeom.geometry()) split_geom_engine.prepareGeometry() while len(inGeoms) > 0: inGeom = inGeoms.pop() if inGeom.isNull( ): # this has been encountered and created a run-time error continue if split_geom_engine.intersects(inGeom.geometry()): inPoints = vector.extractPoints(inGeom) if splitterPList is None: splitterPList = vector.extractPoints( splitGeom) try: result, newGeometries, topoTestPoints = inGeom.splitGeometry( splitterPList, False) except: QgsMessageLog.logMessage( self. tr('Geometry exception while splitting' ), self.tr('Processing'), QgsMessageLog.WARNING) result = 1 # splitGeometry: If there are several intersections # between geometry and splitLine, only the first one is considered. if result == 0: # split occurred if inPoints == vector.extractPoints( inGeom): # bug in splitGeometry: sometimes it returns 0 but # the geometry is unchanged outGeoms.append(inGeom) else: inGeoms.append(inGeom) for aNewGeom in newGeometries: inGeoms.append(aNewGeom) else: outGeoms.append(inGeom) else: outGeoms.append(inGeom) inGeoms = outGeoms parts = [] for aGeom in inGeoms: passed = True if QgsWkbTypes.geometryType( aGeom.wkbType()) == QgsWkbTypes.LineGeometry: numPoints = aGeom.geometry().numPoints() if numPoints <= 2: if numPoints == 2: passed = not aGeom.geometry().isClosed( ) # tests if vertex 0 = vertex 1 else: passed = False # sometimes splitting results in lines of zero length if passed: parts.append(aGeom) if len(parts) > 0: outFeat.setGeometry(QgsGeometry.collectGeometry(parts)) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) del writer