Пример #1
0
    def test_stacktrace_html(self):
        """Stack traces can be caught and rendered as html
        """

        # This is about general exception handling, so ok to use catch-all
        # pylint: disable=W0703
        try:
            bbox_intersection('aoeu', 'oaeu', [])
        except Exception, e:
            # Display message and traceback

            message = get_error_message(e)
            # print message
            message = message.to_text()
            self.assertIn(str(e), message)
            self.assertIn('line', message)
            self.assertIn('file', message)

            message = get_error_message(e)
            message = message.to_html()
            assert str(e) in message

            message = message.decode('string_escape')
            control_file_path = test_data_path(
                'control',
                'files',
                'test-stacktrace-html.txt')
            expected_results = open(control_file_path).read().replace('\n', '')
            self.assertIn(expected_results, message)
Пример #2
0
    def test_stacktrace_html(self):
        """Stack traces can be caught and rendered as html
        """

        # This is about general exception handling, so ok to use catch-all
        # pylint: disable=W0703
        try:
            bbox_intersection('aoeu', 'oaeu', [])
        except Exception, e:
            # Display message and traceback

            message = get_error_message(e)
            # print message
            message = message.to_text()
            self.assertIn(str(e), message)
            self.assertIn('line', message)
            self.assertIn('file', message)

            message = get_error_message(e)
            message = message.to_html()
            assert str(e) in message

            message = message.decode('string_escape')
            control_file_path = test_data_path(
                'control',
                'files',
                'test-stacktrace-html.txt')
            expected_results = open(control_file_path).read().replace('\n', '')
            self.assertIn(expected_results, message)
Пример #3
0
 def test_issue157(self):
     """Verify that we get the error class name back - issue #157
        .. seealso:: https://github.com/AIFDR/inasafe/issues/121
     """
     try:
         bbox_intersection('aoeu', 'oaeu', [])
     except BoundingBoxError, e:
         message = get_error_message(e)
         myString = 'BoundingBoxError'
         assert myString in message.to_text(), message
         myString = 'Western boundary'
         assert myString in message.to_text(), message
Пример #4
0
 def test_issue157(self):
     """Verify that we get the error class name back - issue #157
        .. seealso:: https://github.com/AIFDR/inasafe/issues/121
     """
     try:
         bbox_intersection('aoeu', 'oaeu', [])
     except BoundingBoxError, e:
         message = get_error_message(e)
         myString = 'BoundingBoxError'
         assert myString in message.to_text(), message
         myString = 'Western boundary'
         assert myString in message.to_text(), message
Пример #5
0
    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
            }
Пример #6
0
def get_optimal_extent(hazard_geo_extent,
                       exposure_geo_extent,
                       viewport_geo_extent=None):
    """A helper function to determine what the optimal extent is.

    Optimal extent should be considered as the intersection between
    the three inputs. The inasafe library will perform various checks
    to ensure that the extent is tenable, includes data from both
    etc.

    This is a thin wrapper around safe.storage.utilities.bbox_intersection

    Typically the result of this function will be used to clip
    input layers to a common extent before processing.

    :param hazard_geo_extent: An array representing the hazard layer
        extents in the form [xmin, ymin, xmax, ymax]. It is assumed that
        the coordinates are in EPSG:4326 although currently no checks are
        made to enforce this.
    :type hazard_geo_extent: list

    :param exposure_geo_extent: An array representing the exposure layer
        extents in the form [xmin, ymin, xmax, ymax]. It is assumed that
        the coordinates are in EPSG:4326 although currently no checks are
        made to enforce this.
    :type exposure_geo_extent: list

    :param viewport_geo_extent: (optional) An array representing the
        viewport extents in the form [xmin, ymin, xmax, ymax]. It is
        assumed that the coordinates are in EPSG:4326 although currently
        no checks are made to enforce this.

        ..note:: We do minimal checking as the inasafe library takes care
        of it for us.

    :returns: An array containing an extent in the form
        [xmin, ymin, xmax, ymax]
        e.g.::
        [100.03, -1.14, 100.81, -0.73]
    :rtype: list

    :raises: Any exceptions raised by the InaSAFE library will be
        propagated.
    """

    message = tr(
        'theHazardGeoExtent or theExposureGeoExtent cannot be None.Found: '
        '/ntheHazardGeoExtent: %s /ntheExposureGeoExtent: %s' %
        (hazard_geo_extent, exposure_geo_extent))

    if (hazard_geo_extent is None) or (exposure_geo_extent is None):
        raise BoundingBoxError(message)

    # .. note:: The bbox_intersection function below assumes that
    # all inputs are in EPSG:4326
    optimal_extent = bbox_intersection(hazard_geo_extent, exposure_geo_extent,
                                       viewport_geo_extent)

    if optimal_extent is None:
        # Bounding boxes did not overlap
        message = tr(
            'Bounding boxes of hazard data, exposure data and viewport '
            'did not overlap, so no computation was done. Please make '
            'sure you pan to where the data is and that hazard and '
            'exposure data overlaps.')
        raise InsufficientOverlapError(message)

    return optimal_extent
Пример #7
0
def get_optimal_extent(
        hazard_geo_extent, exposure_geo_extent, viewport_geo_extent=None):
    """A helper function to determine what the optimal extent is.

    Optimal extent should be considered as the intersection between
    the three inputs. The inasafe library will perform various checks
    to ensure that the extent is tenable, includes data from both
    etc.

    This is a thin wrapper around safe.storage.utilities.bbox_intersection

    Typically the result of this function will be used to clip
    input layers to a common extent before processing.

    :param hazard_geo_extent: An array representing the hazard layer
        extents in the form [xmin, ymin, xmax, ymax]. It is assumed that
        the coordinates are in EPSG:4326 although currently no checks are
        made to enforce this.
    :type hazard_geo_extent: list

    :param exposure_geo_extent: An array representing the exposure layer
        extents in the form [xmin, ymin, xmax, ymax]. It is assumed that
        the coordinates are in EPSG:4326 although currently no checks are
        made to enforce this.
    :type exposure_geo_extent: list

    :param viewport_geo_extent: (optional) An array representing the
        viewport extents in the form [xmin, ymin, xmax, ymax]. It is
        assumed that the coordinates are in EPSG:4326 although currently
        no checks are made to enforce this.

        ..note:: We do minimal checking as the inasafe library takes care
        of it for us.

    :returns: An array containing an extent in the form
        [xmin, ymin, xmax, ymax]
        e.g.::
        [100.03, -1.14, 100.81, -0.73]
    :rtype: list

    :raises: Any exceptions raised by the InaSAFE library will be
        propagated.
    """

    message = tr(
        'theHazardGeoExtent or theExposureGeoExtent cannot be None.Found: '
        '/ntheHazardGeoExtent: %s /ntheExposureGeoExtent: %s' %
        (hazard_geo_extent, exposure_geo_extent))

    if (hazard_geo_extent is None) or (exposure_geo_extent is None):
        raise BoundingBoxError(message)

    # .. note:: The bbox_intersection function below assumes that
    # all inputs are in EPSG:4326
    optimal_extent = bbox_intersection(
        hazard_geo_extent, exposure_geo_extent, viewport_geo_extent)

    if optimal_extent is None:
        # Bounding boxes did not overlap
        message = tr(
            'Bounding boxes of hazard data, exposure data and viewport '
            'did not overlap, so no computation was done. Please make '
            'sure you pan to where the data is and that hazard and '
            'exposure data overlaps.')
        raise InsufficientOverlapError(message)

    return optimal_extent
Пример #8
0
    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
            }