Exemple #1
0
    def test_write_read_iso_19115_metadata(self):
        """Test for write_read_iso_19115_metadata."""
        keywords = {
            # 'date': '26-03-2015 14:03',
            'exposure': 'structure',
            'keyword_version': inasafe_keyword_version,
            'layer_geometry': 'polygon',
            'layer_mode': 'classified',
            'layer_purpose': 'exposure',
            'license': 'Open Data Commons Open Database License (ODbL)',
            'source': 'OpenStreetMap - www.openstreetmap.org',
            'title': 'Buildings',
            'inasafe_fields': {
                'youth_count_field': [
                    'POP_F_0-4', 'POP_F_5-6', 'POP_F_7-12',
                ]
            }
        }
        layer = clone_shp_layer(
            name='buildings',
            include_keywords=False,
            source_directory=standard_data_path('exposure'))
        write_iso19115_metadata(layer.source(), keywords)

        read_metadata = read_iso19115_metadata(layer.source())
        self.assertDictEqual(keywords, read_metadata)
Exemple #2
0
    def read_from_qgis_native(self, qgis_layer):
        """Read raster data from qgis layer QgsRasterLayer.

            A stub is used now:
                save all data in a file,
                then call safe.read_from_file

            Raises:
                * TypeError         if qgis is not avialable
                * IOError           if can't store temporary file
                * GetDataError      if can't create copy of qgis_layer's
                                        dataProvider
        """
        base_name = unique_filename()
        file_name = base_name + '.tif'

        file_writer = QgsRasterFileWriter(file_name)
        pipe = QgsRasterPipe()
        provider = qgis_layer.dataProvider()
        if not pipe.set(provider.clone()):
            msg = "Cannot set pipe provider"
            raise GetDataError(msg)

        file_writer.writeRaster(
            pipe,
            provider.xSize(),
            provider.ySize(),
            provider.extent(),
            provider.crs())

        # Write keywords if any
        write_iso19115_metadata(file_name, self.keywords)
        self.read_from_file(file_name)
Exemple #3
0
    def read_from_qgis_native(self, qgis_layer):
        """Read raster data from qgis layer QgsRasterLayer.

            A stub is used now:
                save all data in a file,
                then call safe.read_from_file

            Raises:
                * TypeError         if qgis is not avialable
                * IOError           if can't store temporary file
                * GetDataError      if can't create copy of qgis_layer's
                                        dataProvider
        """
        base_name = unique_filename()
        file_name = base_name + '.tif'

        file_writer = QgsRasterFileWriter(file_name)
        pipe = QgsRasterPipe()
        provider = qgis_layer.dataProvider()
        if not pipe.set(provider.clone()):
            msg = "Cannot set pipe provider"
            raise GetDataError(msg)

        file_writer.writeRaster(
            pipe,
            provider.xSize(),
            provider.ySize(),
            provider.extent(),
            provider.crs())

        # Write keywords if any
        write_iso19115_metadata(file_name, self.keywords)
        self.read_from_file(file_name)
Exemple #4
0
    def test_read_iso19115_metadata(self):
        """Test for read_iso19115_metadata method."""
        exposure_layer = clone_shp_layer(
            name='buildings',
            include_keywords=False,
            source_directory=standard_data_path('exposure'))
        keywords = {
            # 'date': '26-03-2015 14:03',
            'exposure': 'structure',
            'keyword_version': inasafe_keyword_version,
            'layer_geometry': 'polygon',
            'layer_mode': 'classified',
            'layer_purpose': 'exposure',
            'license': 'Open Data Commons Open Database License (ODbL)',
            'source': 'OpenStreetMap - www.openstreetmap.org',
            'title': 'Buildings'
        }
        write_iso19115_metadata(exposure_layer.source(), keywords)

        read_metadata = read_iso19115_metadata(exposure_layer.source())

        for key in set(keywords.keys()) & set(read_metadata.keys()):
            self.assertEqual(read_metadata[key], keywords[key])
        for key in set(keywords.keys()) - set(read_metadata.keys()):
            message = 'key %s is not found in ISO metadata' % key
            self.assertEqual(read_metadata[key], keywords[key], message)
        for key in set(read_metadata.keys()) - set(keywords.keys()):
            message = 'key %s is not found in old keywords' % key
            self.assertEqual(read_metadata[key], keywords[key], message)
Exemple #5
0
    def read_from_qgis_native(self, qgis_layer):
        """Read and unpack vector data from qgis layer QgsVectorLayer.

            A stub is used now:
                save all data in a file,
                then call safe.read_from_file

            Raises:
                * TypeError         if qgis is not avialable
                * IOError           if can't store temporary file
        """
        # FIXME (DK): this branch isn't covered by test
        if not QGIS_IS_AVAILABLE:
            msg = ('Used data is QgsVectorLayer instance, '
                   'but QGIS is not available.')
            raise TypeError(msg)

        base_name = unique_filename()
        file_name = base_name + '.shp'
        error = QgsVectorFileWriter.writeAsVectorFormat(
            qgis_layer, file_name, "UTF8", qgis_layer.crs(), "ESRI Shapefile")
        if error != QgsVectorFileWriter.NoError:
            # FIXME (DK): this branch isn't covered by test
            msg = ('Can not save data in temporary file.')
            raise IOError(msg)

        # Write keywords if any
        # write_keywords(self.keywords, base_name + '.keywords')
        write_iso19115_metadata(file_name, self.keywords)
        self.read_from_file(file_name)
