def processAlgorithm(self, progress): polyLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.POLYGONS)) pointLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.POINTS)) fieldName = self.getParameterValue(self.FIELD) fieldIdx = pointLayer.fieldNameIndex(self.getParameterValue(self.WEIGHT)) polyProvider = polyLayer.dataProvider() fields = polyProvider.fields() fields.append(QgsField(fieldName, QVariant.Int)) (idxCount, fieldList) = vector.findOrCreateField(polyLayer, polyLayer.pendingFields(), fieldName) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields.toList(), polyProvider.geometryType(), polyProvider.crs()) spatialIndex = vector.spatialindex(pointLayer) ftPoint = QgsFeature() outFeat = QgsFeature() geom = QgsGeometry() features = vector.features(polyLayer) total = 100.0 / len(features) for current, ftPoly in enumerate(features): geom = ftPoly.geometry() engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() attrs = ftPoly.attributes() count = 0 points = spatialIndex.intersects(geom.boundingBox()) if len(points) > 0: progress.setText(unicode(len(points))) request = QgsFeatureRequest().setFilterFids(points) fit = pointLayer.getFeatures(request) ftPoint = QgsFeature() while fit.nextFeature(ftPoint): tmpGeom = QgsGeometry(ftPoint.geometry()) if engine.contains(tmpGeom.geometry()): weight = unicode(ftPoint.attributes()[fieldIdx]) try: count += float(weight) except: # Ignore fields with non-numeric values pass outFeat.setGeometry(geom) if idxCount == len(attrs): attrs.append(count) else: attrs[idxCount] = count outFeat.setAttributes(attrs) writer.addFeature(outFeat) progress.setPercentage(int(current * total)) del writer
def processAlgorithm(self, progress): polyLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.POLYGONS)) pointLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.POINTS)) fieldName = self.getParameterValue(self.FIELD) classFieldName = self.getParameterValue(self.CLASSFIELD) polyProvider = polyLayer.dataProvider() fields = polyProvider.fields() fields.append(QgsField(fieldName, QVariant.Int)) classFieldIndex = pointLayer.fieldNameIndex(classFieldName) (idxCount, fieldList) = vector.findOrCreateField(polyLayer, polyLayer.pendingFields(), fieldName) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields.toList(), polyProvider.geometryType(), polyProvider.crs()) spatialIndex = vector.spatialindex(pointLayer) ftPoint = QgsFeature() outFeat = QgsFeature() geom = QgsGeometry() current = 0 features = vector.features(polyLayer) total = 100.0 / float(len(features)) for ftPoly in features: geom = ftPoly.geometry() engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() attrs = ftPoly.attributes() classes = set() points = spatialIndex.intersects(geom.boundingBox()) if len(points) > 0: request = QgsFeatureRequest().setFilterFids(points) fit = pointLayer.getFeatures(request) ftPoint = QgsFeature() while fit.nextFeature(ftPoint): tmpGeom = QgsGeometry(ftPoint.geometry()) if engine.contains(tmpGeom.geometry()): clazz = ftPoint.attributes()[classFieldIndex] if clazz not in classes: classes.add(clazz) outFeat.setGeometry(geom) if idxCount == len(attrs): attrs.append(len(classes)) else: attrs[idxCount] = len(classes) outFeat.setAttributes(attrs) writer.addFeature(outFeat) current += 1 progress.setPercentage(current / total) del writer
def processAlgorithm(self, parameters, context, feedback): polyLayer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.POLYGONS), context) pointLayer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.POINTS), context) fieldName = self.getParameterValue(self.FIELD) fieldIdx = pointLayer.fields().lookupField(self.getParameterValue(self.WEIGHT)) fields = polyLayer.fields() fields.append(QgsField(fieldName, QVariant.Int)) (idxCount, fieldList) = vector.findOrCreateField(polyLayer, polyLayer.fields(), fieldName) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, polyLayer.wkbType(), polyLayer.crs(), context) spatialIndex = QgsProcessingUtils.createSpatialIndex(pointLayer, context) ftPoint = QgsFeature() outFeat = QgsFeature() geom = QgsGeometry() features = QgsProcessingUtils.getFeatures(polyLayer, context) total = 100.0 / QgsProcessingUtils.featureCount(polyLayer, context) for current, ftPoly in enumerate(features): geom = ftPoly.geometry() engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() attrs = ftPoly.attributes() count = 0 points = spatialIndex.intersects(geom.boundingBox()) if len(points) > 0: feedback.setProgressText(str(len(points))) request = QgsFeatureRequest().setFilterFids(points).setSubsetOfAttributes([fieldIdx]) fit = pointLayer.getFeatures(request) ftPoint = QgsFeature() while fit.nextFeature(ftPoint): tmpGeom = QgsGeometry(ftPoint.geometry()) if engine.contains(tmpGeom.geometry()): weight = str(ftPoint.attributes()[fieldIdx]) try: count += float(weight) except: # Ignore fields with non-numeric values pass outFeat.setGeometry(geom) if idxCount == len(attrs): attrs.append(count) else: attrs[idxCount] = count outFeat.setAttributes(attrs) writer.addFeature(outFeat) feedback.setProgress(int(current * total)) del writer
def processAlgorithm(self, parameters, context, feedback): polyLayer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.POLYGONS), context) pointLayer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.POINTS), context) fieldName = self.getParameterValue(self.FIELD) classFieldName = self.getParameterValue(self.CLASSFIELD) fields = polyLayer.fields() fields.append(QgsField(fieldName, QVariant.Int)) classFieldIndex = pointLayer.fields().lookupField(classFieldName) (idxCount, fieldList) = vector.findOrCreateField(polyLayer, polyLayer.fields(), fieldName) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, polyLayer.wkbType(), polyLayer.crs(), context) spatialIndex = QgsProcessingUtils.createSpatialIndex(pointLayer, context) ftPoint = QgsFeature() outFeat = QgsFeature() geom = QgsGeometry() features = QgsProcessingUtils.getFeatures(polyLayer, context) total = 100.0 / polyLayer.featureCount() if polyLayer.featureCount() else 0 for current, ftPoly in enumerate(features): geom = ftPoly.geometry() engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() attrs = ftPoly.attributes() classes = set() points = spatialIndex.intersects(geom.boundingBox()) if len(points) > 0: request = QgsFeatureRequest().setFilterFids(points).setSubsetOfAttributes([classFieldIndex]) fit = pointLayer.getFeatures(request) ftPoint = QgsFeature() while fit.nextFeature(ftPoint): tmpGeom = QgsGeometry(ftPoint.geometry()) if engine.contains(tmpGeom.geometry()): clazz = ftPoint.attributes()[classFieldIndex] if clazz not in classes: classes.add(clazz) outFeat.setGeometry(geom) if idxCount == len(attrs): attrs.append(len(classes)) else: attrs[idxCount] = len(classes) outFeat.setAttributes(attrs) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) del writer
def processAlgorithm(self, feedback): extent = str(self.getParameterValue(self.EXTENT)).split(',') spacing = float(self.getParameterValue(self.SPACING)) inset = float(self.getParameterValue(self.INSET)) randomize = self.getParameterValue(self.RANDOMIZE) isSpacing = self.getParameterValue(self.IS_SPACING) crsId = self.getParameterValue(self.CRS) crs = QgsCoordinateReferenceSystem() crs.createFromUserInput(crsId) extent = QgsRectangle(float(extent[0]), float(extent[2]), float(extent[1]), float(extent[3])) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, QgsWkbTypes.Point, crs) if randomize: seed() area = extent.width() * extent.height() if isSpacing: pSpacing = spacing else: pSpacing = sqrt(area / spacing) f = QgsFeature() f.initAttributes(1) f.setFields(fields) count = 0 total = 100.0 / (area / pSpacing) y = extent.yMaximum() - inset extent_geom = QgsGeometry.fromRect(extent) extent_engine = QgsGeometry.createGeometryEngine(extent_geom.geometry()) extent_engine.prepareGeometry() while y >= extent.yMinimum(): x = extent.xMinimum() + inset while x <= extent.xMaximum(): if randomize: geom = QgsGeometry().fromPoint(QgsPoint( uniform(x - (pSpacing / 2.0), x + (pSpacing / 2.0)), uniform(y - (pSpacing / 2.0), y + (pSpacing / 2.0)))) else: geom = QgsGeometry().fromPoint(QgsPoint(x, y)) if extent_engine.intersects(geom.geometry()): f.setAttribute('id', count) f.setGeometry(geom) writer.addFeature(f) x += pSpacing count += 1 feedback.setProgress(int(count * total)) y = y - pSpacing del writer
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT_LAYER)) if layer.geometryType() == QGis.Line: output_wkb = QGis.WKBMultiPoint elif layer.geometryType() == QGis.Polygon: output_wkb = QGis.WKBLineString writer = self.getOutputFromName( self.OUTPUT_LAYER).getVectorWriter( layer.fields(), output_wkb, layer.crs()) features = vector.features(layer) total = 100.0 / len(features) for current, input_feature in enumerate(features): output_feature = input_feature if input_feature.constGeometry(): input_geometry = QgsGeometry(input_feature.geometry()) output_geometry = QgsGeometry(input_geometry.geometry().boundary()) if not output_geometry: raise GeoAlgorithmExecutionException( self.tr('Error calculating boundary')) output_feature.setGeometry(output_geometry) writer.addFeature(output_feature) progress.setPercentage(int(current * total)) del writer
def processAlgorithm(self, parameters, context, feedback): extent = self.parameterAsExtent(parameters, self.EXTENT, context) spacing = self.parameterAsDouble(parameters, self.SPACING, context) inset = self.parameterAsDouble(parameters, self.INSET, context) randomize = self.parameterAsBool(parameters, self.RANDOMIZE, context) isSpacing = self.parameterAsBool(parameters, self.IS_SPACING, context) crs = self.parameterAsCrs(parameters, self.CRS, context) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Point, crs) if randomize: seed() area = extent.width() * extent.height() if isSpacing: pSpacing = spacing else: pSpacing = sqrt(area / spacing) f = QgsFeature() f.initAttributes(1) f.setFields(fields) count = 0 total = 100.0 / (area / pSpacing) y = extent.yMaximum() - inset extent_geom = QgsGeometry.fromRect(extent) extent_engine = QgsGeometry.createGeometryEngine(extent_geom.geometry()) extent_engine.prepareGeometry() while y >= extent.yMinimum(): x = extent.xMinimum() + inset while x <= extent.xMaximum(): if feedback.isCanceled(): break if randomize: geom = QgsGeometry().fromPoint(QgsPointXY( uniform(x - (pSpacing / 2.0), x + (pSpacing / 2.0)), uniform(y - (pSpacing / 2.0), y + (pSpacing / 2.0)))) else: geom = QgsGeometry().fromPoint(QgsPointXY(x, y)) if extent_engine.intersects(geom.geometry()): f.setAttribute('id', count) f.setGeometry(geom) sink.addFeature(f, QgsFeatureSink.FastInsert) x += pSpacing count += 1 feedback.setProgress(int(count * total)) y = y - pSpacing return {self.OUTPUT: dest_id}
def smart_clip(layer_to_clip, mask_layer, callback=None): """Smart clip a vector layer with another. Issue https://github.com/inasafe/inasafe/issues/3186 :param layer_to_clip: The vector layer to clip. :type layer_to_clip: QgsVectorLayer :param mask_layer: The vector layer to use for clipping. :type mask_layer: QgsVectorLayer :param callback: A function to all to indicate progress. The function should accept params 'current' (int), 'maximum' (int) and 'step' (str). Defaults to None. :type callback: function :return: The clip vector layer. :rtype: QgsVectorLayer .. versionadded:: 4.0 """ output_layer_name = smart_clip_steps['output_layer_name'] processing_step = smart_clip_steps['step_name'] writer = create_memory_layer( output_layer_name, layer_to_clip.geometryType(), layer_to_clip.crs(), layer_to_clip.fields() ) writer.startEditing() # first build up a list of clip geometries request = QgsFeatureRequest().setSubsetOfAttributes([]) iterator = mask_layer.getFeatures(request) feature = next(iterator) geometries = QgsGeometry(feature.geometry()) # use prepared geometries for faster intersection tests # noinspection PyArgumentList engine = QgsGeometry.createGeometryEngine(geometries.geometry()) engine.prepareGeometry() extent = mask_layer.extent() for feature in layer_to_clip.getFeatures(QgsFeatureRequest(extent)): if engine.intersects(feature.geometry().geometry()): out_feat = QgsFeature() out_feat.setGeometry(feature.geometry()) out_feat.setAttributes(feature.attributes()) writer.addFeature(out_feat) writer.commitChanges() writer.keywords = layer_to_clip.keywords.copy() writer.keywords['title'] = output_layer_name check_layer(writer) return writer
def processAlgorithm(self, parameters, context, feedback): vlayer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context) output = self.getOutputFromName(self.OUTPUT) if self.getParameterValue(self.FIELDS): fields = vlayer.fields() else: fields = QgsFields() if self.getParameterValue(self.GEOMETRY): fieldsCount = fields.count() fields.append(QgsField('area', QVariant.Double, 'double', 16, 2)) fields.append(QgsField('perimeter', QVariant.Double, 'double', 16, 2)) allLinesList = [] features = QgsProcessingUtils.getFeatures(vlayer, context, QgsFeatureRequest().setSubsetOfAttributes([])) feedback.pushInfo(self.tr('Processing lines...')) total = 40.0 / QgsProcessingUtils.featureCount(vlayer, context) for current, inFeat in enumerate(features): if inFeat.geometry(): allLinesList.append(inFeat.geometry()) feedback.setProgress(int(current * total)) feedback.setProgress(40) feedback.pushInfo(self.tr('Noding lines...')) allLines = QgsGeometry.unaryUnion(allLinesList) feedback.setProgress(45) feedback.pushInfo(self.tr('Polygonizing...')) polygons = QgsGeometry.polygonize([allLines]) if polygons.isEmpty(): raise GeoAlgorithmExecutionException(self.tr('No polygons were created!')) feedback.setProgress(50) feedback.pushInfo('Saving polygons...') writer = output.getVectorWriter(fields, QgsWkbTypes.Polygon, vlayer.crs(), context) total = 50.0 / polygons.geometry().numGeometries() for i in range(polygons.geometry().numGeometries()): outFeat = QgsFeature() geom = QgsGeometry(polygons.geometry().geometryN(i).clone()) outFeat.setGeometry(geom) if self.getParameterValue(self.GEOMETRY): outFeat.setAttributes([None] * fieldsCount + [geom.geometry().area(), geom.geometry().perimeter()]) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) feedback.setProgress(50 + int(current * total)) del writer
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 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, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) extent = self.parameterAsExtent(parameters, self.TARGET_AREA, context) target_crs = self.parameterAsCrs(parameters, self.TARGET_AREA_CRS, context) target_geom = QgsGeometry.fromRect(extent) fields = QgsFields() fields.append(QgsField('auth_id', QVariant.String, '', 20)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem()) # make intersection tests nice and fast engine = QgsGeometry.createGeometryEngine(target_geom.geometry()) engine.prepareGeometry() layer_bounds = QgsGeometry.fromRect(source.sourceExtent()) crses_to_check = QgsCoordinateReferenceSystem.validSrsIds() total = 100.0 / len(crses_to_check) found_results = 0 for current, srs_id in enumerate(crses_to_check): if feedback.isCanceled(): break candidate_crs = QgsCoordinateReferenceSystem.fromSrsId(srs_id) if not candidate_crs.isValid(): continue transform_candidate = QgsCoordinateTransform(candidate_crs, target_crs) transformed_bounds = QgsGeometry(layer_bounds) try: if not transformed_bounds.transform(transform_candidate) == 0: continue except: continue if engine.intersects(transformed_bounds.geometry()): feedback.pushInfo(self.tr('Found candidate CRS: {}').format(candidate_crs.authid())) f = QgsFeature(fields) f.setAttributes([candidate_crs.authid()]) sink.addFeature(f, QgsFeatureSink.FastInsert) found_results += 1 feedback.setProgress(int(current * total)) if found_results == 0: feedback.reportError(self.tr('No matching projections found')) return {self.OUTPUT: dest_id}
def processAlgorithm(self, feedback): polyLayer = dataobjects.getLayerFromString(self.getParameterValue(self.POLYGONS)) pointLayer = dataobjects.getLayerFromString(self.getParameterValue(self.POINTS)) fieldName = self.getParameterValue(self.FIELD) fields = polyLayer.fields() fields.append(QgsField(fieldName, QVariant.Int)) (idxCount, fieldList) = vector.findOrCreateField(polyLayer, polyLayer.fields(), fieldName) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields.toList(), polyLayer.wkbType(), polyLayer.crs()) spatialIndex = vector.spatialindex(pointLayer) ftPoly = QgsFeature() ftPoint = QgsFeature() outFeat = QgsFeature() geom = QgsGeometry() features = vector.features(polyLayer) total = 100.0 / len(features) for current, ftPoly in enumerate(features): geom = ftPoly.geometry() engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() attrs = ftPoly.attributes() count = 0 points = spatialIndex.intersects(geom.boundingBox()) if len(points) > 0: request = QgsFeatureRequest().setFilterFids(points).setSubsetOfAttributes([]) fit = pointLayer.getFeatures(request) ftPoint = QgsFeature() while fit.nextFeature(ftPoint): tmpGeom = ftPoint.geometry() if engine.contains(tmpGeom.geometry()): count += 1 outFeat.setGeometry(geom) if idxCount == len(attrs): attrs.append(count) else: attrs[idxCount] = count outFeat.setAttributes(attrs) writer.addFeature(outFeat) feedback.setProgress(int(current * total)) del writer
def processAlgorithm(self, parameters, context, feedback): layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context) extent = self.getParameterValue(self.TARGET_AREA).split(',') if not extent: extent = QgsProcessingUtils.combineLayerExtents([layer]) target_crs = QgsCoordinateReferenceSystem(self.getParameterValue(self.TARGET_AREA_CRS)) target_geom = QgsGeometry.fromRect(QgsRectangle(float(extent[0]), float(extent[2]), float(extent[1]), float(extent[3]))) output_file = self.getOutputValue(self.OUTPUT_HTML_FILE) # make intersection tests nice and fast engine = QgsGeometry.createGeometryEngine(target_geom.geometry()) engine.prepareGeometry() layer_bounds = QgsGeometry.fromRect(layer.extent()) results = [] for srs_id in QgsCoordinateReferenceSystem.validSrsIds(): candidate_crs = QgsCoordinateReferenceSystem.fromSrsId(srs_id) if not candidate_crs.isValid(): continue transform_candidate = QgsCoordinateTransform(candidate_crs, target_crs) transformed_bounds = QgsGeometry(layer_bounds) try: if not transformed_bounds.transform(transform_candidate) == 0: continue except: continue if engine.intersects(transformed_bounds.geometry()): results.append(candidate_crs.authid()) self.createHTML(output_file, results)
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, parameters, context, feedback): sourceA = self.parameterAsSource(parameters, self.INPUT, context) sourceB = self.parameterAsSource(parameters, self.OVERLAY, context) geomType = QgsWkbTypes.multiType(sourceA.wkbType()) fieldsA = self.parameterAsFields(parameters, self.INPUT_FIELDS, context) fieldsB = self.parameterAsFields(parameters, self.OVERLAY_FIELDS, context) fieldListA = QgsFields() field_indices_a = [] if len(fieldsA) > 0: for f in fieldsA: idxA = sourceA.fields().lookupField(f) if idxA >= 0: field_indices_a.append(idxA) fieldListA.append(sourceA.fields()[idxA]) else: fieldListA = sourceA.fields() field_indices_a = [i for i in range(0, fieldListA.count())] fieldListB = QgsFields() field_indices_b = [] if len(fieldsB) > 0: for f in fieldsB: idxB = sourceB.fields().lookupField(f) if idxB >= 0: field_indices_b.append(idxB) fieldListB.append(sourceB.fields()[idxB]) else: fieldListB = sourceB.fields() field_indices_b = [i for i in range(0, fieldListB.count())] output_fields = QgsProcessingUtils.combineFields( fieldListA, fieldListB) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, output_fields, geomType, sourceA.sourceCrs()) outFeat = QgsFeature() indexB = QgsSpatialIndex( sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes( []).setDestinationCrs(sourceA.sourceCrs())), feedback) total = 100.0 / sourceA.featureCount() if sourceA.featureCount() else 1 count = 0 for featA in sourceA.getFeatures( QgsFeatureRequest().setSubsetOfAttributes(field_indices_a)): if feedback.isCanceled(): break if not featA.hasGeometry(): continue geom = featA.geometry() atMapA = featA.attributes() intersects = indexB.intersects(geom.boundingBox()) request = QgsFeatureRequest().setFilterFids(intersects) request.setDestinationCrs(sourceA.sourceCrs()) request.setSubsetOfAttributes(field_indices_b) engine = None if len(intersects) > 0: # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for featB in sourceB.getFeatures(request): if feedback.isCanceled(): break tmpGeom = featB.geometry() if engine.intersects(tmpGeom.geometry()): out_attributes = [ featA.attributes()[i] for i in field_indices_a ] out_attributes.extend( [featB.attributes()[i] for i in field_indices_b]) int_geom = QgsGeometry(geom.intersection(tmpGeom)) if int_geom.wkbType( ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType( int_geom.geometry().wkbType( )) == QgsWkbTypes.GeometryCollection: int_com = geom.combine(tmpGeom) int_geom = QgsGeometry() if int_com: int_sym = geom.symDifference(tmpGeom) int_geom = QgsGeometry(int_com.difference(int_sym)) if int_geom.isEmpty() or not int_geom.isGeosValid(): raise QgsProcessingException( self.tr('GEOS geoprocessing error: One or ' 'more input features have invalid ' 'geometry.')) try: if QgsWkbTypes.geometryType(int_geom.wkbType( )) == QgsWkbTypes.geometryType(geomType): int_geom.convertToMultiType() outFeat.setGeometry(int_geom) outFeat.setAttributes(out_attributes) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: raise QgsProcessingException( self.tr('Feature geometry error: One or more ' 'output features ignored due to invalid ' 'geometry.')) count += 1 feedback.setProgress(int(count * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, progress): lineLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.LINES)) polyLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.POLYGONS)) lengthFieldName = self.getParameterValue(self.LEN_FIELD) countFieldName = self.getParameterValue(self.COUNT_FIELD) (idxLength, fieldList) = vector.findOrCreateField(polyLayer, polyLayer.fields(), lengthFieldName) (idxCount, fieldList) = vector.findOrCreateField(polyLayer, fieldList, countFieldName) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fieldList.toList(), polyLayer.wkbType(), polyLayer.crs()) spatialIndex = vector.spatialindex(lineLayer) ftLine = QgsFeature() ftPoly = QgsFeature() outFeat = QgsFeature() inGeom = QgsGeometry() outGeom = QgsGeometry() distArea = QgsDistanceArea() features = vector.features(polyLayer) total = 100.0 / len(features) hasIntersections = False for current, ftPoly in enumerate(features): inGeom = ftPoly.geometry() attrs = ftPoly.attributes() count = 0 length = 0 hasIntersections = False lines = spatialIndex.intersects(inGeom.boundingBox()) engine = None if len(lines) > 0: hasIntersections = True # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(inGeom.geometry()) engine.prepareGeometry() if hasIntersections: request = QgsFeatureRequest().setFilterFids(lines).setSubsetOfAttributes([]) for ftLine in lineLayer.getFeatures(request): tmpGeom = ftLine.geometry() if engine.intersects(tmpGeom.geometry()): outGeom = inGeom.intersection(tmpGeom) length += distArea.measureLength(outGeom) count += 1 outFeat.setGeometry(inGeom) if idxLength == len(attrs): attrs.append(length) else: attrs[idxLength] = length if idxCount == len(attrs): attrs.append(count) else: attrs[idxCount] = count outFeat.setAttributes(attrs) writer.addFeature(outFeat) progress.setPercentage(int(current * total)) del writer
def processAlgorithm(self, parameters, context, feedback): sourceA = self.parameterAsSource(parameters, self.INPUT, context) sourceB = self.parameterAsSource(parameters, self.OVERLAY, context) geomType = QgsWkbTypes.multiType(sourceA.wkbType()) fieldsA = self.parameterAsFields(parameters, self.INPUT_FIELDS, context) fieldsB = self.parameterAsFields(parameters, self.OVERLAY_FIELDS, context) fieldListA = QgsFields() field_indices_a = [] if len(fieldsA) > 0: for f in fieldsA: idxA = sourceA.fields().lookupField(f) if idxA >= 0: field_indices_a.append(idxA) fieldListA.append(sourceA.fields()[idxA]) else: fieldListA = sourceA.fields() field_indices_a = [i for i in range(0, fieldListA.count())] fieldListB = QgsFields() field_indices_b = [] if len(fieldsB) > 0: for f in fieldsB: idxB = sourceB.fields().lookupField(f) if idxB >= 0: field_indices_b.append(idxB) fieldListB.append(sourceB.fields()[idxB]) else: fieldListB = sourceB.fields() field_indices_b = [i for i in range(0, fieldListB.count())] fieldListB = vector.testForUniqueness(fieldListA, fieldListB) for b in fieldListB: fieldListA.append(b) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fieldListA, geomType, sourceA.sourceCrs()) outFeat = QgsFeature() indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())), feedback) total = 100.0 / sourceA.featureCount() if sourceA.featureCount() else 1 count = 0 for featA in sourceA.getFeatures(QgsFeatureRequest().setSubsetOfAttributes(field_indices_a)): if feedback.isCanceled(): break if not featA.hasGeometry(): continue geom = featA.geometry() atMapA = featA.attributes() intersects = indexB.intersects(geom.boundingBox()) request = QgsFeatureRequest().setFilterFids(intersects) request.setDestinationCrs(sourceA.sourceCrs()) request.setSubsetOfAttributes(field_indices_b) engine = None if len(intersects) > 0: # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for featB in sourceB.getFeatures(request): if feedback.isCanceled(): break tmpGeom = featB.geometry() if engine.intersects(tmpGeom.geometry()): out_attributes = [featA.attributes()[i] for i in field_indices_a] out_attributes.extend([featB.attributes()[i] for i in field_indices_b]) int_geom = QgsGeometry(geom.intersection(tmpGeom)) if int_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(int_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection: int_com = geom.combine(tmpGeom) int_geom = QgsGeometry() if int_com: int_sym = geom.symDifference(tmpGeom) int_geom = QgsGeometry(int_com.difference(int_sym)) if int_geom.isEmpty() or not int_geom.isGeosValid(): raise QgsProcessingException( self.tr('GEOS geoprocessing error: One or ' 'more input features have invalid ' 'geometry.')) try: if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]: outFeat.setGeometry(int_geom) outFeat.setAttributes(out_attributes) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: raise QgsProcessingException( self.tr('Feature geometry error: One or more ' 'output features ignored due to invalid ' 'geometry.')) count += 1 feedback.setProgress(int(count * total)) return {self.OUTPUT: dest_id}
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 processAlgorithm(self, parameters, context, feedback): vlayerA = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context) vlayerB = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT2), context) geomType = QgsWkbTypes.multiType(vlayerA.wkbType()) fields = vector.combineVectorFields(vlayerA, vlayerB) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, geomType, vlayerA.crs(), context) outFeat = QgsFeature() index = QgsProcessingUtils.createSpatialIndex(vlayerB, context) selectionA = QgsProcessingUtils.getFeatures(vlayerA, context) total = 100.0 / vlayerA.featureCount() if vlayerA.featureCount() else 0 for current, inFeatA in enumerate(selectionA): feedback.setProgress(int(current * total)) geom = inFeatA.geometry() atMapA = inFeatA.attributes() intersects = index.intersects(geom.boundingBox()) request = QgsFeatureRequest().setFilterFids(intersects) engine = None if len(intersects) > 0: # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerB.getFeatures(request): tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): atMapB = inFeatB.attributes() int_geom = QgsGeometry(geom.intersection(tmpGeom)) if int_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(int_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection: int_com = geom.combine(tmpGeom) int_geom = QgsGeometry() if int_com: int_sym = geom.symDifference(tmpGeom) int_geom = QgsGeometry(int_com.difference(int_sym)) if int_geom.isEmpty() or not int_geom.isGeosValid(): raise GeoAlgorithmExecutionException( self.tr('GEOS geoprocessing error: One or ' 'more input features have invalid ' 'geometry.')) try: if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]: outFeat.setGeometry(int_geom) attrs = [] attrs.extend(atMapA) attrs.extend(atMapB) outFeat.setAttributes(attrs) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) except: raise GeoAlgorithmExecutionException( self.tr('Feature geometry error: One or more ' 'output features ignored due to invalid ' 'geometry.')) del writer
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 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): extent = str(self.getParameterValue(self.EXTENT)).split(',') spacing = float(self.getParameterValue(self.SPACING)) inset = float(self.getParameterValue(self.INSET)) randomize = self.getParameterValue(self.RANDOMIZE) isSpacing = self.getParameterValue(self.IS_SPACING) extent = QgsRectangle(float(extent[0]), float(extent[2]), float(extent[1]), float(extent[3])) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) mapCRS = iface.mapCanvas().mapSettings().destinationCrs() writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, QgsWkbTypes.Point, mapCRS) if randomize: seed() area = extent.width() * extent.height() if isSpacing: pSpacing = spacing else: pSpacing = sqrt(area / spacing) f = QgsFeature() f.initAttributes(1) f.setFields(fields) count = 0 total = 100.0 / (area / pSpacing) y = extent.yMaximum() - inset extent_geom = QgsGeometry.fromRect(extent) extent_engine = QgsGeometry.createGeometryEngine( extent_geom.geometry()) extent_engine.prepareGeometry() while y >= extent.yMinimum(): x = extent.xMinimum() + inset while x <= extent.xMaximum(): if randomize: geom = QgsGeometry().fromPoint( QgsPoint( uniform(x - (pSpacing / 2.0), x + (pSpacing / 2.0)), uniform(y - (pSpacing / 2.0), y + (pSpacing / 2.0)))) else: geom = QgsGeometry().fromPoint(QgsPoint(x, y)) if extent_engine.intersects(geom.geometry()): f.setAttribute('id', count) f.setGeometry(geom) writer.addFeature(f) x += pSpacing count += 1 progress.setPercentage(int(count * total)) y = y - pSpacing del writer
def processAlgorithm(self, context, feedback): vlayerA = QgsProcessingUtils.mapLayerFromString( self.getParameterValue(self.INPUT), context) vlayerB = QgsProcessingUtils.mapLayerFromString( self.getParameterValue(self.INPUT2), context) geomType = QgsWkbTypes.multiType(vlayerA.wkbType()) fields = vector.combineVectorFields(vlayerA, vlayerB) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, geomType, vlayerA.crs(), context) outFeat = QgsFeature() index = QgsProcessingUtils.createSpatialIndex(vlayerB, context) selectionA = QgsProcessingUtils.getFeatures(vlayerA, context) total = 100.0 / QgsProcessingUtils.featureCount(vlayerA, context) for current, inFeatA in enumerate(selectionA): feedback.setProgress(int(current * total)) geom = inFeatA.geometry() atMapA = inFeatA.attributes() intersects = index.intersects(geom.boundingBox()) request = QgsFeatureRequest().setFilterFids(intersects) engine = None if len(intersects) > 0: # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerB.getFeatures(request): tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): atMapB = inFeatB.attributes() int_geom = QgsGeometry(geom.intersection(tmpGeom)) if int_geom.wkbType( ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType( int_geom.geometry().wkbType( )) == QgsWkbTypes.GeometryCollection: int_com = geom.combine(tmpGeom) int_geom = QgsGeometry() if int_com: int_sym = geom.symDifference(tmpGeom) int_geom = QgsGeometry(int_com.difference(int_sym)) if int_geom.isEmpty() or not int_geom.isGeosValid(): raise GeoAlgorithmExecutionException( self.tr('GEOS geoprocessing error: One or ' 'more input features have invalid ' 'geometry.')) try: if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[ int_geom.wkbType()]]: outFeat.setGeometry(int_geom) attrs = [] attrs.extend(atMapA) attrs.extend(atMapB) outFeat.setAttributes(attrs) writer.addFeature(outFeat) except: raise GeoAlgorithmExecutionException( self.tr('Feature geometry error: One or more ' 'output features ignored due to invalid ' 'geometry.')) del writer
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) fieldName = self.parameterAsString(parameters, self.FIELD, context) useField = bool(fieldName) field_index = None f = QgsField('value', QVariant.String, '', 255) if useField: field_index = source.fields().lookupField(fieldName) fType = source.fields()[field_index].type() if fType in [ QVariant.Int, QVariant.UInt, QVariant.LongLong, QVariant.ULongLong ]: f.setType(fType) f.setLength(20) elif fType == QVariant.Double: f.setType(QVariant.Double) f.setLength(20) f.setPrecision(6) else: f.setType(QVariant.String) f.setLength(255) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 20)) fields.append(f) fields.append(QgsField('area', QVariant.Double, '', 20, 6)) fields.append(QgsField('perim', QVariant.Double, '', 20, 6)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Polygon, source.sourceCrs()) outFeat = QgsFeature() outGeom = QgsGeometry() fid = 0 val = None if useField: unique = source.uniqueValues(field_index) current = 0 total = 100.0 / (source.featureCount() * len(unique)) if source.featureCount() else 1 for i in unique: if feedback.isCanceled(): break first = True hull = [] features = source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes([field_index])) for f in features: if feedback.isCanceled(): break idVar = f.attributes()[field_index] if str(idVar).strip() == str(i).strip(): if first: val = idVar first = False inGeom = f.geometry() points = vector.extractPoints(inGeom) hull.extend(points) current += 1 feedback.setProgress(int(current * total)) if len(hull) >= 3: tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull)) try: outGeom = tmpGeom.convexHull() if outGeom: area = outGeom.geometry().area() perim = outGeom.geometry().perimeter() else: area = NULL perim = NULL outFeat.setGeometry(outGeom) outFeat.setAttributes([fid, val, area, perim]) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: raise QgsProcessingException( self.tr('Exception while computing convex hull')) fid += 1 else: hull = [] total = 100.0 / source.featureCount() if source.featureCount( ) else 1 features = source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes([])) for current, f in enumerate(features): if feedback.isCanceled(): break inGeom = f.geometry() points = vector.extractPoints(inGeom) hull.extend(points) feedback.setProgress(int(current * total)) tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull)) try: outGeom = tmpGeom.convexHull() if outGeom: area = outGeom.geometry().area() perim = outGeom.geometry().perimeter() else: area = NULL perim = NULL outFeat.setGeometry(outGeom) outFeat.setAttributes([0, 'all', area, perim]) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: raise QgsProcessingException( self.tr('Exception while computing convex hull')) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): sourceA = self.parameterAsSource(parameters, self.INPUT, context) sourceB = self.parameterAsSource(parameters, self.OVERLAY, context) geomType = QgsWkbTypes.multiType(sourceA.wkbType()) fields = vector.combineFields(sourceA.fields(), sourceB.fields()) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, geomType, sourceA.sourceCrs()) featA = QgsFeature() featB = QgsFeature() outFeat = QgsFeature() indexA = QgsSpatialIndex(sourceA, feedback) indexB = QgsSpatialIndex( sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes( []).setDestinationCrs(sourceA.sourceCrs())), feedback) total = 100.0 / (sourceA.featureCount() * sourceB.featureCount()) if sourceA.featureCount( ) and sourceB.featureCount() else 1 count = 0 for featA in sourceA.getFeatures(): if feedback.isCanceled(): break lstIntersectingB = [] geom = featA.geometry() atMapA = featA.attributes() intersects = indexB.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMapA) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: # This really shouldn't happen, as we haven't # edited the input geom at all feedback.pushInfo( self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) else: request = QgsFeatureRequest().setFilterFids( intersects).setSubsetOfAttributes([]) request.setDestinationCrs(sourceA.sourceCrs()) engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for featB in sourceB.getFeatures(request): atMapB = featB.attributes() tmpGeom = featB.geometry() if engine.intersects(tmpGeom.geometry()): int_geom = geom.intersection(tmpGeom) lstIntersectingB.append(tmpGeom) if not int_geom: # There was a problem creating the intersection feedback.pushInfo( self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) int_geom = QgsGeometry() else: int_geom = QgsGeometry(int_geom) if int_geom.wkbType( ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType( int_geom.geometry().wkbType( )) == QgsWkbTypes.GeometryCollection: # Intersection produced different geomety types temp_list = int_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): int_geom = QgsGeometry(i) try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) sink.addFeature( outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo( self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) else: # Geometry list: prevents writing error # in geometries of different types # produced by the intersection # fix #3549 if int_geom.wkbType() in wkbTypeGroups[ wkbTypeGroups[int_geom.wkbType()]]: try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo( self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) # the remaining bit of featA's geometry # if there is nothing left, this will just silently fail and we're good diff_geom = QgsGeometry(geom) if len(lstIntersectingB) != 0: intB = QgsGeometry.unaryUnion(lstIntersectingB) diff_geom = diff_geom.difference(intB) if diff_geom.wkbType( ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType( diff_geom.geometry().wkbType( )) == QgsWkbTypes.GeometryCollection: temp_list = diff_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): diff_geom = QgsGeometry(i) try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMapA) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo( self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) count += 1 feedback.setProgress(int(count * total)) length = len(sourceA.fields()) atMapA = [None] * length for featA in sourceB.getFeatures(QgsFeatureRequest().setDestinationCrs( sourceA.sourceCrs())): if feedback.isCanceled(): break add = False geom = featA.geometry() diff_geom = QgsGeometry(geom) atMap = [None] * length atMap.extend(featA.attributes()) intersects = indexA.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMap) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo( self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) else: request = QgsFeatureRequest().setFilterFids( intersects).setSubsetOfAttributes([]) request.setDestinationCrs(sourceA.sourceCrs()) # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(diff_geom.geometry()) engine.prepareGeometry() for featB in sourceA.getFeatures(request): atMapB = featB.attributes() tmpGeom = featB.geometry() if engine.intersects(tmpGeom.geometry()): add = True diff_geom = QgsGeometry(diff_geom.difference(tmpGeom)) else: try: # Ihis only happens if the bounding box # intersects, but the geometry doesn't outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo( self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) if add: try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo( self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) count += 1 feedback.setProgress(int(count * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, progress): polyLayer = dataobjects.getObjectFromUri( self.getParameterValue(self.POLYGONS)) pointLayer = dataobjects.getObjectFromUri( self.getParameterValue(self.POINTS)) fieldName = self.getParameterValue(self.FIELD) fieldIdx = pointLayer.fields().lookupField( self.getParameterValue(self.WEIGHT)) fields = polyLayer.fields() fields.append(QgsField(fieldName, QVariant.Int)) (idxCount, fieldList) = vector.findOrCreateField(polyLayer, polyLayer.fields(), fieldName) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields.toList(), polyLayer.wkbType(), polyLayer.crs()) spatialIndex = vector.spatialindex(pointLayer) ftPoint = QgsFeature() outFeat = QgsFeature() geom = QgsGeometry() features = vector.features(polyLayer) total = 100.0 / len(features) for current, ftPoly in enumerate(features): geom = ftPoly.geometry() engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() attrs = ftPoly.attributes() count = 0 points = spatialIndex.intersects(geom.boundingBox()) if len(points) > 0: progress.setText(str(len(points))) request = QgsFeatureRequest().setFilterFids( points).setSubsetOfAttributes([fieldIdx]) fit = pointLayer.getFeatures(request) ftPoint = QgsFeature() while fit.nextFeature(ftPoint): tmpGeom = QgsGeometry(ftPoint.geometry()) if engine.contains(tmpGeom.geometry()): weight = str(ftPoint.attributes()[fieldIdx]) try: count += float(weight) except: # Ignore fields with non-numeric values pass outFeat.setGeometry(geom) if idxCount == len(attrs): attrs.append(count) else: attrs[idxCount] = count outFeat.setAttributes(attrs) writer.addFeature(outFeat) progress.setPercentage(int(current * total)) del writer
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): layerA = dataobjects.getObjectFromUri( self.getParameterValue(Clip.INPUT)) layerB = dataobjects.getObjectFromUri( self.getParameterValue(Clip.OVERLAY)) geomType = layerA.dataProvider().geometryType() if geomType in GEOM_25D: raise GeoAlgorithmExecutionException( self.tr('Input layer has unsupported geometry type {}').format(geomType)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( layerA.pendingFields(), layerA.dataProvider().geometryType(), layerA.dataProvider().crs()) inFeatA = QgsFeature() inFeatB = QgsFeature() outFeat = QgsFeature() index = vector.spatialindex(layerB) selectionA = vector.features(layerA) total = 100.0 / len(selectionA) for current, inFeatA in enumerate(selectionA): geom = QgsGeometry(inFeatA.geometry()) attrs = inFeatA.attributes() intersects = index.intersects(geom.boundingBox()) first = True found = False if len(intersects) > 0: for i in intersects: layerB.getFeatures( QgsFeatureRequest().setFilterFid(i)).nextFeature( inFeatB) tmpGeom = QgsGeometry(inFeatB.geometry()) if tmpGeom.intersects(geom): found = True if first: outFeat.setGeometry(QgsGeometry(tmpGeom)) first = False else: cur_geom = QgsGeometry(outFeat.geometry()) new_geom = QgsGeometry(cur_geom.combine(tmpGeom)) if new_geom.isGeosEmpty() or not new_geom.isGeosValid(): ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, self.tr('GEOS geoprocessing error: One or ' 'more input features have invalid ' 'geometry.')) break outFeat.setGeometry(QgsGeometry(new_geom)) if found: cur_geom = QgsGeometry(outFeat.geometry()) new_geom = QgsGeometry(geom.intersection(cur_geom)) if new_geom.wkbType() == QGis.WKBUnknown or QgsWKBTypes.flatType(new_geom.geometry().wkbType()) == QgsWKBTypes.GeometryCollection: int_com = QgsGeometry(geom.combine(cur_geom)) int_sym = QgsGeometry(geom.symDifference(cur_geom)) new_geom = QgsGeometry(int_com.difference(int_sym)) if new_geom.isGeosEmpty() or not new_geom.isGeosValid(): ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, self.tr('GEOS geoprocessing error: One or more ' 'input features have invalid geometry.')) continue try: outFeat.setGeometry(new_geom) outFeat.setAttributes(attrs) writer.addFeature(outFeat) except: ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, self.tr('Feature geometry error: One or more ' 'output features ignored due to ' 'invalid geometry.')) continue progress.setPercentage(int(current * total)) del writer
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, feedback): vlayerA = dataobjects.getObjectFromUri( self.getParameterValue(Union.INPUT)) vlayerB = dataobjects.getObjectFromUri( self.getParameterValue(Union.INPUT2)) geomType = vlayerA.wkbType() fields = vector.combineVectorFields(vlayerA, vlayerB) writer = self.getOutputFromName(Union.OUTPUT).getVectorWriter( fields, geomType, vlayerA.crs()) inFeatA = QgsFeature() inFeatB = QgsFeature() outFeat = QgsFeature() indexA = vector.spatialindex(vlayerB) indexB = vector.spatialindex(vlayerA) count = 0 nElement = 0 featuresA = vector.features(vlayerA) nFeat = len(featuresA) for inFeatA in featuresA: feedback.setProgress(nElement / float(nFeat) * 50) nElement += 1 lstIntersectingB = [] geom = inFeatA.geometry() atMapA = inFeatA.attributes() intersects = indexA.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMapA) writer.addFeature(outFeat) except: # This really shouldn't happen, as we haven't # edited the input geom at all ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) else: request = QgsFeatureRequest().setFilterFids(intersects) engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerB.getFeatures(request): count += 1 atMapB = inFeatB.attributes() tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): int_geom = geom.intersection(tmpGeom) lstIntersectingB.append(tmpGeom) if not int_geom: # There was a problem creating the intersection ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('GEOS geoprocessing error: One or more input features have invalid geometry.' )) int_geom = QgsGeometry() else: int_geom = QgsGeometry(int_geom) if int_geom.wkbType( ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType( int_geom.geometry().wkbType( )) == QgsWkbTypes.GeometryCollection: # Intersection produced different geomety types temp_list = int_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): int_geom = QgsGeometry(i) try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) else: # Geometry list: prevents writing error # in geometries of different types # produced by the intersection # fix #3549 if int_geom.wkbType() in wkbTypeGroups[ wkbTypeGroups[int_geom.wkbType()]]: try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) # the remaining bit of inFeatA's geometry # if there is nothing left, this will just silently fail and we're good diff_geom = QgsGeometry(geom) if len(lstIntersectingB) != 0: intB = QgsGeometry.unaryUnion(lstIntersectingB) diff_geom = diff_geom.difference(intB) if diff_geom.wkbType() == 0 or QgsWkbTypes.flatType( diff_geom.geometry().wkbType( )) == QgsWkbTypes.GeometryCollection: temp_list = diff_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): diff_geom = QgsGeometry(i) try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMapA) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) length = len(vlayerA.fields()) atMapA = [None] * length featuresA = vector.features(vlayerB) nFeat = len(featuresA) for inFeatA in featuresA: feedback.setProgress(nElement / float(nFeat) * 100) add = False geom = inFeatA.geometry() diff_geom = QgsGeometry(geom) atMap = [None] * length atMap.extend(inFeatA.attributes()) intersects = indexB.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) else: request = QgsFeatureRequest().setFilterFids(intersects) # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(diff_geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerA.getFeatures(request): atMapB = inFeatB.attributes() tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): add = True diff_geom = QgsGeometry(diff_geom.difference(tmpGeom)) else: try: # Ihis only happens if the bounding box # intersects, but the geometry doesn't outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) if add: try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) nElement += 1 del writer
class GeometryHighlightItem(QgsMapCanvasItem): # Code ported from QGIS QgsHighlight def __init__(self, mapCanvas, geometry, layer): super(GeometryHighlightItem, self).__init__(mapCanvas) self._mapCanvas = None # QgsMapCanvas self._geometry = None # QgsGeometry() self._brush = QBrush() self._pen = QPen() self._mapCanvas = mapCanvas if not geometry or not isinstance(geometry, QgsGeometry) or geometry.isEmpty() or not geometry.isGeosValid(): return self._geometry = QgsGeometry(geometry) # Force deep copy self.setLineColor(Application.highlightLineColor()) self.setFillColor(Application.highlightFillColor()) if (layer and self._mapCanvas.mapSettings().hasCrsTransformEnabled()): ct = self._mapCanvas.mapSettings().layerTransform(layer) if ct: self._geometry.transform(ct) self.updateRect() self.update() def remove(self): self._mapCanvas.scene().removeItem(self) def setLineWidth(self, width): self._pen.setWidth(width) def setLineColor(self, color): lineColor = QColor(color) lineColor.setAlpha(255) self._pen.setColor(lineColor) def setFillColor(self, fillColor): self._brush.setColor(fillColor) self._brush.setStyle(Qt.SolidPattern) def updatePosition(self): pass # protected: def paint(self, painter, option=None, widget=None): # Override if not self._geometry: return painter.setPen(self._pen) painter.setBrush(self._brush) wkbType = self._geometry.wkbType() if wkbType == QGis.WKBPoint or wkbType == QGis.WKBPoint25D: self._paintPoint(painter, self._geometry.geometry()) elif wkbType == QGis.WKBMultiPoint or wkbType == QGis.WKBMultiPoint25D: for point in self._geometry.geometry(): self._paintPoint(painter, point) elif wkbType == QGis.WKBLineString or wkbType == QGis.WKBLineString25D: self._paintLine(painter, self._geometry.geometry()) elif wkbType == QGis.WKBMultiLineString or wkbType == QGis.WKBMultiLineString25D: for line in self._geometry.geometry(): self._paintLine(painter, line) elif wkbType == QGis.WKBPolygon or wkbType == QGis.WKBPolygon25D: self._paintPolygon(painter, self._geometry.geometry()) elif wkbType == QGis.WKBMultiPolygon or wkbType == QGis.WKBMultiPolygon25D: for polygon in self._geometry.geometry(): self._paintPolygon(painter, polygon) def updateRect(self): if self._geometry: r = self._geometry.boundingBox() if r.isEmpty(): d = self._mapCanvas.extent().width() * 0.005 r.setXMinimum(r.xMinimum() - d) r.setYMinimum(r.yMinimum() - d) r.setXMaximum(r.xMaximum() + d) r.setYMaximum(r.yMaximum() + d) self.setRect(r) self.setVisible(True) else: self.setRect(QgsRectangle()) # private: def _paintPoint(self, painter, point): painter.drawEllipse(self.toCanvasCoordinates(point) - self.pos(), 2, 2) def _paintLine(self, painter, line): polyline = QPolygonF() for point in line: polyline.append(self.toCanvasCoordinates(point) - self.pos()) painter.drawPolyline(polyline) def _paintPolygon(self, painter, polygon): path = QPainterPath() for line in polygon: ring = QPolygonF() for point in line: cur = self.toCanvasCoordinates(point) - self.pos() ring.append(cur) ring.append(ring[0]) path.addPolygon(ring) painter.drawPath(path)
def processAlgorithm(self, parameters, context, feedback): extent = self.parameterAsExtent(parameters, self.EXTENT, context) spacing = self.parameterAsDouble(parameters, self.SPACING, context) inset = self.parameterAsDouble(parameters, self.INSET, context) randomize = self.parameterAsBool(parameters, self.RANDOMIZE, context) isSpacing = self.parameterAsBool(parameters, self.IS_SPACING, context) crs = self.parameterAsCrs(parameters, self.CRS, context) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Point, crs) if randomize: seed() area = extent.width() * extent.height() if isSpacing: pSpacing = spacing else: pSpacing = sqrt(area / spacing) f = QgsFeature() f.initAttributes(1) f.setFields(fields) count = 0 total = 100.0 / (area / pSpacing) y = extent.yMaximum() - inset extent_geom = QgsGeometry.fromRect(extent) extent_engine = QgsGeometry.createGeometryEngine( extent_geom.geometry()) extent_engine.prepareGeometry() while y >= extent.yMinimum(): x = extent.xMinimum() + inset while x <= extent.xMaximum(): if feedback.isCanceled(): break if randomize: geom = QgsGeometry().fromPoint( QgsPointXY( uniform(x - (pSpacing / 2.0), x + (pSpacing / 2.0)), uniform(y - (pSpacing / 2.0), y + (pSpacing / 2.0)))) else: geom = QgsGeometry().fromPoint(QgsPointXY(x, y)) if extent_engine.intersects(geom.geometry()): f.setAttribute('id', count) f.setGeometry(geom) sink.addFeature(f, QgsFeatureSink.FastInsert) x += pSpacing count += 1 feedback.setProgress(int(count * total)) y = y - pSpacing return {self.OUTPUT: dest_id}
def processAlgorithm(self, progress): vlayerA = dataobjects.getObjectFromUri( self.getParameterValue(Union.INPUT)) vlayerB = dataobjects.getObjectFromUri( self.getParameterValue(Union.INPUT2)) vproviderA = vlayerA.dataProvider() geomType = vproviderA.geometryType() if geomType in GEOM_25D: raise GeoAlgorithmExecutionException( self.tr('Input layer does not support 2.5D type geometry ({}).' ).format(QgsWKBTypes.displayString(geomType))) fields = vector.combineVectorFields(vlayerA, vlayerB) writer = self.getOutputFromName(Union.OUTPUT).getVectorWriter( fields, geomType, vproviderA.crs()) inFeatA = QgsFeature() inFeatB = QgsFeature() outFeat = QgsFeature() indexA = vector.spatialindex(vlayerB) indexB = vector.spatialindex(vlayerA) count = 0 nElement = 0 featuresA = vector.features(vlayerA) nFeat = len(featuresA) for inFeatA in featuresA: progress.setPercentage(nElement / float(nFeat) * 50) nElement += 1 lstIntersectingB = [] geom = QgsGeometry(inFeatA.geometry()) atMapA = inFeatA.attributes() intersects = indexA.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMapA) writer.addFeature(outFeat) except: # This really shouldn't happen, as we haven't # edited the input geom at all ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) else: for id in intersects: count += 1 request = QgsFeatureRequest().setFilterFid(id) inFeatB = vlayerB.getFeatures(request).next() atMapB = inFeatB.attributes() tmpGeom = QgsGeometry(inFeatB.geometry()) if geom.intersects(tmpGeom): int_geom = geom.intersection(tmpGeom) lstIntersectingB.append(tmpGeom) if int_geom is None: # There was a problem creating the intersection ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('GEOS geoprocessing error: One or more input features have invalid geometry.' )) int_geom = QgsGeometry() else: int_geom = QgsGeometry(int_geom) if int_geom.wkbType( ) == QGis.WKBUnknown or QgsWKBTypes.flatType( int_geom.geometry().wkbType( )) == QgsWKBTypes.GeometryCollection: # Intersection produced different geomety types temp_list = int_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): int_geom = QgsGeometry(i) try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) else: # Geometry list: prevents writing error # in geometries of different types # produced by the intersection # fix #3549 if int_geom.wkbType() in wkbTypeGroups[ wkbTypeGroups[int_geom.wkbType()]]: try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) # the remaining bit of inFeatA's geometry # if there is nothing left, this will just silently fail and we're good diff_geom = QgsGeometry(geom) if len(lstIntersectingB) != 0: intB = QgsGeometry.unaryUnion(lstIntersectingB) diff_geom = diff_geom.difference(intB) if diff_geom.isGeosEmpty() or not diff_geom.isGeosValid(): ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self. tr('GEOS geoprocessing error: One or more input features have invalid geometry.' )) if diff_geom.wkbType() == 0 or QgsWKBTypes.flatType( diff_geom.geometry().wkbType( )) == QgsWKBTypes.GeometryCollection: temp_list = diff_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): diff_geom = QgsGeometry(i) try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMapA) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) length = len(vproviderA.fields()) atMapA = [None] * length featuresA = vector.features(vlayerB) nFeat = len(featuresA) for inFeatA in featuresA: progress.setPercentage(nElement / float(nFeat) * 100) add = False geom = QgsGeometry(inFeatA.geometry()) diff_geom = QgsGeometry(geom) atMap = [None] * length atMap.extend(inFeatA.attributes()) intersects = indexB.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) else: for id in intersects: request = QgsFeatureRequest().setFilterFid(id) inFeatB = vlayerA.getFeatures(request).next() atMapB = inFeatB.attributes() tmpGeom = QgsGeometry(inFeatB.geometry()) if diff_geom.intersects(tmpGeom): add = True diff_geom = QgsGeometry(diff_geom.difference(tmpGeom)) if diff_geom.isGeosEmpty( ) or not diff_geom.isGeosValid(): ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self. tr('GEOS geoprocessing error: One or more input features have invalid geometry.' )) else: try: # Ihis only happends if the bounding box # intersects, but the geometry doesn't outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) if add: try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) nElement += 1 del writer
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) fieldName = self.parameterAsString(parameters, self.FIELD, context) useField = bool(fieldName) field_index = None f = QgsField('value', QVariant.String, '', 255) if useField: field_index = source.fields().lookupField(fieldName) fType = source.fields()[field_index].type() if fType in [QVariant.Int, QVariant.UInt, QVariant.LongLong, QVariant.ULongLong]: f.setType(fType) f.setLength(20) elif fType == QVariant.Double: f.setType(QVariant.Double) f.setLength(20) f.setPrecision(6) else: f.setType(QVariant.String) f.setLength(255) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 20)) fields.append(f) fields.append(QgsField('area', QVariant.Double, '', 20, 6)) fields.append(QgsField('perim', QVariant.Double, '', 20, 6)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Polygon, source.sourceCrs()) outFeat = QgsFeature() outGeom = QgsGeometry() fid = 0 val = None if useField: unique = source.uniqueValues(field_index) current = 0 total = 100.0 / (source.featureCount() * len(unique)) if source.featureCount() else 1 for i in unique: if feedback.isCanceled(): break first = True hull = [] features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([field_index])) for f in features: if feedback.isCanceled(): break idVar = f.attributes()[field_index] if str(idVar).strip() == str(i).strip(): if first: val = idVar first = False inGeom = f.geometry() points = vector.extractPoints(inGeom) hull.extend(points) current += 1 feedback.setProgress(int(current * total)) if len(hull) >= 3: tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull)) try: outGeom = tmpGeom.convexHull() if outGeom: area = outGeom.geometry().area() perim = outGeom.geometry().perimeter() else: area = NULL perim = NULL outFeat.setGeometry(outGeom) outFeat.setAttributes([fid, val, area, perim]) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: raise QgsProcessingException( self.tr('Exception while computing convex hull')) fid += 1 else: hull = [] total = 100.0 / source.featureCount() if source.featureCount() else 1 features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([])) for current, f in enumerate(features): if feedback.isCanceled(): break inGeom = f.geometry() points = vector.extractPoints(inGeom) hull.extend(points) feedback.setProgress(int(current * total)) tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull)) try: outGeom = tmpGeom.convexHull() if outGeom: area = outGeom.geometry().area() perim = outGeom.geometry().perimeter() else: area = NULL perim = NULL outFeat.setGeometry(outGeom) outFeat.setAttributes([0, 'all', area, perim]) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: raise QgsProcessingException( self.tr('Exception while computing convex hull')) return {self.OUTPUT: dest_id}
def processAlgorithm(self, progress): vlayerA = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT)) vlayerB = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT2)) ignoreNull = self.getParameterValue(Intersection.IGNORE_NULL) geomType = QgsWKBTypes.multiType(QGis.fromOldWkbType(vlayerA.wkbType())) fields = vector.combineVectorFields(vlayerA, vlayerB) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, geomType, vlayerA.crs()) outFeat = QgsFeature() index = vector.spatialindex(vlayerB) selectionA = vector.features(vlayerA) total = 100.0 / len(selectionA) if len(selectionA) > 0 else 1 for current, inFeatA in enumerate(selectionA): progress.setPercentage(int(current * total)) geom = inFeatA.geometry() if not geom: if ignoreNull: continue else: raise GeoAlgorithmExecutionException( self.tr('Input layer A contains NULL geometries. ' 'Please check "Ignore NULL geometries" ' 'if you want to run this algorithm anyway.')) if not geom.isGeosValid(): raise GeoAlgorithmExecutionException( self.tr('Input layer A contains invalid geometries ' '(feature {}). Unable to complete intersection ' 'algorithm.'.format(inFeatA.id()))) atMapA = inFeatA.attributes() intersects = index.intersects(geom.boundingBox()) for inFeatB in vlayerB.getFeatures(QgsFeatureRequest().setFilterFids(intersects)): tmpGeom = QgsGeometry(inFeatB.geometry()) if not geom: if ignoreNull: continue else: raise GeoAlgorithmExecutionException( self.tr('Input layer B contains NULL geometries. ' 'Please check "Ignore NULL geometries" ' 'if you want to run this algorithm anyway.')) if not geom.isGeosValid(): raise GeoAlgorithmExecutionException( self.tr('Input layer B contains invalid geometries ' '(feature {}). Unable to complete intersection ' 'algorithm.'.format(inFeatB.id()))) if geom.intersects(tmpGeom): atMapB = inFeatB.attributes() int_geom = QgsGeometry(geom.intersection(tmpGeom)) if int_geom.wkbType() == QGis.WKBUnknown or QgsWKBTypes.flatType(int_geom.geometry().wkbType()) == QgsWKBTypes.GeometryCollection: int_com = geom.combine(tmpGeom) int_geom = QgsGeometry() if int_com is not None: int_sym = geom.symDifference(tmpGeom) if int_sym: diff_geom = int_com.difference(int_sym) int_geom = QgsGeometry(diff_geom) if int_geom.isGeosEmpty() or not int_geom.isGeosValid(): raise GeoAlgorithmExecutionException( self.tr('GEOS geoprocessing error: One or ' 'more input features have invalid ' 'geometry.')) try: if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]: outFeat.setGeometry(int_geom) attrs = [] attrs.extend(atMapA) attrs.extend(atMapB) outFeat.setAttributes(attrs) writer.addFeature(outFeat) except: raise GeoAlgorithmExecutionException( self.tr('Feature geometry error: one or ' 'more output features ignored due ' 'to invalid geometry.')) del writer
def processAlgorithm(self, parameters, context, feedback): vlayerA = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(Union.INPUT), context) vlayerB = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(Union.INPUT2), context) geomType = vlayerA.wkbType() fields = vector.combineFields(vlayerA.fields(), vlayerB.fields()) writer = self.getOutputFromName(Union.OUTPUT).getVectorWriter(fields, geomType, vlayerA.crs(), context) inFeatA = QgsFeature() inFeatB = QgsFeature() outFeat = QgsFeature() indexA = QgsProcessingUtils.createSpatialIndex(vlayerB, context) indexB = QgsProcessingUtils.createSpatialIndex(vlayerA, context) count = 0 nElement = 0 featuresA = QgsProcessingUtils.getFeatures(vlayerA, context) nFeat = QgsProcessingUtils.featureCount(vlayerA, context) for inFeatA in featuresA: feedback.setProgress(nElement / float(nFeat) * 50) nElement += 1 lstIntersectingB = [] geom = inFeatA.geometry() atMapA = inFeatA.attributes() intersects = indexA.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMapA) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) except: # This really shouldn't happen, as we haven't # edited the input geom at all QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'), self.tr('Processing'), QgsMessageLog.INFO) else: request = QgsFeatureRequest().setFilterFids(intersects) engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerB.getFeatures(request): count += 1 atMapB = inFeatB.attributes() tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): int_geom = geom.intersection(tmpGeom) lstIntersectingB.append(tmpGeom) if not int_geom: # There was a problem creating the intersection QgsMessageLog.logMessage(self.tr('GEOS geoprocessing error: One or more input features have invalid geometry.'), self.tr('Processing'), QgsMessageLog.INFO) int_geom = QgsGeometry() else: int_geom = QgsGeometry(int_geom) if int_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(int_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection: # Intersection produced different geomety types temp_list = int_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): int_geom = QgsGeometry(i) try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) except: QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'), self.tr('Processing'), QgsMessageLog.INFO) else: # Geometry list: prevents writing error # in geometries of different types # produced by the intersection # fix #3549 if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]: try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) except: QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'), self.tr('Processing'), QgsMessageLog.INFO) # the remaining bit of inFeatA's geometry # if there is nothing left, this will just silently fail and we're good diff_geom = QgsGeometry(geom) if len(lstIntersectingB) != 0: intB = QgsGeometry.unaryUnion(lstIntersectingB) diff_geom = diff_geom.difference(intB) if diff_geom.wkbType() == 0 or QgsWkbTypes.flatType(diff_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection: temp_list = diff_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): diff_geom = QgsGeometry(i) try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMapA) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) except: QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'), self.tr('Processing'), QgsMessageLog.INFO) length = len(vlayerA.fields()) atMapA = [None] * length featuresA = QgsProcessingUtils.getFeatures(vlayerB, context) nFeat = QgsProcessingUtils.featureCount(vlayerB, context) for inFeatA in featuresA: feedback.setProgress(nElement / float(nFeat) * 100) add = False geom = inFeatA.geometry() diff_geom = QgsGeometry(geom) atMap = [None] * length atMap.extend(inFeatA.attributes()) intersects = indexB.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) except: QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'), self.tr('Processing'), QgsMessageLog.INFO) else: request = QgsFeatureRequest().setFilterFids(intersects) # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(diff_geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerA.getFeatures(request): atMapB = inFeatB.attributes() tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): add = True diff_geom = QgsGeometry(diff_geom.difference(tmpGeom)) else: try: # Ihis only happens if the bounding box # intersects, but the geometry doesn't outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) except: QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'), self.tr('Processing'), QgsMessageLog.INFO) if add: try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) except: QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'), self.tr('Processing'), QgsMessageLog.INFO) nElement += 1 del writer
def processAlgorithm(self, progress): vlayerA = dataobjects.getObjectFromUri(self.getParameterValue(Union.INPUT)) vlayerB = dataobjects.getObjectFromUri(self.getParameterValue(Union.INPUT2)) geomType = vlayerA.wkbType() fields = vector.combineVectorFields(vlayerA, vlayerB) writer = self.getOutputFromName(Union.OUTPUT).getVectorWriter(fields, geomType, vlayerA.crs()) inFeatA = QgsFeature() inFeatB = QgsFeature() outFeat = QgsFeature() indexA = vector.spatialindex(vlayerB) indexB = vector.spatialindex(vlayerA) count = 0 nElement = 0 featuresA = vector.features(vlayerA) nFeat = len(featuresA) for inFeatA in featuresA: progress.setPercentage(nElement / float(nFeat) * 50) nElement += 1 lstIntersectingB = [] geom = inFeatA.geometry() atMapA = inFeatA.attributes() intersects = indexA.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMapA) writer.addFeature(outFeat) except: # This really shouldn't happen, as we haven't # edited the input geom at all ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self.tr("Feature geometry error: One or more output features ignored due to invalid geometry."), ) else: request = QgsFeatureRequest().setFilterFids(intersects) engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerB.getFeatures(request): count += 1 atMapB = inFeatB.attributes() tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): int_geom = geom.intersection(tmpGeom) lstIntersectingB.append(tmpGeom) if not int_geom: # There was a problem creating the intersection ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self.tr("GEOS geoprocessing error: One or more input features have invalid geometry."), ) int_geom = QgsGeometry() else: int_geom = QgsGeometry(int_geom) if ( int_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(int_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection ): # Intersection produced different geomety types temp_list = int_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): int_geom = QgsGeometry(i) try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self.tr( "Feature geometry error: One or more output features ignored due to invalid geometry." ), ) else: # Geometry list: prevents writing error # in geometries of different types # produced by the intersection # fix #3549 if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]: try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self.tr( "Feature geometry error: One or more output features ignored due to invalid geometry." ), ) # the remaining bit of inFeatA's geometry # if there is nothing left, this will just silently fail and we're good diff_geom = QgsGeometry(geom) if len(lstIntersectingB) != 0: intB = QgsGeometry.unaryUnion(lstIntersectingB) diff_geom = diff_geom.difference(intB) if diff_geom.isGeosEmpty() or not diff_geom.isGeosValid(): ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self.tr("GEOS geoprocessing error: One or more input features have invalid geometry."), ) if ( diff_geom.wkbType() == 0 or QgsWkbTypes.flatType(diff_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection ): temp_list = diff_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): diff_geom = QgsGeometry(i) try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMapA) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self.tr("Feature geometry error: One or more output features ignored due to invalid geometry."), ) length = len(vlayerA.fields()) atMapA = [None] * length featuresA = vector.features(vlayerB) nFeat = len(featuresA) for inFeatA in featuresA: progress.setPercentage(nElement / float(nFeat) * 100) add = False geom = inFeatA.geometry() diff_geom = QgsGeometry(geom) atMap = [None] * length atMap.extend(inFeatA.attributes()) intersects = indexB.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self.tr("Feature geometry error: One or more output features ignored due to invalid geometry."), ) else: request = QgsFeatureRequest().setFilterFids(intersects) # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(diff_geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerA.getFeatures(request): atMapB = inFeatB.attributes() tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): add = True diff_geom = QgsGeometry(diff_geom.difference(tmpGeom)) if diff_geom.isGeosEmpty() or not diff_geom.isGeosValid(): ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self.tr("GEOS geoprocessing error: One or more input features have invalid geometry."), ) else: try: # Ihis only happends if the bounding box # intersects, but the geometry doesn't outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self.tr( "Feature geometry error: One or more output features ignored due to invalid geometry." ), ) if add: try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self.tr("Feature geometry error: One or more output features ignored due to invalid geometry."), ) nElement += 1 del writer
def processAlgorithm(self, progress): polyLayer = dataobjects.getObjectFromUri( self.getParameterValue(self.POLYGONS)) pointLayer = dataobjects.getObjectFromUri( self.getParameterValue(self.POINTS)) fieldName = self.getParameterValue(self.FIELD) classFieldName = self.getParameterValue(self.CLASSFIELD) polyProvider = polyLayer.dataProvider() fields = polyProvider.fields() fields.append(QgsField(fieldName, QVariant.Int)) classFieldIndex = pointLayer.fieldNameIndex(classFieldName) (idxCount, fieldList) = vector.findOrCreateField(polyLayer, polyLayer.pendingFields(), fieldName) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields.toList(), polyProvider.geometryType(), polyProvider.crs()) spatialIndex = vector.spatialindex(pointLayer) ftPoint = QgsFeature() outFeat = QgsFeature() geom = QgsGeometry() current = 0 features = vector.features(polyLayer) total = 100.0 / float(len(features)) for ftPoly in features: geom = ftPoly.geometry() engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() attrs = ftPoly.attributes() classes = set() points = spatialIndex.intersects(geom.boundingBox()) if len(points) > 0: request = QgsFeatureRequest().setFilterFids(points) fit = pointLayer.getFeatures(request) ftPoint = QgsFeature() while fit.nextFeature(ftPoint): tmpGeom = QgsGeometry(ftPoint.geometry()) if engine.contains(tmpGeom.geometry()): clazz = ftPoint.attributes()[classFieldIndex] if clazz not in classes: classes.add(clazz) outFeat.setGeometry(geom) if idxCount == len(attrs): attrs.append(len(classes)) else: attrs[idxCount] = len(classes) outFeat.setAttributes(attrs) writer.addFeature(outFeat) current += 1 progress.setPercentage(current / total) del writer
def processAlgorithm(self, progress): vlayerA = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT)) vlayerB = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT2)) geomType = QgsWkbTypes.multiType(vlayerA.wkbType()) fields = vector.combineVectorFields(vlayerA, vlayerB) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, geomType, vlayerA.crs()) outFeat = QgsFeature() index = vector.spatialindex(vlayerB) selectionA = vector.features(vlayerA) total = 100.0 / len(selectionA) for current, inFeatA in enumerate(selectionA): progress.setPercentage(int(current * total)) geom = inFeatA.geometry() atMapA = inFeatA.attributes() intersects = index.intersects(geom.boundingBox()) request = QgsFeatureRequest().setFilterFids(intersects) engine = None if len(intersects) > 0: # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerB.getFeatures(request): tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): atMapB = inFeatB.attributes() int_geom = QgsGeometry(geom.intersection(tmpGeom)) if int_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(int_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection: int_com = geom.combine(tmpGeom) int_geom = QgsGeometry() if int_com: int_sym = geom.symDifference(tmpGeom) int_geom = QgsGeometry(int_com.difference(int_sym)) if int_geom.isGeosEmpty() or not int_geom.isGeosValid(): ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, self.tr('GEOS geoprocessing error: One or ' 'more input features have invalid ' 'geometry.')) try: if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]: outFeat.setGeometry(int_geom) attrs = [] attrs.extend(atMapA) attrs.extend(atMapB) outFeat.setAttributes(attrs) writer.addFeature(outFeat) except: ProcessingLog.addToLog(ProcessingLog.LOG_INFO, self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) continue del writer
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 processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri(self.getParameterValue( self.INPUT)) method = self.getParameterValue(self.METHOD) geometryType = layer.geometryType() fields = layer.fields() export_z = False export_m = False if geometryType == QgsWkbTypes.PolygonGeometry: areaName = vector.createUniqueFieldName('area', fields) fields.append(QgsField(areaName, QVariant.Double)) perimeterName = vector.createUniqueFieldName('perimeter', fields) fields.append(QgsField(perimeterName, QVariant.Double)) elif geometryType == QgsWkbTypes.LineGeometry: lengthName = vector.createUniqueFieldName('length', fields) fields.append(QgsField(lengthName, QVariant.Double)) else: xName = vector.createUniqueFieldName('xcoord', fields) fields.append(QgsField(xName, QVariant.Double)) yName = vector.createUniqueFieldName('ycoord', fields) fields.append(QgsField(yName, QVariant.Double)) if QgsWkbTypes.hasZ(layer.wkbType()): export_z = True zName = vector.createUniqueFieldName('zcoord', fields) fields.append(QgsField(zName, QVariant.Double)) if QgsWkbTypes.hasM(layer.wkbType()): export_m = True zName = vector.createUniqueFieldName('mvalue', fields) fields.append(QgsField(zName, QVariant.Double)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields.toList(), layer.wkbType(), layer.crs()) ellips = None crs = None coordTransform = None # Calculate with: # 0 - layer CRS # 1 - project CRS # 2 - ellipsoidal if method == 2: ellips = QgsProject.instance().readEntry('Measure', '/Ellipsoid', 'NONE')[0] crs = layer.crs().srsid() elif method == 1: mapCRS = iface.mapCanvas().mapSettings().destinationCrs() layCRS = layer.crs() coordTransform = QgsCoordinateTransform(layCRS, mapCRS) outFeat = QgsFeature() inGeom = QgsGeometry() outFeat.initAttributes(len(fields)) outFeat.setFields(fields) features = vector.features(layer) total = 100.0 / len(features) for current, f in enumerate(features): inGeom = f.geometry() if method == 1: inGeom.transform(coordTransform) (attr1, attr2) = vector.simpleMeasure(inGeom, method, ellips, crs) outFeat.setGeometry(inGeom) attrs = f.attributes() attrs.append(attr1) if attr2 is not None: attrs.append(attr2) # add point z/m if export_z: attrs.append(inGeom.geometry().z()) if export_m: attrs.append(inGeom.geometry().m()) outFeat.setAttributes(attrs) writer.addFeature(outFeat) progress.setPercentage(int(current * total)) del writer
def processAlgorithm(self, parameters, context, feedback): polyLayer = QgsProcessingUtils.mapLayerFromString( self.getParameterValue(self.POLYGONS), context) pointLayer = QgsProcessingUtils.mapLayerFromString( self.getParameterValue(self.POINTS), context) fieldName = self.getParameterValue(self.FIELD) classFieldName = self.getParameterValue(self.CLASSFIELD) fields = polyLayer.fields() fields.append(QgsField(fieldName, QVariant.Int)) classFieldIndex = pointLayer.fields().lookupField(classFieldName) (idxCount, fieldList) = vector.findOrCreateField(polyLayer, polyLayer.fields(), fieldName) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, polyLayer.wkbType(), polyLayer.crs(), context) spatialIndex = QgsProcessingUtils.createSpatialIndex( pointLayer, context) ftPoint = QgsFeature() outFeat = QgsFeature() geom = QgsGeometry() features = QgsProcessingUtils.getFeatures(polyLayer, context) total = 100.0 / polyLayer.featureCount() if polyLayer.featureCount( ) else 0 for current, ftPoly in enumerate(features): geom = ftPoly.geometry() engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() attrs = ftPoly.attributes() classes = set() points = spatialIndex.intersects(geom.boundingBox()) if len(points) > 0: request = QgsFeatureRequest().setFilterFids( points).setSubsetOfAttributes([classFieldIndex]) fit = pointLayer.getFeatures(request) ftPoint = QgsFeature() while fit.nextFeature(ftPoint): tmpGeom = QgsGeometry(ftPoint.geometry()) if engine.contains(tmpGeom.geometry()): clazz = ftPoint.attributes()[classFieldIndex] if clazz not in classes: classes.add(clazz) outFeat.setGeometry(geom) if idxCount == len(attrs): attrs.append(len(classes)) else: attrs[idxCount] = len(classes) outFeat.setAttributes(attrs) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) del writer
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT)) method = self.getParameterValue(self.METHOD) geometryType = layer.geometryType() fields = layer.fields() export_z = False export_m = False if geometryType == QgsWkbTypes.PolygonGeometry: areaName = vector.createUniqueFieldName('area', fields) fields.append(QgsField(areaName, QVariant.Double)) perimeterName = vector.createUniqueFieldName('perimeter', fields) fields.append(QgsField(perimeterName, QVariant.Double)) elif geometryType == QgsWkbTypes.LineGeometry: lengthName = vector.createUniqueFieldName('length', fields) fields.append(QgsField(lengthName, QVariant.Double)) else: xName = vector.createUniqueFieldName('xcoord', fields) fields.append(QgsField(xName, QVariant.Double)) yName = vector.createUniqueFieldName('ycoord', fields) fields.append(QgsField(yName, QVariant.Double)) if QgsWkbTypes.hasZ(layer.wkbType()): export_z = True zName = vector.createUniqueFieldName('zcoord', fields) fields.append(QgsField(zName, QVariant.Double)) if QgsWkbTypes.hasM(layer.wkbType()): export_m = True zName = vector.createUniqueFieldName('mvalue', fields) fields.append(QgsField(zName, QVariant.Double)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields.toList(), layer.wkbType(), layer.crs()) ellips = None crs = None coordTransform = None # Calculate with: # 0 - layer CRS # 1 - project CRS # 2 - ellipsoidal if method == 2: ellips = QgsProject.instance().readEntry('Measure', '/Ellipsoid', 'NONE')[0] crs = layer.crs().srsid() elif method == 1: mapCRS = iface.mapCanvas().mapSettings().destinationCrs() layCRS = layer.crs() coordTransform = QgsCoordinateTransform(layCRS, mapCRS) outFeat = QgsFeature() inGeom = QgsGeometry() outFeat.initAttributes(len(fields)) outFeat.setFields(fields) features = vector.features(layer) total = 100.0 / len(features) for current, f in enumerate(features): inGeom = f.geometry() if method == 1: inGeom.transform(coordTransform) (attr1, attr2) = vector.simpleMeasure(inGeom, method, ellips, crs) outFeat.setGeometry(inGeom) attrs = f.attributes() attrs.append(attr1) if attr2 is not None: attrs.append(attr2) # add point z/m if export_z: attrs.append(inGeom.geometry().z()) if export_m: attrs.append(inGeom.geometry().m()) outFeat.setAttributes(attrs) writer.addFeature(outFeat) progress.setPercentage(int(current * total)) del writer
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 processAlgorithm(self, progress): vlayerA = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT)) vlayerB = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT2)) geomType = QgsWkbTypes.multiType(vlayerA.wkbType()) fields = vector.combineVectorFields(vlayerA, vlayerB) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, geomType, vlayerA.crs()) outFeat = QgsFeature() index = vector.spatialindex(vlayerB) selectionA = vector.features(vlayerA) total = 100.0 / len(selectionA) for current, inFeatA in enumerate(selectionA): progress.setPercentage(int(current * total)) geom = inFeatA.geometry() atMapA = inFeatA.attributes() intersects = index.intersects(geom.boundingBox()) request = QgsFeatureRequest().setFilterFids(intersects) engine = None if len(intersects) > 0: # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerB.getFeatures(request): tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): atMapB = inFeatB.attributes() int_geom = QgsGeometry(geom.intersection(tmpGeom)) if int_geom.wkbType( ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType( int_geom.geometry().wkbType( )) == QgsWkbTypes.GeometryCollection: int_com = geom.combine(tmpGeom) int_geom = QgsGeometry() if int_com: int_sym = geom.symDifference(tmpGeom) int_geom = QgsGeometry(int_com.difference(int_sym)) if int_geom.isGeosEmpty() or not int_geom.isGeosValid(): ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self.tr('GEOS geoprocessing error: One or ' 'more input features have invalid ' 'geometry.')) try: if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[ int_geom.wkbType()]]: outFeat.setGeometry(int_geom) attrs = [] attrs.extend(atMapA) attrs.extend(atMapB) outFeat.setAttributes(attrs) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) continue del writer
def processAlgorithm(self, parameters, context, feedback): sourceA = self.parameterAsSource(parameters, self.INPUT, context) sourceB = self.parameterAsSource(parameters, self.OVERLAY, context) geomType = QgsWkbTypes.multiType(sourceA.wkbType()) fields = vector.combineFields(sourceA.fields(), sourceB.fields()) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, geomType, sourceA.sourceCrs()) featA = QgsFeature() featB = QgsFeature() outFeat = QgsFeature() indexA = QgsSpatialIndex(sourceA, feedback) indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())), feedback) total = 100.0 / (sourceA.featureCount() * sourceB.featureCount()) if sourceA.featureCount() and sourceB.featureCount() else 1 count = 0 for featA in sourceA.getFeatures(): if feedback.isCanceled(): break lstIntersectingB = [] geom = featA.geometry() atMapA = featA.attributes() intersects = indexB.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMapA) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: # This really shouldn't happen, as we haven't # edited the input geom at all feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) else: request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([]) request.setDestinationCrs(sourceA.sourceCrs()) engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for featB in sourceB.getFeatures(request): atMapB = featB.attributes() tmpGeom = featB.geometry() if engine.intersects(tmpGeom.geometry()): int_geom = geom.intersection(tmpGeom) lstIntersectingB.append(tmpGeom) if not int_geom: # There was a problem creating the intersection feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) int_geom = QgsGeometry() else: int_geom = QgsGeometry(int_geom) if int_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(int_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection: # Intersection produced different geomety types temp_list = int_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): int_geom = QgsGeometry(i) try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) else: # Geometry list: prevents writing error # in geometries of different types # produced by the intersection # fix #3549 if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]: try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) # the remaining bit of featA's geometry # if there is nothing left, this will just silently fail and we're good diff_geom = QgsGeometry(geom) if len(lstIntersectingB) != 0: intB = QgsGeometry.unaryUnion(lstIntersectingB) diff_geom = diff_geom.difference(intB) if diff_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(diff_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection: temp_list = diff_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): diff_geom = QgsGeometry(i) try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMapA) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) count += 1 feedback.setProgress(int(count * total)) length = len(sourceA.fields()) atMapA = [None] * length for featA in sourceB.getFeatures(QgsFeatureRequest().setDestinationCrs(sourceA.sourceCrs())): if feedback.isCanceled(): break add = False geom = featA.geometry() diff_geom = QgsGeometry(geom) atMap = [None] * length atMap.extend(featA.attributes()) intersects = indexA.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMap) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) else: request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([]) request.setDestinationCrs(sourceA.sourceCrs()) # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(diff_geom.geometry()) engine.prepareGeometry() for featB in sourceA.getFeatures(request): atMapB = featB.attributes() tmpGeom = featB.geometry() if engine.intersects(tmpGeom.geometry()): add = True diff_geom = QgsGeometry(diff_geom.difference(tmpGeom)) else: try: # Ihis only happens if the bounding box # intersects, but the geometry doesn't outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) if add: try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) count += 1 feedback.setProgress(int(count * total)) return {self.OUTPUT: dest_id}
class GeometryHighlightItem(QgsMapCanvasItem): # Code ported from QGIS QgsHighlight def __init__(self, mapCanvas, geometry, layer): super(GeometryHighlightItem, self).__init__(mapCanvas) self._mapCanvas = None # QgsMapCanvas self._geometry = None # QgsGeometry() self._brush = QBrush() self._pen = QPen() self._mapCanvas = mapCanvas if not geometry or not isinstance(geometry, QgsGeometry) or geometry.isEmpty( ) or not geometry.isGeosValid(): return self._geometry = QgsGeometry(geometry) # Force deep copy self.setLineColor(Application.highlightLineColor()) self.setFillColor(Application.highlightFillColor()) if (layer and self._mapCanvas.mapSettings().hasCrsTransformEnabled()): ct = self._mapCanvas.mapSettings().layerTransform(layer) if ct: self._geometry.transform(ct) self.updateRect() self.update() def remove(self): self._mapCanvas.scene().removeItem(self) def setLineWidth(self, width): self._pen.setWidth(width) def setLineColor(self, color): lineColor = QColor(color) lineColor.setAlpha(255) self._pen.setColor(lineColor) def setFillColor(self, fillColor): self._brush.setColor(fillColor) self._brush.setStyle(Qt.SolidPattern) def updatePosition(self): pass # protected: def paint(self, painter, option=None, widget=None): # Override if not self._geometry: return painter.setPen(self._pen) painter.setBrush(self._brush) wkbType = self._geometry.wkbType() if wkbType == QGis.WKBPoint or wkbType == QGis.WKBPoint25D: self._paintPoint(painter, self._geometry.geometry()) elif wkbType == QGis.WKBMultiPoint or wkbType == QGis.WKBMultiPoint25D: for point in self._geometry.geometry(): self._paintPoint(painter, point) elif wkbType == QGis.WKBLineString or wkbType == QGis.WKBLineString25D: self._paintLine(painter, self._geometry.geometry()) elif wkbType == QGis.WKBMultiLineString or wkbType == QGis.WKBMultiLineString25D: for line in self._geometry.geometry(): self._paintLine(painter, line) elif wkbType == QGis.WKBPolygon or wkbType == QGis.WKBPolygon25D: self._paintPolygon(painter, self._geometry.geometry()) elif wkbType == QGis.WKBMultiPolygon or wkbType == QGis.WKBMultiPolygon25D: for polygon in self._geometry.geometry(): self._paintPolygon(painter, polygon) def updateRect(self): if self._geometry: r = self._geometry.boundingBox() if r.isEmpty(): d = self._mapCanvas.extent().width() * 0.005 r.setXMinimum(r.xMinimum() - d) r.setYMinimum(r.yMinimum() - d) r.setXMaximum(r.xMaximum() + d) r.setYMaximum(r.yMaximum() + d) self.setRect(r) self.setVisible(True) else: self.setRect(QgsRectangle()) # private: def _paintPoint(self, painter, point): painter.drawEllipse(self.toCanvasCoordinates(point) - self.pos(), 2, 2) def _paintLine(self, painter, line): polyline = QPolygonF() for point in line: polyline.append(self.toCanvasCoordinates(point) - self.pos()) painter.drawPolyline(polyline) def _paintPolygon(self, painter, polygon): path = QPainterPath() for line in polygon: ring = QPolygonF() for point in line: cur = self.toCanvasCoordinates(point) - self.pos() ring.append(cur) ring.append(ring[0]) path.addPolygon(ring) painter.drawPath(path)