def union(union_a, union_b): """Union of two vector layers. Issue https://github.com/inasafe/inasafe/issues/3186 :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 :return: The clip vector layer. :rtype: QgsVectorLayer .. versionadded:: 4.0 """ output_layer_name = union_steps['output_layer_name'] output_layer_name = output_layer_name % ( union_a.keywords['layer_purpose'], union_b.keywords['layer_purpose'] ) 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) parameters = {'INPUT': union_a, 'OVERLAY': union_b, 'OUTPUT': 'memory:'} # TODO implement callback through QgsProcessingFeedback object initialize_processing() feedback = create_processing_feedback() context = create_processing_context(feedback=feedback) result = processing.run('native:union', parameters, context=context) if result is None: raise ProcessingInstallationError union_layer = result['OUTPUT'] union_layer.setName(output_layer_name) # use to avoid modifying original source union_layer.keywords = dict(union_a.keywords) union_layer.keywords['inasafe_fields'] = inasafe_fields union_layer.keywords['title'] = output_layer_name union_layer.keywords['layer_purpose'] = 'aggregate_hazard' union_layer.keywords['hazard_keywords'] = keywords_union_1.copy() union_layer.keywords['aggregation_keywords'] = keywords_union_2.copy() fill_hazard_class(union_layer) check_layer(union_layer) return union_layer
def intersection(source, mask): """Intersect two layers. Issue https://github.com/inasafe/inasafe/issues/3186 :param source: The vector layer to clip. :type source: QgsVectorLayer :param mask: The vector layer to use for clipping. :type mask: QgsVectorLayer :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']) parameters = {'INPUT': source, 'OVERLAY': mask, 'OUTPUT': 'memory:'} # TODO implement callback through QgsProcessingFeedback object initialize_processing() feedback = create_processing_feedback() context = create_processing_context(feedback=feedback) result = processing.run('native:intersection', parameters, context=context) if result is None: raise ProcessingInstallationError intersect = result['OUTPUT'] intersect.setName(output_layer_name) intersect.keywords = dict(source.keywords) intersect.keywords['title'] = output_layer_name intersect.keywords['layer_purpose'] = \ layer_purpose_exposure_summary['key'] intersect.keywords['inasafe_fields'] = \ dict(source.keywords['inasafe_fields']) intersect.keywords['inasafe_fields'].update( mask.keywords['inasafe_fields']) intersect.keywords['hazard_keywords'] = \ dict(mask.keywords['hazard_keywords']) intersect.keywords['exposure_keywords'] = dict(source.keywords) intersect.keywords['aggregation_keywords'] = dict( mask.keywords['aggregation_keywords']) check_layer(intersect) return intersect
def intersection(source, mask): """Intersect two layers. Issue https://github.com/inasafe/inasafe/issues/3186 :param source: The vector layer to clip. :type source: QgsVectorLayer :param mask: The vector layer to use for clipping. :type mask: QgsVectorLayer :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']) parameters = {'INPUT': source, 'OVERLAY': mask, 'OUTPUT': 'memory:'} # TODO implement callback through QgsProcessingFeedback object initialize_processing() feedback = create_processing_feedback() context = create_processing_context(feedback=feedback) result = processing.run('native:intersection', parameters, context=context) if result is None: raise ProcessingInstallationError intersect = result['OUTPUT'] intersect.setName(output_layer_name) intersect.keywords = dict(source.keywords) intersect.keywords['title'] = output_layer_name intersect.keywords['layer_purpose'] = \ layer_purpose_exposure_summary['key'] intersect.keywords['inasafe_fields'] = \ dict(source.keywords['inasafe_fields']) intersect.keywords['inasafe_fields'].update( mask.keywords['inasafe_fields']) intersect.keywords['hazard_keywords'] = \ dict(mask.keywords['hazard_keywords']) intersect.keywords['exposure_keywords'] = dict(source.keywords) intersect.keywords['aggregation_keywords'] = dict( mask.keywords['aggregation_keywords']) check_layer(intersect) return intersect
def clean_layer(layer): """Clean a vector layer. :param layer: The vector layer. :type layer: qgis.core.QgsVectorLayer :return: The buffered vector layer. :rtype: qgis.core.QgsVectorLayer """ output_layer_name = clean_geometry_steps['output_layer_name'] output_layer_name = output_layer_name % layer.keywords['layer_purpose'] count = layer.featureCount() parameters = {'INPUT': layer, 'OUTPUT': 'memory:'} initialize_processing() feedback = create_processing_feedback() context = create_processing_context(feedback=feedback) result = processing.run('qgis:fixgeometries', parameters, context=context) if result is None: raise ProcessingInstallationError cleaned = result['OUTPUT'] cleaned.setName(output_layer_name) removed_count = count - cleaned.featureCount() if removed_count: LOGGER.critical( '{removed_count} features have been removed from {layer_name} ' 'because of invalid geometries.'.format( removed_count=removed_count, layer_name=layer.name())) else: LOGGER.info('No feature has been removed from the layer: ' '{layer_name}'.format(layer_name=layer.name())) cleaned.keywords = layer.keywords.copy() cleaned.keywords['title'] = output_layer_name check_layer(cleaned) return cleaned
def clip(layer_to_clip, mask_layer): """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 :return: The clip vector layer. :rtype: QgsVectorLayer .. versionadded:: 4.0 """ output_layer_name = clip_steps['output_layer_name'] output_layer_name = output_layer_name % ( layer_to_clip.keywords['layer_purpose']) parameters = { 'INPUT': layer_to_clip, 'OVERLAY': mask_layer, 'OUTPUT': 'memory:' } # TODO implement callback through QgsProcessingFeedback object initialize_processing() feedback = create_processing_feedback() context = create_processing_context(feedback=feedback) result = processing.run('native:clip', parameters, context=context) if result is None: raise ProcessingInstallationError clipped = result['OUTPUT'] clipped.setName(output_layer_name) clipped.keywords = layer_to_clip.keywords.copy() clipped.keywords['title'] = output_layer_name check_layer(clipped) return clipped
def clip_by_extent(layer, extent): """Clip a raster using a bounding box using processing. Issue https://github.com/inasafe/inasafe/issues/3183 :param layer: The layer to clip. :type layer: QgsRasterLayer :param extent: The extent. :type extent: QgsRectangle :return: Clipped layer. :rtype: QgsRasterLayer .. versionadded:: 4.0 """ parameters = dict() # noinspection PyBroadException try: output_layer_name = quick_clip_steps['output_layer_name'] output_layer_name = output_layer_name % layer.keywords['layer_purpose'] output_raster = unique_filename(suffix='.tif', dir=temp_dir()) # We make one pixel size buffer on the extent to cover every pixels. # See https://github.com/inasafe/inasafe/issues/3655 pixel_size_x = layer.rasterUnitsPerPixelX() pixel_size_y = layer.rasterUnitsPerPixelY() buffer_size = max(pixel_size_x, pixel_size_y) extent = extent.buffered(buffer_size) if is_raster_y_inverted(layer): # The raster is Y inverted. We need to switch Y min and Y max. bbox = [ str(extent.xMinimum()), str(extent.xMaximum()), str(extent.yMaximum()), str(extent.yMinimum()) ] else: # The raster is normal. bbox = [ str(extent.xMinimum()), str(extent.xMaximum()), str(extent.yMinimum()), str(extent.yMaximum()) ] # These values are all from the processing algorithm. # https://github.com/qgis/QGIS/blob/master/python/plugins/processing/ # algs/gdal/ClipByExtent.py # Please read the file to know these parameters. parameters['INPUT'] = layer.source() parameters['NO_DATA'] = '' parameters['PROJWIN'] = ','.join(bbox) parameters['DATA_TYPE'] = 5 parameters['COMPRESS'] = 4 parameters['JPEGCOMPRESSION'] = 75 parameters['ZLEVEL'] = 6 parameters['PREDICTOR'] = 1 parameters['TILED'] = False parameters['BIGTIFF'] = 0 parameters['TFW'] = False parameters['EXTRA'] = '' parameters['OUTPUT'] = output_raster initialize_processing() feedback = create_processing_feedback() context = create_processing_context(feedback=feedback) result = processing.run( "gdal:cliprasterbyextent", parameters, context=context) if result is None: raise ProcessingInstallationError clipped = QgsRasterLayer(result['OUTPUT'], output_layer_name) # We transfer keywords to the output. clipped.keywords = layer.keywords.copy() clipped.keywords['title'] = output_layer_name check_layer(clipped) except Exception as e: # This step clip_raster_by_extent was nice to speedup the analysis. # As we got an exception because the layer is invalid, we are not going # to stop the analysis. We will return the original raster layer. # It will take more processing time until we clip the vector layer. # Check https://github.com/inasafe/inasafe/issues/4026 why we got some # exceptions with this step. LOGGER.exception(parameters) LOGGER.exception( 'Error from QGIS clip raster by extent. Please check the QGIS ' 'logs too !') LOGGER.info( 'Even if we got an exception, we are continuing the analysis. The ' 'layer was not clipped.') LOGGER.exception(str(e)) LOGGER.exception(get_error_message(e).to_text()) clipped = layer return clipped
def clip_by_extent(layer, extent): """Clip a raster using a bounding box using processing. Issue https://github.com/inasafe/inasafe/issues/3183 :param layer: The layer to clip. :type layer: QgsRasterLayer :param extent: The extent. :type extent: QgsRectangle :return: Clipped layer. :rtype: QgsRasterLayer .. versionadded:: 4.0 """ parameters = dict() # noinspection PyBroadException try: output_layer_name = quick_clip_steps['output_layer_name'] output_layer_name = output_layer_name % layer.keywords['layer_purpose'] output_raster = unique_filename(suffix='.tif', dir=temp_dir()) # We make one pixel size buffer on the extent to cover every pixels. # See https://github.com/inasafe/inasafe/issues/3655 pixel_size_x = layer.rasterUnitsPerPixelX() pixel_size_y = layer.rasterUnitsPerPixelY() buffer_size = max(pixel_size_x, pixel_size_y) extent = extent.buffered(buffer_size) if is_raster_y_inverted(layer): # The raster is Y inverted. We need to switch Y min and Y max. bbox = [ str(extent.xMinimum()), str(extent.xMaximum()), str(extent.yMaximum()), str(extent.yMinimum()) ] else: # The raster is normal. bbox = [ str(extent.xMinimum()), str(extent.xMaximum()), str(extent.yMinimum()), str(extent.yMaximum()) ] # These values are all from the processing algorithm. # https://github.com/qgis/QGIS/blob/master/python/plugins/processing/ # algs/gdal/ClipByExtent.py # Please read the file to know these parameters. parameters['INPUT'] = layer.source() parameters['NO_DATA'] = '' parameters['PROJWIN'] = ','.join(bbox) parameters['DATA_TYPE'] = 5 parameters['COMPRESS'] = 4 parameters['JPEGCOMPRESSION'] = 75 parameters['ZLEVEL'] = 6 parameters['PREDICTOR'] = 1 parameters['TILED'] = False parameters['BIGTIFF'] = 0 parameters['TFW'] = False parameters['EXTRA'] = '' parameters['OUTPUT'] = output_raster initialize_processing() feedback = create_processing_feedback() context = create_processing_context(feedback=feedback) result = processing.run("gdal:cliprasterbyextent", parameters, context=context) if result is None: raise ProcessingInstallationError clipped = QgsRasterLayer(result['OUTPUT'], output_layer_name) # We transfer keywords to the output. clipped.keywords = layer.keywords.copy() clipped.keywords['title'] = output_layer_name check_layer(clipped) except Exception as e: # This step clip_raster_by_extent was nice to speedup the analysis. # As we got an exception because the layer is invalid, we are not going # to stop the analysis. We will return the original raster layer. # It will take more processing time until we clip the vector layer. # Check https://github.com/inasafe/inasafe/issues/4026 why we got some # exceptions with this step. LOGGER.exception(parameters) LOGGER.exception( 'Error from QGIS clip raster by extent. Please check the QGIS ' 'logs too !') LOGGER.info( 'Even if we got an exception, we are continuing the analysis. The ' 'layer was not clipped.') LOGGER.exception(str(e)) LOGGER.exception(get_error_message(e).to_text()) clipped = layer return clipped