Exemple #6
0
    def read_from_qgis_native(self, qgis_layer):
        """Read and unpack vector data from qgis layer QgsVectorLayer.

            A stub is used now:
                save all data in a file,
                then call safe.read_from_file

            Raises:
                * TypeError         if qgis is not avialable
                * IOError           if can't store temporary file
        """
        # FIXME (DK): this branch isn't covered by test
        if not QGIS_IS_AVAILABLE:
            msg = ('Used data is QgsVectorLayer instance, '
                   'but QGIS is not available.')
            raise TypeError(msg)

        base_name = unique_filename()
        file_name = base_name + '.shp'
        error = QgsVectorFileWriter.writeAsVectorFormat(
            qgis_layer,
            file_name,
            "UTF8",
            qgis_layer.crs(),
            "ESRI Shapefile"
        )
        if error != QgsVectorFileWriter.NoError:
            # FIXME (DK): this branch isn't covered by test
            msg = ('Can not save data in temporary file.')
            raise IOError(msg)

        # Write keywords if any
        # write_keywords(self.keywords, base_name + '.keywords')
        write_iso19115_metadata(file_name, self.keywords)
        self.read_from_file(file_name)
Exemple #7
0
    def test_read_iso19115_metadata(self):
        """Test for read_iso19115_metadata method."""
        exposure_layer = clone_shp_layer(
            name='buildings',
            include_keywords=False,
            source_directory=standard_data_path('exposure'))
        keywords = {
            # 'date': '26-03-2015 14:03',
            'exposure': 'structure',
            'keyword_version': inasafe_keyword_version,
            'layer_geometry': 'polygon',
            'layer_mode': 'classified',
            'layer_purpose': 'exposure',
            'license': 'Open Data Commons Open Database License (ODbL)',
            'source': 'OpenStreetMap - www.openstreetmap.org',
            'title': 'Buildings'
        }
        write_iso19115_metadata(exposure_layer.source(), keywords)

        read_metadata = read_iso19115_metadata(exposure_layer.source())

        for key in set(keywords.keys()) & set(read_metadata.keys()):
            self.assertEqual(read_metadata[key], keywords[key])
        for key in set(keywords.keys()) - set(read_metadata.keys()):
            message = 'key %s is not found in ISO metadata' % key
            self.assertEqual(read_metadata[key], keywords[key], message)
        for key in set(read_metadata.keys()) - set(keywords.keys()):
            message = 'key %s is not found in old keywords' % key
            self.assertEqual(read_metadata[key], keywords[key], message)
Exemple #8
0
    def test_write_read_iso_19115_metadata(self):
        """Test for write_read_iso_19115_metadata."""
        keywords = {
            # 'date': '26-03-2015 14:03',
            'exposure': 'structure',
            'keyword_version': inasafe_keyword_version,
            'layer_geometry': 'polygon',
            'layer_mode': 'classified',
            'layer_purpose': 'exposure',
            'license': 'Open Data Commons Open Database License (ODbL)',
            'source': 'OpenStreetMap - www.openstreetmap.org',
            'title': 'Buildings',
            'inasafe_fields': {
                'youth_count_field': [
                    'POP_F_0-4',
                    'POP_F_5-6',
                    'POP_F_7-12',
                ]
            }
        }
        layer = clone_shp_layer(
            name='buildings',
            include_keywords=False,
            source_directory=standard_data_path('exposure'))
        write_iso19115_metadata(layer.source(), keywords)

        read_metadata = read_iso19115_metadata(layer.source())
        self.assertDictEqual(keywords, read_metadata)
    def convert_metadata(self):
        """Method invoked when OK button is clicked."""
        # Converter parameter
        converter_parameter = {}
        # Target exposure
        if self.target_exposure_combo_box.isEnabled():
            exposure_index = self.target_exposure_combo_box.currentIndex()
            exposure_key = self.target_exposure_combo_box.itemData(
                exposure_index, Qt.UserRole)
            converter_parameter['exposure'] = exposure_key

        # Metadata
        current_metadata = self.keyword_io.read_keywords(self.layer)
        old_metadata = convert_metadata(current_metadata,
                                        **converter_parameter)

        # Input
        input_layer_path = self.layer.source()
        input_directory_path = os.path.dirname(input_layer_path)
        input_file_name = os.path.basename(input_layer_path)
        input_base_name = os.path.splitext(input_file_name)[0]
        input_extension = os.path.splitext(input_file_name)[1]

        # Output
        output_path = self.output_path_line_edit.text()
        output_directory_path = os.path.dirname(output_path)
        output_file_name = os.path.basename(output_path)
        output_base_name = os.path.splitext(output_file_name)[0]

        # Copy all related files, if exists
        extensions = [
            # Vector layer
            '.shp',
            '.geojson',
            '.qml',
            '.shx',
            '.dbf',
            '.prj',
            'qpj',
            # Raster layer
            '.tif',
            '.tiff',
            '.asc',
        ]
        for extension in extensions:
            source_path = os.path.join(input_directory_path,
                                       input_base_name + extension)
            if not os.path.exists(source_path):
                continue
            target_path = os.path.join(output_directory_path,
                                       output_base_name + extension)
            QFile.copy(source_path, target_path)

        # Replace the metadata with the old one
        output_file_path = os.path.join(output_directory_path,
                                        output_base_name + input_extension)
        write_iso19115_metadata(output_file_path,
                                old_metadata,
                                version_35=True)
