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 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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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 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)
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')
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')
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)
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)
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)