def clip_layers(first_layer_path, second_layer_path): """Clip and resample layers with the reference to the first layer. :param first_layer_path: Path to the first layer path. :type first_layer_path: str :param second_layer_path: Path to the second layer path. :type second_layer_path: str :return: Path to the clipped datasets (clipped 1st layer, clipped 2nd layer). :rtype: tuple(str, str) :raise FileNotFoundError """ base_name, _ = os.path.splitext(first_layer_path) # noinspection PyCallingNonCallable first_layer = QgsRasterLayer(first_layer_path, base_name) base_name, _ = os.path.splitext(second_layer_path) # noinspection PyCallingNonCallable second_layer = QgsRasterLayer(second_layer_path, base_name) # Get the firs_layer extents as an array in EPSG:4326 first_layer_geo_extent = extent_to_geoarray( first_layer.extent(), first_layer.crs()) first_layer_geo_cell_size, _ = get_wgs84_resolution(first_layer) second_layer_geo_cell_size, _ = get_wgs84_resolution(second_layer) if first_layer_geo_cell_size < second_layer_geo_cell_size: cell_size = first_layer_geo_cell_size else: cell_size = second_layer_geo_cell_size clipped_first_layer = clip_layer( layer=first_layer, extent=first_layer_geo_extent, cell_size=cell_size) clipped_second_layer = clip_layer( layer=second_layer, extent=first_layer_geo_extent, cell_size=cell_size) return clipped_first_layer, clipped_second_layer
def calculate_specified_impact(self, function_id, hazard_layer, exposure_layer, output_basename): LOGGER.info('Calculate %s' % function_id) if_manager = ImpactFunctionManager() impact_function = if_manager.get_instance(function_id) impact_function.hazard = hazard_layer extent = impact_function.hazard.extent() hazard_extent = [ extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum() ] # clip exposure if required (if it is too large) if isinstance(exposure_layer, QgsRasterLayer): cell_size, _ = get_wgs84_resolution(exposure_layer) else: cell_size = None clipped_exposure = clip_layer(layer=exposure_layer, extent=hazard_extent, cell_size=cell_size) exposure_layer = clipped_exposure impact_function.exposure = exposure_layer impact_function.requested_extent = hazard_extent impact_function.requested_extent_crs = impact_function.hazard.crs() impact_function.force_memory = True try: impact_function.run_analysis() impact_layer = impact_function.impact if impact_layer: self.set_impact_style(impact_layer) # copy results of impact to report_path directory self.copy_layer(impact_layer, output_basename) except ZeroImpactException as e: # in case zero impact, just return LOGGER.info('No impact detected') LOGGER.info(e.message) return False except Exception as e: LOGGER.info('Calculation error') LOGGER.exception(e) return False LOGGER.info('Calculation completed.') return True
def calculate_specified_impact(self, function_id, hazard_layer, exposure_layer, output_basename): LOGGER.info("Calculate %s" % function_id) if_manager = ImpactFunctionManager() impact_function = if_manager.get_instance(function_id) impact_function.hazard = hazard_layer extent = impact_function.hazard.extent() hazard_extent = [extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum()] # clip exposure if required (if it is too large) if isinstance(exposure_layer, QgsRasterLayer): cell_size, _ = get_wgs84_resolution(exposure_layer) else: cell_size = None clipped_exposure = clip_layer(layer=exposure_layer, extent=hazard_extent, cell_size=cell_size) exposure_layer = clipped_exposure impact_function.exposure = exposure_layer impact_function.requested_extent = hazard_extent impact_function.requested_extent_crs = impact_function.hazard.crs() impact_function.force_memory = True try: impact_function.run_analysis() impact_layer = impact_function.impact if impact_layer: self.set_impact_style(impact_layer) # copy results of impact to report_path directory self.copy_layer(impact_layer, output_basename) except ZeroImpactException as e: # in case zero impact, just return LOGGER.info("No impact detected") LOGGER.info(e.message) return False except Exception as e: LOGGER.info("Calculation error") LOGGER.exception(e) return False LOGGER.info("Calculation completed.") return True
def clip_parameters(self): """Calculate the best extents to use for the assessment. :returns: A dictionary consisting of: * extra_exposure_keywords: dict - any additional keywords that should be written to the exposure layer. For example if rescaling is required for a raster, the original resolution can be added to the keywords file. * adjusted_geo_extent: list - [xmin, ymin, xmax, ymax] - the best extent that can be used given the input datasets and the current viewport extents. * cell_size: float - the cell size that is the best of the hazard and exposure rasters. :rtype: dict, QgsRectangle, float, QgsMapLayer, QgsRectangle, QgsMapLayer :raises: InsufficientOverlapError """ if self._clip_parameters is None: # Get the Hazard extents as an array in EPSG:4326 # noinspection PyTypeChecker hazard_geoextent = extent_to_array(self.hazard.extent(), self.hazard.crs()) # Get the Exposure extents as an array in EPSG:4326 # noinspection PyTypeChecker exposure_geoextent = extent_to_array(self.exposure.extent(), self.exposure.crs()) # Set the analysis extents based on user's desired behaviour settings = QSettings() mode_name = settings.value('inasafe/analysis_extents_mode', 'HazardExposureView') # Default to using canvas extents if no case below matches analysis_geoextent = self.viewport_extent if mode_name == 'HazardExposureView': analysis_geoextent = self.viewport_extent elif mode_name == 'HazardExposure': analysis_geoextent = None elif mode_name == 'HazardExposureBookmark' or \ mode_name == 'HazardExposureBoundingBox': if self.requested_extent is not None \ and self.requested_extent_crs is not None: # User has defined preferred extent, so use that analysis_geoextent = array_to_geo_array( self.requested_extent, self.requested_extent_crs) # Now work out the optimal extent between the two layers and # the current view extent. The optimal extent is the intersection # between the two layers and the viewport. try: # Extent is returned as an array [xmin,ymin,xmax,ymax] # We will convert it to a QgsRectangle afterwards. # If the user has defined a preferred analysis extent it will # always be used, otherwise the data will be clipped to # the viewport unless the user has deselected clip to viewport # in options. geo_extent = get_optimal_extent(hazard_geoextent, exposure_geoextent, analysis_geoextent) except InsufficientOverlapError, e: # noinspection PyTypeChecker message = generate_insufficient_overlap_message( e, exposure_geoextent, self.exposure.qgis_layer(), hazard_geoextent, self.hazard.qgis_layer(), analysis_geoextent) raise InsufficientOverlapError(message) # TODO: move this to its own function # Next work out the ideal spatial resolution for rasters # in the analysis. If layers are not native WGS84, we estimate # this based on the geographic extents # rather than the layers native extents so that we can pass # the ideal WGS84 cell size and extents to the layer prep routines # and do all preprocessing in a single operation. # All this is done in the function getWGS84resolution adjusted_geo_extent = geo_extent cell_size = None extra_exposure_keywords = {} if self.hazard.layer_type() == QgsMapLayer.RasterLayer: # Hazard layer is raster hazard_geo_cell_size, _ = get_wgs84_resolution( self.hazard.qgis_layer()) if self.exposure.layer_type() == QgsMapLayer.RasterLayer: # In case of two raster layers establish common resolution exposure_geo_cell_size, _ = get_wgs84_resolution( self.exposure.qgis_layer()) # See issue #1008 - the flag below is used to indicate # if the user wishes to prevent resampling of exposure data keywords = self.exposure.keywords allow_resampling_flag = True if 'allow_resampling' in keywords: resampling_lower = keywords['allow_resampling'].lower() allow_resampling_flag = resampling_lower == 'true' if hazard_geo_cell_size < exposure_geo_cell_size and \ allow_resampling_flag: cell_size = hazard_geo_cell_size # Adjust the geo extent to coincide with hazard grids # so gdalwarp can do clipping properly adjusted_geo_extent = adjust_clip_extent( geo_extent, get_wgs84_resolution(self.hazard.qgis_layer()), hazard_geoextent) else: cell_size = exposure_geo_cell_size # Adjust extent to coincide with exposure grids # so gdalwarp can do clipping properly adjusted_geo_extent = adjust_clip_extent( geo_extent, get_wgs84_resolution(self.exposure.qgis_layer()), exposure_geoextent) # Record native resolution to allow rescaling of exposure if not numpy.allclose(cell_size, exposure_geo_cell_size): extra_exposure_keywords['resolution'] = \ exposure_geo_cell_size else: if self.exposure.layer_type() != QgsMapLayer.VectorLayer: raise RuntimeError # In here we do not set cell_size so that in # _clip_raster_layer we can perform gdalwarp without # specifying cell size as we still want to have the # original pixel size. # Adjust the geo extent to be at the edge of the pixel in # so gdalwarp can do clipping properly adjusted_geo_extent = adjust_clip_extent( geo_extent, get_wgs84_resolution(self.hazard.qgis_layer()), hazard_geoextent) # If exposure is vector data grow hazard raster layer to # ensure there are enough pixels for points at the edge of # the view port to be interpolated correctly. This requires # resolution to be available adjusted_geo_extent = get_buffered_extent( adjusted_geo_extent, get_wgs84_resolution(self.hazard.qgis_layer())) else: # Hazard layer is vector # In case hazard data is a point data set, we will need to set # the geo_extent to the extent of exposure and the analysis # extent. We check the extent first if the point extent # intersects with geo_extent. if self.hazard.geometry_type() == QGis.Point: user_extent_enabled = (self.requested_extent is not None and self.requested_extent_crs is not None) if user_extent_enabled: # Get intersection between exposure and analysis extent geo_extent = bbox_intersection(exposure_geoextent, analysis_geoextent) # Check if the point is within geo_extent if bbox_intersection(geo_extent, exposure_geoextent) is None: raise InsufficientOverlapError else: geo_extent = exposure_geoextent adjusted_geo_extent = geo_extent if self.exposure.layer_type() == QgsMapLayer.RasterLayer: # Adjust the geo extent to be at the edge of the pixel in # so gdalwarp can do clipping properly adjusted_geo_extent = adjust_clip_extent( geo_extent, get_wgs84_resolution(self.exposure.qgis_layer()), exposure_geoextent) self._clip_parameters = { 'extra_exposure_keywords': extra_exposure_keywords, 'adjusted_geo_extent': adjusted_geo_extent, 'cell_size': cell_size }
def clip_parameters(self): """Calculate the best extents to use for the assessment. :returns: A dictionary consisting of: * extra_exposure_keywords: dict - any additional keywords that should be written to the exposure layer. For example if rescaling is required for a raster, the original resolution can be added to the keywords file. * adjusted_geo_extent: list - [xmin, ymin, xmax, ymax] - the best extent that can be used given the input datasets and the current viewport extents. * cell_size: float - the cell size that is the best of the hazard and exposure rasters. :rtype: dict, QgsRectangle, float, QgsMapLayer, QgsRectangle, QgsMapLayer :raises: InsufficientOverlapError """ if self._clip_parameters is None: # Get the Hazard extents as an array in EPSG:4326 # noinspection PyTypeChecker hazard_geoextent = extent_to_array( self.hazard.extent(), self.hazard.crs()) # Get the Exposure extents as an array in EPSG:4326 # noinspection PyTypeChecker exposure_geoextent = extent_to_array( self.exposure.extent(), self.exposure.crs()) # Set the analysis extents based on user's desired behaviour settings = QSettings() mode_name = settings.value( 'inasafe/analysis_extents_mode', 'HazardExposureView') # Default to using canvas extents if no case below matches analysis_geoextent = self.viewport_extent if mode_name == 'HazardExposureView': analysis_geoextent = self.viewport_extent elif mode_name == 'HazardExposure': analysis_geoextent = None elif mode_name == 'HazardExposureBookmark' or \ mode_name == 'HazardExposureBoundingBox': if self.requested_extent is not None \ and self.requested_extent_crs is not None: # User has defined preferred extent, so use that analysis_geoextent = array_to_geo_array( self.requested_extent, self.requested_extent_crs) # Now work out the optimal extent between the two layers and # the current view extent. The optimal extent is the intersection # between the two layers and the viewport. try: # Extent is returned as an array [xmin,ymin,xmax,ymax] # We will convert it to a QgsRectangle afterwards. # If the user has defined a preferred analysis extent it will # always be used, otherwise the data will be clipped to # the viewport unless the user has deselected clip to viewport # in options. geo_extent = get_optimal_extent( hazard_geoextent, exposure_geoextent, analysis_geoextent) except InsufficientOverlapError, e: # noinspection PyTypeChecker message = generate_insufficient_overlap_message( e, exposure_geoextent, self.exposure.qgis_layer(), hazard_geoextent, self.hazard.qgis_layer(), analysis_geoextent) raise InsufficientOverlapError(message) # TODO: move this to its own function # Next work out the ideal spatial resolution for rasters # in the analysis. If layers are not native WGS84, we estimate # this based on the geographic extents # rather than the layers native extents so that we can pass # the ideal WGS84 cell size and extents to the layer prep routines # and do all preprocessing in a single operation. # All this is done in the function getWGS84resolution adjusted_geo_extent = geo_extent cell_size = None extra_exposure_keywords = {} if self.hazard.layer_type() == QgsMapLayer.RasterLayer: # Hazard layer is raster hazard_geo_cell_size, _ = get_wgs84_resolution( self.hazard.qgis_layer()) if self.exposure.layer_type() == QgsMapLayer.RasterLayer: # In case of two raster layers establish common resolution exposure_geo_cell_size, _ = get_wgs84_resolution( self.exposure.qgis_layer()) # See issue #1008 - the flag below is used to indicate # if the user wishes to prevent resampling of exposure data keywords = self.exposure.keywords allow_resampling_flag = True if 'allow_resampling' in keywords: resampling_lower = keywords['allow_resampling'].lower() allow_resampling_flag = resampling_lower == 'true' if hazard_geo_cell_size < exposure_geo_cell_size and \ allow_resampling_flag: cell_size = hazard_geo_cell_size # Adjust the geo extent to coincide with hazard grids # so gdalwarp can do clipping properly adjusted_geo_extent = adjust_clip_extent( geo_extent, get_wgs84_resolution(self.hazard.qgis_layer()), hazard_geoextent) else: cell_size = exposure_geo_cell_size # Adjust extent to coincide with exposure grids # so gdalwarp can do clipping properly adjusted_geo_extent = adjust_clip_extent( geo_extent, get_wgs84_resolution(self.exposure.qgis_layer()), exposure_geoextent) # Record native resolution to allow rescaling of exposure if not numpy.allclose(cell_size, exposure_geo_cell_size): extra_exposure_keywords['resolution'] = \ exposure_geo_cell_size else: if self.exposure.layer_type() != QgsMapLayer.VectorLayer: raise RuntimeError # In here we do not set cell_size so that in # _clip_raster_layer we can perform gdalwarp without # specifying cell size as we still want to have the # original pixel size. # Adjust the geo extent to be at the edge of the pixel in # so gdalwarp can do clipping properly adjusted_geo_extent = adjust_clip_extent( geo_extent, get_wgs84_resolution(self.hazard.qgis_layer()), hazard_geoextent) # If exposure is vector data grow hazard raster layer to # ensure there are enough pixels for points at the edge of # the view port to be interpolated correctly. This requires # resolution to be available adjusted_geo_extent = get_buffered_extent( adjusted_geo_extent, get_wgs84_resolution(self.hazard.qgis_layer())) else: # Hazard layer is vector # In case hazard data is a point data set, we will need to set # the geo_extent to the extent of exposure and the analysis # extent. We check the extent first if the point extent # intersects with geo_extent. if self.hazard.geometry_type() == QGis.Point: user_extent_enabled = ( self.requested_extent is not None and self.requested_extent_crs is not None) if user_extent_enabled: # Get intersection between exposure and analysis extent geo_extent = bbox_intersection( exposure_geoextent, analysis_geoextent) # Check if the point is within geo_extent if bbox_intersection( geo_extent, exposure_geoextent) is None: raise InsufficientOverlapError else: geo_extent = exposure_geoextent adjusted_geo_extent = geo_extent if self.exposure.layer_type() == QgsMapLayer.RasterLayer: # Adjust the geo extent to be at the edge of the pixel in # so gdalwarp can do clipping properly adjusted_geo_extent = adjust_clip_extent( geo_extent, get_wgs84_resolution(self.exposure.qgis_layer()), exposure_geoextent) self._clip_parameters = { 'extra_exposure_keywords': extra_exposure_keywords, 'adjusted_geo_extent': adjusted_geo_extent, 'cell_size': cell_size }