Exemple #10
0
    def copy_keywords(
            self,
            source_layer,
            destination_file,
            extra_keywords=None):
        """Helper to copy the keywords file from a source to a target dataset.

        e.g.::

            copyKeywords('foo.shp', 'bar.shp')

        Will result in the foo.keywords file being copied to bar.keyword.

        Optional argument extraKeywords is a dictionary with additional
        keywords that will be added to the destination file e.g::

            copyKeywords('foo.shp', 'bar.shp', {'resolution': 0.01})

        :param source_layer: A QGIS QgsMapLayer instance.
        :type source_layer: QgsMapLayer

        :param destination_file: The output filename that should be used
            to store the keywords in. It's a path to a layer file.
        :type destination_file: str

        :param extra_keywords: A dict containing all the extra keywords
            to be written for the layer. The written keywords will consist of
            any original keywords from the source layer's keywords file and
            and the extra keywords (which will replace the source layers
            keywords if the key is identical).
        :type extra_keywords: dict

        """
        keywords = self.read_keywords(source_layer)
        if extra_keywords is None:
            extra_keywords = {}
        message = self.tr(
            'Expected extra keywords to be a dictionary. Got '
            '%s' % str(type(extra_keywords))[1:-1])
        verify(isinstance(extra_keywords, dict), message)
        # compute the output keywords file name
        destination_base = os.path.splitext(destination_file)[0]
        new_destination = destination_base + '.xml'
        # write the extra keywords into the source dict
        try:
            for key in extra_keywords:
                keywords[key] = extra_keywords[key]
            write_iso19115_metadata(destination_file, keywords)
            # write_keywords_to_file(new_destination, keywords)
        except Exception, e:
            message = self.tr(
                'Failed to copy keywords file from : \n%s\nto\n%s: %s' % (
                    source_layer.source(), new_destination, str(e)))
            raise Exception(message)
Exemple #11
0
    def copy_keywords(
            self,
            source_layer,
            destination_file,
            extra_keywords=None):
        """Helper to copy the keywords file from a source to a target dataset.

        e.g.::

            copyKeywords('foo.shp', 'bar.shp')

        Will result in the foo.keywords file being copied to bar.keyword.

        Optional argument extraKeywords is a dictionary with additional
        keywords that will be added to the destination file e.g::

            copyKeywords('foo.shp', 'bar.shp', {'resolution': 0.01})

        :param source_layer: A QGIS QgsMapLayer instance.
        :type source_layer: QgsMapLayer

        :param destination_file: The output filename that should be used
            to store the keywords in. It's a path to a layer file.
        :type destination_file: str

        :param extra_keywords: A dict containing all the extra keywords
            to be written for the layer. The written keywords will consist of
            any original keywords from the source layer's keywords file and
            and the extra keywords (which will replace the source layers
            keywords if the key is identical).
        :type extra_keywords: dict

        """
        keywords = self.read_keywords(source_layer)
        if extra_keywords is None:
            extra_keywords = {}
        message = self.tr(
            'Expected extra keywords to be a dictionary. Got '
            '%s' % str(type(extra_keywords))[1:-1])
        verify(isinstance(extra_keywords, dict), message)
        # compute the output keywords file name
        destination_base = os.path.splitext(destination_file)[0]
        new_destination = destination_base + '.xml'
        # write the extra keywords into the source dict
        try:
            for key in extra_keywords:
                keywords[key] = extra_keywords[key]
            write_iso19115_metadata(destination_file, keywords)
            # write_keywords_to_file(new_destination, keywords)
        except Exception, e:
            message = self.tr(
                'Failed to copy keywords file from : \n%s\nto\n%s: %s' % (
                    source_layer.source(), new_destination, str(e)))
            raise Exception(message)
    def convert_metadata(self):
        """Method invoked when OK button is clicked."""
        # Converter parameter
        converter_parameter = {}
        # Target exposure
        if self.target_exposure_combo_box.isEnabled():
            exposure_index = self.target_exposure_combo_box.currentIndex()
            exposure_key = self.target_exposure_combo_box.itemData(
                exposure_index, Qt.UserRole)
            converter_parameter['exposure'] = exposure_key

        # Metadata
        current_metadata = self.keyword_io.read_keywords(self.layer)
        old_metadata = convert_metadata(
            current_metadata, **converter_parameter)

        # Input
        input_layer_path = self.layer.source()
        input_directory_path = os.path.dirname(input_layer_path)
        input_file_name = os.path.basename(input_layer_path)
        input_base_name = os.path.splitext(input_file_name)[0]
        input_extension = os.path.splitext(input_file_name)[1]

        # Output
        output_path = self.output_path_line_edit.text()
        output_directory_path = os.path.dirname(output_path)
        output_file_name = os.path.basename(output_path)
        output_base_name = os.path.splitext(output_file_name)[0]

        # Copy all related files, if exists
        extensions = [
            # Vector layer
            '.shp', '.geojson', '.qml', '.shx', '.dbf', '.prj', 'qpj',
            # Raster layer
            '.tif', '.tiff', '.asc',
        ]
        for extension in extensions:
            source_path = os.path.join(
                input_directory_path, input_base_name + extension)
            if not os.path.exists(source_path):
                continue
            target_path = os.path.join(
                output_directory_path, output_base_name + extension)
            QFile.copy(source_path, target_path)

        # Replace the metadata with the old one
        output_file_path = os.path.join(
            output_directory_path, output_base_name + input_extension
        )
        write_iso19115_metadata(
            output_file_path, old_metadata, version_35=True)
Exemple #13
0
    def write_to_file(self, filename):
        """Save raster data to file

        Args:
            * filename: filename with extension .tif

        Gdal documentation at: http://www.gdal.org/classGDALRasterBand.html
        """

        # Check file format
        basename, extension = os.path.splitext(filename)

        msg = ('Invalid file type for file %s. Only extension '
               'tif allowed.' % filename)
        verify(extension in ['.tif'], msg)
        file_format = DRIVER_MAP[extension]

        # Get raster data
        A = self.get_data()

        # Get Dimensions. Note numpy and Gdal swap order
        N, M = A.shape

        # Create empty file.
        # FIXME (Ole): It appears that this is created as single
        #              precision even though Float64 is specified
        #              - see issue #17
        driver = gdal.GetDriverByName(file_format)
        fid = driver.Create(get_string(filename), M, N, 1, gdal.GDT_Float64)
        if fid is None:
            msg = ('Gdal could not create filename %s using '
                   'format %s' % (filename, file_format))
            raise WriteLayerError(msg)

        self.filename = filename

        # Write metadata
        fid.SetProjection(str(self.projection))
        fid.SetGeoTransform(self.geotransform)

        # Write data
        fid.GetRasterBand(1).WriteArray(A)
        fid.GetRasterBand(1).SetNoDataValue(self.get_nodata_value())
        # noinspection PyUnusedLocal
        fid = None  # Close

        # Write keywords if any
        write_iso19115_metadata(filename, self.keywords)
Exemple #14
0
 def test_write_read_iso_19115_metadata(self):
     """Test for write_read_iso_19115_metadata."""
     keywords = {
         # 'date': '26-03-2015 14:03',
         'exposure': 'structure',
         'keyword_version': '3.2',
         'layer_geometry': 'polygon',
         'layer_mode': 'classified',
         'layer_purpose': 'exposure',
         'license': 'Open Data Commons Open Database License (ODbL)',
         'source': 'OpenStreetMap - www.openstreetmap.org',
         'structure_class_field': 'TYPE',
         'title': 'Buildings'
     }
     layer = clone_shp_layer(name='buildings',
                             include_keywords=False,
                             source_directory=test_data_path('exposure'))
     write_iso19115_metadata(layer.source(), keywords)
Exemple #15
0
def create_contour_metadata(contour_path):
    """Create metadata file for contour layer.

    :param contour_path: Path where the contour is located.
    :type contour_path: basestring
    """
    metadata = {
        'title': tr('Earthquake Contour'),
        'layer_purpose': layer_purpose_earthquake_contour['key'],
        'layer_geometry': layer_geometry_line['key'],
        'layer_mode': layer_mode_classified['key'],
        'inasafe_fields': {}
    }

    for contour_field in contour_fields:
        metadata['inasafe_fields'][contour_field['key']] = contour_field[
            'field_name']

    write_iso19115_metadata(contour_path, metadata)
 def test_write_read_iso_19115_metadata(self):
     """Test for write_read_iso_19115_metadata."""
     keywords = {
         # 'date': '26-03-2015 14:03',
         'exposure': 'structure',
         'keyword_version': '3.2',
         'layer_geometry': 'polygon',
         'layer_mode': 'classified',
         'layer_purpose': 'exposure',
         'license': 'Open Data Commons Open Database License (ODbL)',
         'source': 'OpenStreetMap - www.openstreetmap.org',
         'structure_class_field': 'TYPE',
         'title': 'Buildings'
     }
     layer = clone_shp_layer(
         name='buildings',
         include_keywords=False,
         source_directory=test_data_path('exposure'))
     write_iso19115_metadata(layer.source(), keywords)
Exemple #17
0
    def write_keywords(self, layer, keywords):
        """Write keywords for a datasource.

        This is a wrapper method that will 'do the right thing' to store
        keywords for the given datasource. In particular, if the datasource
        is remote (e.g. a database connection) it will write the keywords from
        the keywords store.

        :param layer: A QGIS QgsMapLayer instance.
        :type layer: qgis.core.QgsMapLayer

        :param keywords: A dict containing all the keywords to be written
              for the layer.
        :type keywords: dict

        :raises: UnsupportedProviderError
        """
        source = layer.source()
        write_iso19115_metadata(source, keywords)
Exemple #18
0
def create_contour_metadata(contour_path):
    """Create metadata file for contour layer.

    :param contour_path: Path where the contour is located.
    :type contour_path: basestring
    """
    metadata = {
        'title': tr('Earthquake Contour'),
        'layer_purpose': layer_purpose_earthquake_contour['key'],
        'layer_geometry': layer_geometry_line['key'],
        'layer_mode': layer_mode_classified['key'],
        'inasafe_fields': {}
    }

    for contour_field in contour_fields:
        metadata['inasafe_fields'][
            contour_field['key']] = contour_field['field_name']

    write_iso19115_metadata(contour_path, metadata)
Exemple #19
0
    def write_keywords(self, layer, keywords):
        """Write keywords for a datasource.

        This is a wrapper method that will 'do the right thing' to store
        keywords for the given datasource. In particular, if the datasource
        is remote (e.g. a database connection) it will write the keywords from
        the keywords store.

        :param layer: A QGIS QgsMapLayer instance.
        :type layer: QgsMapLayer

        :param keywords: A dict containing all the keywords to be written
              for the layer.
        :type keywords: dict

        :raises: UnsupportedProviderError
        """
        source = layer.source()
        write_iso19115_metadata(source, keywords)
Exemple #20
0
    def test_write_iso19115_metadata(self):
        """Test for write_iso19115_metadata."""
        exposure_layer = clone_shp_layer(
            name='buildings',
            include_keywords=False,
            source_directory=standard_data_path('exposure'))
        keywords = {
            'date': '26-03-2015 14:03',
            'exposure': 'structure',
            'keyword_version': inasafe_keyword_version,
            'layer_geometry': 'polygon',
            'layer_mode': 'classified',
            'layer_purpose': 'exposure',
            'license': 'Open Data Commons Open Database License (ODbL)',
            'source': 'OpenStreetMap - www.openstreetmap.org',
            'title': 'Buildings'
        }
        metadata = write_iso19115_metadata(exposure_layer.source(), keywords)
        self.assertEqual(metadata.exposure, 'structure')

        # Version 3.5
        exposure_layer = clone_shp_layer(
            name='buildings',
            include_keywords=False,
            source_directory=standard_data_path('exposure'))
        keywords = {
            'date': '26-03-2015 14:03',
            'exposure': 'structure',
            'keyword_version': '3.2',
            'layer_geometry': 'polygon',
            'layer_mode': 'classified',
            'layer_purpose': 'exposure',
            'license': 'Open Data Commons Open Database License (ODbL)',
            'source': 'OpenStreetMap - www.openstreetmap.org',
            'structure_class_field': 'TYPE',
            'title': 'Buildings'
        }
        metadata = write_iso19115_metadata(exposure_layer.source(),
                                           keywords,
                                           version_35=True)
        self.assertEqual(metadata.exposure, 'structure')
Exemple #21
0
    def test_write_iso19115_metadata(self):
        """Test for write_iso19115_metadata."""
        exposure_layer = clone_shp_layer(
            name='buildings',
            include_keywords=False,
            source_directory=standard_data_path('exposure'))
        keywords = {
            'date': '26-03-2015 14:03',
            'exposure': 'structure',
            'keyword_version': inasafe_keyword_version,
            'layer_geometry': 'polygon',
            'layer_mode': 'classified',
            'layer_purpose': 'exposure',
            'license': 'Open Data Commons Open Database License (ODbL)',
            'source': 'OpenStreetMap - www.openstreetmap.org',
            'title': 'Buildings'
        }
        metadata = write_iso19115_metadata(exposure_layer.source(), keywords)
        self.assertEqual(metadata.exposure, 'structure')

        # Version 3.5
        exposure_layer = clone_shp_layer(
            name='buildings',
            include_keywords=False,
            source_directory=standard_data_path('exposure'))
        keywords = {
            'date': '26-03-2015 14:03',
            'exposure': 'structure',
            'keyword_version': '3.2',
            'layer_geometry': 'polygon',
            'layer_mode': 'classified',
            'layer_purpose': 'exposure',
            'license': 'Open Data Commons Open Database License (ODbL)',
            'source': 'OpenStreetMap - www.openstreetmap.org',
            'structure_class_field': 'TYPE',
            'title': 'Buildings'
        }
        metadata = write_iso19115_metadata(
            exposure_layer.source(), keywords, version_35=True)
        self.assertEqual(metadata.exposure, 'structure')
Exemple #22
0
    def write_keywords(layer, keywords):
        """Write keywords for a datasource.

        This is a wrapper method that will 'do the right thing' to store
        keywords for the given datasource. In particular, if the datasource
        is remote (e.g. a database connection) it will write the keywords from
        the keywords store.

        :param layer: A QGIS QgsMapLayer instance.
        :type layer: qgis.core.QgsMapLayer

        :param keywords: A dict containing all the keywords to be written
              for the layer.
        :type keywords: dict

        :raises: UnsupportedProviderError
        """
        if not isinstance(layer, QgsMapLayer):
            raise Exception(
                tr('The layer is not a QgsMapLayer : {type}').format(
                    type=type(layer)))

        source = layer.source()
        write_iso19115_metadata(source, keywords)
Exemple #23
0
    def write_to_file(self, filename, sublayer=None):
        """Save vector data to file

        :param filename: filename with extension .shp or .gml
        :type filename: str

        :param sublayer: Optional parameter for writing a sublayer. Ignored
            unless we are writing to an sqlite file.
        :type sublayer: str

        :raises: WriteLayerError

        Note:
            Shp limitation, if attribute names are longer than 10
            characters they will be truncated. This is due to limitations in
            the shp file driver and has to be done here since gdal v1.7 onwards
            has changed its handling of this issue:
            http://www.gdal.org/ogr/drv_shapefile.html

            **For this reason we recommend writing to spatialite.**

        """

        # Check file format
        base_name, extension = os.path.splitext(filename)

        msg = ('Invalid file type for file %s. Only extensions '
               'sqlite, shp or gml allowed.' % filename)
        verify(extension in ['.sqlite', '.shp', '.gml'], msg)
        driver = DRIVER_MAP[extension]

        # FIXME (Ole): Tempory flagging of GML issue (ticket #18)
        if extension == '.gml':
            msg = ('OGR GML driver does not store geospatial reference.'
                   'This format is disabled for the time being. See '
                   'https://github.com/AIFDR/riab/issues/18')
            raise WriteLayerError(msg)

        # Derive layer_name from filename (excluding preceding dirs)
        if sublayer is None or extension == '.shp':
            layer_name = os.path.split(base_name)[-1]
        else:
            layer_name = sublayer

        # Get vector data
        if self.is_polygon_data:
            geometry = self.get_geometry(as_geometry_objects=True)
        else:
            geometry = self.get_geometry()
        data = self.get_data()

        N = len(geometry)

        # Clear any previous file of this name (ogr does not overwrite)
        try:
            os.remove(filename)
        except OSError:
            pass

        # Create new file with one layer
        drv = ogr.GetDriverByName(driver)
        if drv is None:
            msg = 'OGR driver %s not available' % driver
            raise WriteLayerError(msg)

        ds = drv.CreateDataSource(get_string(filename))
        if ds is None:
            msg = 'Creation of output file %s failed' % filename
            raise WriteLayerError(msg)
        lyr = ds.CreateLayer(
            get_string(layer_name),
            self.projection.spatial_reference,
            self.geometry_type)
        if lyr is None:
            msg = 'Could not create layer %s' % layer_name
            raise WriteLayerError(msg)

        # Define attributes if any
        store_attributes = False
        fields = []
        if data is not None:
            if len(data) > 0:
                try:
                    fields = data[0].keys()
                except:
                    msg = ('Input parameter "attributes" was specified '
                           'but it does not contain list of dictionaries '
                           'with field information as expected. The first '
                           'element is %s' % data[0])
                    raise WriteLayerError(msg)
                else:
                    # Establish OGR types for each element
                    ogr_types = {}
                    for name in fields:
                        att = data[0][name]
                        py_type = type(att)
                        msg = ('Unknown type for storing vector '
                               'data: %s, %s' % (name, str(py_type)[1:-1]))
                        verify(py_type in TYPE_MAP, msg)
                        ogr_types[name] = TYPE_MAP[py_type]

            else:
                # msg = ('Input parameter "data" was specified '
                #       'but appears to be empty')
                # raise InaSAFEError(msg)
                pass

            # Create attribute fields in layer
            store_attributes = True
            for name in fields:
                # Rizky : OGR can't handle unicode field name, thus we
                # convert it to ASCII
                fd = ogr.FieldDefn(str(name), ogr_types[name])
                # FIXME (Ole): Trying to address issue #16
                #              But it doesn't work and
                #              somehow changes the values of MMI in test
                # width = max(128, len(name))
                # print name, width
                # fd.SetWidth(width)

                # Silent handling of warnings like
                # Warning 6: Normalized/laundered field name:
                # 'CONTENTS_LOSS_AUD' to 'CONTENTS_L'
                gdal.PushErrorHandler('CPLQuietErrorHandler')
                if lyr.CreateField(fd) != 0:
                    msg = 'Could not create field %s' % name
                    raise WriteLayerError(msg)

                # Restore error handler
                gdal.PopErrorHandler()

        # Store geometry
        geom = ogr.Geometry(self.geometry_type)
        layer_def = lyr.GetLayerDefn()
        for i in range(N):
            # Create new feature instance
            feature = ogr.Feature(layer_def)

            # Store geometry and check
            if self.is_point_data:
                x = float(geometry[i][0])
                y = float(geometry[i][1])
                geom.SetPoint_2D(0, x, y)
            elif self.is_line_data:
                geom = array_to_line(
                    geometry[i], geometry_type=ogr.wkbLineString)
            elif self.is_polygon_data:
                # Create polygon geometry
                geom = ogr.Geometry(ogr.wkbPolygon)

                # Add outer ring
                linear_ring = array_to_line(
                    geometry[i].outer_ring, geometry_type=ogr.wkbLinearRing)
                geom.AddGeometry(linear_ring)

                # Add inner rings if any
                for A in geometry[i].inner_rings:
                    geom.AddGeometry(array_to_line(
                        A, geometry_type=ogr.wkbLinearRing))
            else:
                msg = 'Geometry type %s not implemented' % self.geometry_type
                raise WriteLayerError(msg)

            feature.SetGeometry(geom)

            G = feature.GetGeometryRef()
            if G is None:
                msg = 'Could not create GeometryRef for file %s' % filename
                raise WriteLayerError(msg)

            # Store attributes
            if store_attributes:
                for j, name in enumerate(fields):
                    actual_field_name = layer_def.GetFieldDefn(j).GetNameRef()

                    val = data[i][name]

                    if isinstance(val, numpy.ndarray):
                        # A singleton of type <type 'numpy.ndarray'> works
                        # for gdal version 1.6 but fails for version 1.8
                        # in SetField with error: NotImplementedError:
                        # Wrong number of arguments for overloaded function
                        val = float(val)
                    elif val is None:
                        val = ''

                    # We do this because there is NaN problem on windows
                    # NaN value must be converted to _pseudo_in to solve the
                    # problem. But, when InaSAFE read the file, it'll be
                    # converted back to NaN value, so that NaN in InaSAFE is a
                    # numpy.nan
                    # please check https://github.com/AIFDR/inasafe/issues/269
                    # for more information
                    if val != val:
                        val = _pseudo_inf

                    feature.SetField(actual_field_name, val)

            # Save this feature
            if lyr.CreateFeature(feature) != 0:
                msg = 'Failed to create feature %i in file %s' % (i, filename)
                raise WriteLayerError(msg)

            feature.Destroy()

        # Write keywords if any
        # write_keywords(self.keywords, base_name + '.keywords')
        write_iso19115_metadata(filename, self.keywords)
        self.keywords = read_iso19115_metadata(filename)
Exemple #24
0
    def write_to_file(self, filename, sublayer=None):
        """Save vector data to file

        :param filename: filename with extension .shp or .gml
        :type filename: str

        :param sublayer: Optional parameter for writing a sublayer. Ignored
            unless we are writing to an sqlite file.
        :type sublayer: str

        :raises: WriteLayerError

        Note:
            Shp limitation, if attribute names are longer than 10
            characters they will be truncated. This is due to limitations in
            the shp file driver and has to be done here since gdal v1.7 onwards
            has changed its handling of this issue:
            http://www.gdal.org/ogr/drv_shapefile.html

            **For this reason we recommend writing to spatialite.**

        """

        # Check file format
        base_name, extension = os.path.splitext(filename)

        msg = ('Invalid file type for file %s. Only extensions '
               'sqlite, shp or gml allowed.' % filename)
        verify(extension in ['.sqlite', '.shp', '.gml'], msg)
        driver = DRIVER_MAP[extension]

        # FIXME (Ole): Tempory flagging of GML issue (ticket #18)
        if extension == '.gml':
            msg = ('OGR GML driver does not store geospatial reference.'
                   'This format is disabled for the time being. See '
                   'https://github.com/AIFDR/riab/issues/18')
            raise WriteLayerError(msg)

        # Derive layer_name from filename (excluding preceding dirs)
        if sublayer is None or extension == '.shp':
            layer_name = os.path.split(base_name)[-1]
        else:
            layer_name = sublayer

        # Get vector data
        if self.is_polygon_data:
            geometry = self.get_geometry(as_geometry_objects=True)
        else:
            geometry = self.get_geometry()
        data = self.get_data()

        N = len(geometry)

        # Clear any previous file of this name (ogr does not overwrite)
        try:
            os.remove(filename)
        except OSError:
            pass

        # Create new file with one layer
        drv = ogr.GetDriverByName(driver)
        if drv is None:
            msg = 'OGR driver %s not available' % driver
            raise WriteLayerError(msg)

        ds = drv.CreateDataSource(get_string(filename))
        if ds is None:
            msg = 'Creation of output file %s failed' % filename
            raise WriteLayerError(msg)
        lyr = ds.CreateLayer(get_string(layer_name),
                             self.projection.spatial_reference,
                             self.geometry_type)
        if lyr is None:
            msg = 'Could not create layer %s' % layer_name
            raise WriteLayerError(msg)

        # Define attributes if any
        store_attributes = False
        fields = []
        if data is not None:
            if len(data) > 0:
                try:
                    fields = data[0].keys()
                except:
                    msg = ('Input parameter "attributes" was specified '
                           'but it does not contain list of dictionaries '
                           'with field information as expected. The first '
                           'element is %s' % data[0])
                    raise WriteLayerError(msg)
                else:
                    # Establish OGR types for each element
                    ogr_types = {}
                    for name in fields:
                        att = data[0][name]
                        py_type = type(att)
                        msg = ('Unknown type for storing vector '
                               'data: %s, %s' % (name, str(py_type)[1:-1]))
                        verify(py_type in TYPE_MAP, msg)
                        ogr_types[name] = TYPE_MAP[py_type]

            else:
                # msg = ('Input parameter "data" was specified '
                #       'but appears to be empty')
                # raise InaSAFEError(msg)
                pass

            # Create attribute fields in layer
            store_attributes = True
            for name in fields:
                # Rizky : OGR can't handle unicode field name, thus we
                # convert it to ASCII
                fd = ogr.FieldDefn(str(name), ogr_types[name])
                # FIXME (Ole): Trying to address issue #16
                #              But it doesn't work and
                #              somehow changes the values of MMI in test
                # width = max(128, len(name))
                # print name, width
                # fd.SetWidth(width)

                # Silent handling of warnings like
                # Warning 6: Normalized/laundered field name:
                # 'CONTENTS_LOSS_AUD' to 'CONTENTS_L'
                gdal.PushErrorHandler('CPLQuietErrorHandler')
                if lyr.CreateField(fd) != 0:
                    msg = 'Could not create field %s' % name
                    raise WriteLayerError(msg)

                # Restore error handler
                gdal.PopErrorHandler()

        # Store geometry
        geom = ogr.Geometry(self.geometry_type)
        layer_def = lyr.GetLayerDefn()
        for i in range(N):
            # Create new feature instance
            feature = ogr.Feature(layer_def)

            # Store geometry and check
            if self.is_point_data:
                x = float(geometry[i][0])
                y = float(geometry[i][1])
                geom.SetPoint_2D(0, x, y)
            elif self.is_line_data:
                geom = array_to_line(geometry[i],
                                     geometry_type=ogr.wkbLineString)
            elif self.is_polygon_data:
                # Create polygon geometry
                geom = ogr.Geometry(ogr.wkbPolygon)

                # Add outer ring
                linear_ring = array_to_line(geometry[i].outer_ring,
                                            geometry_type=ogr.wkbLinearRing)
                geom.AddGeometry(linear_ring)

                # Add inner rings if any
                for A in geometry[i].inner_rings:
                    geom.AddGeometry(
                        array_to_line(A, geometry_type=ogr.wkbLinearRing))
            else:
                msg = 'Geometry type %s not implemented' % self.geometry_type
                raise WriteLayerError(msg)

            feature.SetGeometry(geom)

            G = feature.GetGeometryRef()
            if G is None:
                msg = 'Could not create GeometryRef for file %s' % filename
                raise WriteLayerError(msg)

            # Store attributes
            if store_attributes:
                for j, name in enumerate(fields):
                    actual_field_name = layer_def.GetFieldDefn(j).GetNameRef()

                    val = data[i][name]

                    if isinstance(val, numpy.ndarray):
                        # A singleton of type <type 'numpy.ndarray'> works
                        # for gdal version 1.6 but fails for version 1.8
                        # in SetField with error: NotImplementedError:
                        # Wrong number of arguments for overloaded function
                        val = float(val)
                    elif val is None:
                        val = ''

                    # We do this because there is NaN problem on windows
                    # NaN value must be converted to _pseudo_in to solve the
                    # problem. But, when InaSAFE read the file, it'll be
                    # converted back to NaN value, so that NaN in InaSAFE is a
                    # numpy.nan
                    # please check https://github.com/AIFDR/inasafe/issues/269
                    # for more information
                    if val != val:
                        val = _pseudo_inf

                    feature.SetField(actual_field_name, val)

            # Save this feature
            if lyr.CreateFeature(feature) != 0:
                msg = 'Failed to create feature %i in file %s' % (i, filename)
                raise WriteLayerError(msg)

            feature.Destroy()

        # Write keywords if any
        # write_keywords(self.keywords, base_name + '.keywords')
        write_iso19115_metadata(filename, self.keywords)
        self.keywords = read_iso19115_metadata(filename)