From a3426775681819d2d01fa831c40d67f53c27fc0b Mon Sep 17 00:00:00 2001 From: sbastiangarzon Date: Wed, 17 Feb 2021 17:00:30 +0100 Subject: [PATCH 1/8] CRS extraction for vector, raster logger message --- geoextent/lib/handleRaster.py | 16 +++++++--------- geoextent/lib/handleVector.py | 5 +++-- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/geoextent/lib/handleRaster.py b/geoextent/lib/handleRaster.py index 03d8a98..aea69ef 100644 --- a/geoextent/lib/handleRaster.py +++ b/geoextent/lib/handleRaster.py @@ -34,8 +34,8 @@ def checkFileSupported(filepath): def getBoundingBox(filePath): - ''' extracts bounding box from geotiff \n - input "filepath": type string, file path to geotiff file \n + ''' extracts bounding box from raster \n + input "filepath": type string, file path to raster file \n returns bounding box of the file: type list, length = 4 , type = float, schema = [min(longs), min(lats), max(longs), max(lats)] ''' # Enable exceptions @@ -80,12 +80,10 @@ def getBoundingBox(filePath): return spatialExtent -def getTemporalExtent(filePath): - ''' extracts temporal extent of the geotiff \n +def getTemporalExtent(filepath): + """ extracts temporal extent of the geotiff \n input "filepath": type string, file path to geotiff file \n - returns None as There is no time value for GeoTIFF files - ''' - - print('There is no time value for GeoTIFF files') + returns None as There is no time value for GeoTIFF files + """ + logger.debug('{} There is no time value for raster files'.format(filepath)) return None - diff --git a/geoextent/lib/handleVector.py b/geoextent/lib/handleVector.py index e3cfd08..292a256 100644 --- a/geoextent/lib/handleVector.py +++ b/geoextent/lib/handleVector.py @@ -110,7 +110,6 @@ def getBoundingBox(filepath): """ datasource = ogr.Open(filepath) geo_dict = {} - crs_output = hf.WGS84_EPSG_ID for layer in datasource: layer_name = layer.GetDescription() @@ -118,7 +117,9 @@ def getBoundingBox(filepath): bbox = [ext[0], ext[2], ext[1], ext[3]] try: - crs = layer.GetSpatialRef().GetAttrValue("GEOGCS|AUTHORITY", 1) + spatial_ref = layer.GetSpatialRef() + spatial_ref.AutoIdentifyEPSG() + crs = spatial_ref.GetAuthorityCode(None) except Exception as e: logger.debug("Error extracting EPSG CODE from layer {}: \n {}".format(layer_name, e)) crs = None From 89e8d3e5e1711e390852d15965c964e1a0f64fb2 Mon Sep 17 00:00:00 2001 From: sbastiangarzon Date: Thu, 18 Feb 2021 17:09:07 +0100 Subject: [PATCH 2/8] Validate CRS / flip bbox if required --- geoextent/__init__.py | 2 +- geoextent/lib/extent.py | 12 ++++ geoextent/lib/handleCSV.py | 82 ++++++++++++---------- geoextent/lib/handleRaster.py | 22 +++--- geoextent/lib/helpfunctions.py | 38 +++++++++- tests/test_api.py | 6 ++ tests/testdata/csv/cities_NL_case_flip.csv | 11 +++ 7 files changed, 121 insertions(+), 52 deletions(-) create mode 100644 tests/testdata/csv/cities_NL_case_flip.csv diff --git a/geoextent/__init__.py b/geoextent/__init__.py index 9e30d52..8a15ff1 100644 --- a/geoextent/__init__.py +++ b/geoextent/__init__.py @@ -1,3 +1,3 @@ name = "geoextent" -__version__ = '0.6.0' +__version__ = '0.6.1' diff --git a/geoextent/lib/extent.py b/geoextent/lib/extent.py index 0ae4ec7..07f3e0d 100644 --- a/geoextent/lib/extent.py +++ b/geoextent/lib/extent.py @@ -34,6 +34,18 @@ def compute_bbox_wgs84(module, path): raise Exception("The bounding box could not be transformed to the target CRS epsg:{} \n error {}" .format(hf.WGS84_EPSG_ID, e)) + validate = hf.validate_bbox_wgs84(spatial_extent['bbox']) + logger.debug("Validate: {}".format(validate)) + + if not hf.validate_bbox_wgs84(spatial_extent['bbox']): + try: + flip_bbox = hf.flip_bbox(spatial_extent['bbox']) + spatial_extent['bbox'] = flip_bbox + + except Exception as e: + raise Exception("The bounding box could not be transformed to the target CRS epsg:{} \n error {}" + .format(hf.WGS84_EPSG_ID, e)) + return spatial_extent diff --git a/geoextent/lib/handleCSV.py b/geoextent/lib/handleCSV.py index 38c83e0..52c808a 100644 --- a/geoextent/lib/handleCSV.py +++ b/geoextent/lib/handleCSV.py @@ -3,7 +3,6 @@ from osgeo import gdal from . import helpfunctions as hf - logger = logging.getLogger("geoextent") search = {"longitude": ["(.)*longitude", "(.)*long(.)*", "^lon", "lon$", "(.)*lng(.)*", "^x", "x$"], @@ -30,8 +29,8 @@ def checkFileSupported(filepath): if driver == "CSV": with open(filepath) as csv_file: - daten = csv.reader(csv_file.readlines()) - if daten is None: + data = csv.reader(csv_file.readlines()) + if data is None: logger.debug("File {} is NOT supported by HandleCSV module".format(filepath)) return False else: @@ -40,6 +39,7 @@ def checkFileSupported(filepath): else: return False + def getBoundingBox(filePath): ''' Function purpose: extracts the spatial extent (bounding box) from a csv-file \n @@ -49,32 +49,32 @@ def getBoundingBox(filePath): with open(filePath) as csv_file: # To get delimiter either comma or simecolon - daten = hf.getDelimiter(csv_file) + date = hf.getDelimiter(csv_file) elements = [] - for x in daten: + for x in date: elements.append(x) - spatialLatExtent = hf.searchForParameters(elements, search['latitude'], exp_data='numeric') + spatial_lat_extent = hf.searchForParameters(elements, search['latitude'], exp_data='numeric') - minlat = None - maxlat = None + min_lat = None + max_lat = None - if spatialLatExtent is None: + if spatial_lat_extent is None: pass else: - minlat = (min(spatialLatExtent)) - maxlat = (max(spatialLatExtent)) + min_lat = (min(spatial_lat_extent)) + max_lat = (max(spatial_lat_extent)) - spatialLonExtent = hf.searchForParameters(elements, search['longitude'], exp_data='numeric') + spatial_lon_extent = hf.searchForParameters(elements, search['longitude'], exp_data='numeric') - if spatialLonExtent is None: + if spatial_lon_extent is None: raise Exception('The csv file from ' + filePath + ' has no BoundingBox') else: - minlon = (min(spatialLonExtent)) - maxlon = (max(spatialLonExtent)) + min_lon = (min(spatial_lon_extent)) + max_lon = (max(spatial_lon_extent)) - bbox = [minlon, minlat, maxlon, maxlat] + bbox = [min_lon, min_lat, max_lon, max_lat] logger.debug("Extracted Bounding box (without projection): {}".format(bbox)) crs = getCRS(filePath) logger.debug("Extracted CRS: {}".format(crs)) @@ -84,53 +84,59 @@ def getBoundingBox(filePath): return spatialExtent -def getTemporalExtent(filePath, num_sample): - ''' extract time extent from csv string \n + +def getTemporalExtent(filepath, num_sample): + """ extract time extent from csv string \n input "filePath": type string, file path to csv File \n returns temporal extent of the file: type list, length = 2, both entries have the type str, temporalExtent[0] <= temporalExtent[1] - ''' + """ - with open(filePath) as csv_file: - # To get delimiter either comma or simecolon - daten = hf.getDelimiter(csv_file) + with open(filepath) as csv_file: + # To get delimiter either comma or semicolon + data = hf.getDelimiter(csv_file) elements = [] - for x in daten: + for x in data: elements.append(x) all_temporal_extent = hf.searchForParameters(elements, search['time'], exp_data="time") if all_temporal_extent is None: - raise Exception('The csv file from ' + filePath + ' has no TemporalExtent') + raise Exception('The csv file from ' + filepath + ' has no TemporalExtent') else: tbox = [] - parsed_time = hf.date_parser(all_temporal_extent, num_sample = num_sample) + parsed_time = hf.date_parser(all_temporal_extent, num_sample=num_sample) if parsed_time is not None: # Min and max into ISO8601 format ('%Y-%m-%d') tbox.append(min(parsed_time).strftime('%Y-%m-%d')) tbox.append(max(parsed_time).strftime('%Y-%m-%d')) else: - raise Exception('The csv file from ' + filePath + ' has no recognizable TemporalExtent') + raise Exception('The csv file from ' + filepath + ' has no recognizable TemporalExtent') return tbox -def getCRS(filePath): + +def getCRS(filepath): '''extracts coordinatesystem from csv File \n input "filepath": type string, file path to csv file \n returns the epsg code of the used coordinate reference system, type list, contains extracted coordinate system of content from csv file ''' - with open(filePath) as csv_file: - daten = csv.reader(csv_file.readlines()) + with open(filepath) as csv_file: + data = hf.getDelimiter(csv_file) elements = [] - for x in daten: + for x in data: elements.append(x) - if hf.searchForParameters(elements, search['latitude'] + search['longitude']) is None: - if hf.searchForParameters(elements, ["crs","srsID"]) is None: - raise Exception('The csv file from ' + filePath + ' has no CRS') - if hf.searchForParameters(elements, ["crs","srsID"]) == "WGS84": - return "4326" - else: - raise Exception('The csv file from ' + filePath + ' has no WGS84 CRS') + param = hf.searchForParameters(elements, ["crs", "srsID", "EPSG"]) + + if param is None: + logger.debug("{} : There is no identifiable coordinate reference system. We will try to use EPSG: 4236".format(filepath)) + crs = "4326" + + elif len(list(set(param))) > 1: + logger.debug("{} : Coordinate reference system of the file is ambiguous. Extraction is not possible.".format(filepath)) + raise Exception('The csv file from ' + filepath + ' has no CRS') else: - return "4326" + crs = str(list(set(param))[0]) + + return crs \ No newline at end of file diff --git a/geoextent/lib/handleRaster.py b/geoextent/lib/handleRaster.py index aea69ef..53e459f 100644 --- a/geoextent/lib/handleRaster.py +++ b/geoextent/lib/handleRaster.py @@ -34,10 +34,10 @@ def checkFileSupported(filepath): def getBoundingBox(filePath): - ''' extracts bounding box from raster \n + """ extracts bounding box from raster \n input "filepath": type string, file path to raster file \n - returns bounding box of the file: type list, length = 4 , type = float, schema = [min(longs), min(lats), max(longs), max(lats)] - ''' + returns bounding box of the file: type list, length = 4 , type = float, schema = [min(longs), min(lats), max(longs), max(lats)] + """ # Enable exceptions crs_output = hf.WGS84_EPSG_ID @@ -59,21 +59,21 @@ def getBoundingBox(filePath): height = geotiffContent.RasterYSize gt = geotiffContent.GetGeoTransform() - minx = gt[0] - miny = gt[3] + width * gt[4] + height * gt[5] - maxx = gt[0] + width * gt[1] + height * gt[2] - maxy = gt[3] + min_x = gt[0] + min_y = gt[3] + width * gt[4] + height * gt[5] + max_x = gt[0] + width * gt[1] + height * gt[2] + max_y = gt[3] transform = osr.CoordinateTransformation(old_crs, new_crs) # get the coordinates in lat long - latlongmin = transform.TransformPoint(minx, miny) - latlongmax = transform.TransformPoint(maxx, maxy) + lat_long_min = transform.TransformPoint(min_x, min_y) + lat_long_max = transform.TransformPoint(max_x, max_y) - bbox = [latlongmin[0], latlongmin[1], latlongmax[0], latlongmax[1]] + bbox = [lat_long_min[0], lat_long_min[1], lat_long_max[0], lat_long_max[1]] if int(osgeo.__version__[0]) >= 3: if old_crs.GetAxisMappingStrategy() == 1: - bbox = [latlongmin[1], latlongmin[0], latlongmax[1], latlongmax[0]] + bbox = [lat_long_min[1], lat_long_min[0], lat_long_max[1], lat_long_max[0]] spatialExtent = {"bbox": bbox, "crs": str(crs_output)} diff --git a/geoextent/lib/helpfunctions.py b/geoextent/lib/helpfunctions.py index f9974df..6ce3e58 100644 --- a/geoextent/lib/helpfunctions.py +++ b/geoextent/lib/helpfunctions.py @@ -87,7 +87,7 @@ def searchForParameters(elements, paramArray, exp_data=None): def transformingIntoWGS84(crs, coordinate): ''' - Function purpose: transforming SRS into WGS84 (EPSG:4978; used by the GPS satellite navigation system) \n + Function purpose: transforming SRS into WGS84 (EPSG:4326) \n Input: crs, point \n Output: retPoint constisting of x2, y2 (transformed points) ''' @@ -112,7 +112,7 @@ def transformingIntoWGS84(crs, coordinate): def transformingArrayIntoWGS84(crs, pointArray): ''' - Function purpose: transforming SRS into WGS84 (EPSG:4978; used by the GPS satellite navigation system) from an array \n + Function purpose: transforming SRS into WGS84 (EPSG 4326; used by the GPS satellite navigation system) from an array \n Input: crs, pointArray \n Output: array array ''' @@ -130,6 +130,40 @@ def transformingArrayIntoWGS84(crs, pointArray): return [transf_bbox[0][0], transf_bbox[0][1], transf_bbox[1][0], transf_bbox[1][1]] +def validate_bbox_wgs84(bbox): + """ + :param bbox: + :return: + """ + valid = True + lon_values = bbox[0:3:2] + lat_values = bbox[1:4:2] + + if sum(list(map(lambda x: x < -90 or x > 90, lat_values))) + sum( + list(map(lambda x: x < -180 or x > 180, lon_values))) > 0: + valid = False + + return valid + + +def flip_bbox(bbox): + """ + :param bbox: + :return: + """ + # Flip values + lon_values = bbox[1:4:2] + lat_values = bbox[0:3:2] + + bbox_flip = [lon_values[0], lat_values[0], lon_values[1], lat_values[1]] + if validate_bbox_wgs84(bbox_flip): + logger.warning("Longitude and latitude values flipped") + return bbox_flip + else: + raise Exception("Latitude and longitude values extracted do not seem to be correctly transformed. We tried " + "flipping latitude and longitude values but both bbox are incorrect") + + def validate(date_text): try: if datetime.datetime.strptime(date_text, output_time_format): diff --git a/tests/test_api.py b/tests/test_api.py index 29add37..e0cf96a 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -213,3 +213,9 @@ def test_bbox_and_tbox_both_false(): with pytest.raises(Exception) as excinfo: geoextent.fromFile('tests/path_does_not_matter', bbox=False, tbox=False) assert "No extraction options" in str(excinfo.value) + + +def test_invalid_bbox_and_flip(): + result = geoextent.fromFile('tests/testdata/csv/cities_NL_case_flip.csv', bbox=True) + assert result['bbox'] == pytest.approx([4.3175, 5.0, 95.0, 53.217222], abs=tolerance) + assert result['crs'] == "4326" diff --git a/tests/testdata/csv/cities_NL_case_flip.csv b/tests/testdata/csv/cities_NL_case_flip.csv new file mode 100644 index 0000000..5400fe9 --- /dev/null +++ b/tests/testdata/csv/cities_NL_case_flip.csv @@ -0,0 +1,11 @@ +Name,no_Latitude,EPSG,no_Longitude,NumberOfCitizens,TimeStamp +Amsterdam,4.890444,4326,52.370197,862276,30.09.2018 +Rotterdam,4.479167,4326,51.930833,643307,30.09.2018 +Den Haag,4.3175,4326,52.084167,537368,30.09.2018 +Utrecht,5.115556,4326,52.088889,350821,30.09.2018 +Eindhoven,5.484167,4326,51.434444,230953,01.08.2017 +Groningen,6.574722,4326,53.217222,231214,30.09.2018 +Arnhem,5.9225,4326,51.999167,158629,30.09.2018 +Leeuwarden,5.7925,4326,53.197222,122925,30.09.2019 +Alkmaar,4.746389,4326,52.634444,108552,30.09.2018 +error,95,4326,5,0,30.09.2019 From 61259adfa92bbff0cdda96a2bf8c95b17e436e3c Mon Sep 17 00:00:00 2001 From: sbastiangarzon Date: Thu, 18 Feb 2021 17:17:17 +0100 Subject: [PATCH 3/8] Travis python version --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2d7fe1b..74d00c5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,6 @@ dist: xenial language: python python: - "3.8" - - "nightly" addons: apt: sources: From 5be5b54798560fdcf13b43ffcb1d44bbd3ef4cb0 Mon Sep 17 00:00:00 2001 From: sbastiangarzon Date: Fri, 5 Mar 2021 13:36:14 +0100 Subject: [PATCH 4/8] Fixes #85 #113 #84 bbox - include test --- geoextent/lib/handleRaster.py | 16 +++++++++++----- tests/test_api.py | 24 ++++++++++++++++++++++++ tests/testdata/data-sources.md | 5 ++++- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/geoextent/lib/handleRaster.py b/geoextent/lib/handleRaster.py index 53e459f..a97a4af 100644 --- a/geoextent/lib/handleRaster.py +++ b/geoextent/lib/handleRaster.py @@ -33,7 +33,7 @@ def checkFileSupported(filepath): return False -def getBoundingBox(filePath): +def getBoundingBox(filepath): """ extracts bounding box from raster \n input "filepath": type string, file path to raster file \n returns bounding box of the file: type list, length = 4 , type = float, schema = [min(longs), min(lats), max(longs), max(lats)] @@ -43,7 +43,7 @@ def getBoundingBox(filePath): crs_output = hf.WGS84_EPSG_ID gdal.UseExceptions() - geotiffContent = gdal.Open(filePath) + geotiffContent = gdal.Open(filepath) # get the existing coordinate system old_crs = osr.SpatialReference() @@ -65,9 +65,15 @@ def getBoundingBox(filePath): max_y = gt[3] transform = osr.CoordinateTransformation(old_crs, new_crs) - # get the coordinates in lat long - lat_long_min = transform.TransformPoint(min_x, min_y) - lat_long_max = transform.TransformPoint(max_x, max_y) + try: + # get the coordinates in lat long + lat_long_min = transform.TransformPoint(min_x, min_y) + lat_long_max = transform.TransformPoint(max_x, max_y) + except: + # Assume that coordinates are in EPSG:4236 + logger.debug("{}: There is no identifiable coordinate reference system. We will try to use EPSG: 4236 ".format(filepath)) + lat_long_min = [min_y, min_x] + lat_long_max = [max_y, max_x] bbox = [lat_long_min[0], lat_long_min[1], lat_long_max[0], lat_long_max[1]] diff --git a/tests/test_api.py b/tests/test_api.py index e0cf96a..9ca19e1 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -1,6 +1,7 @@ import os # used to get the location of the testdata import sys import tempfile +import urllib.request import pytest import geoextent.lib.extent as geoextent from help_functions_test import create_zip, tolerance @@ -169,6 +170,17 @@ def test_zipfile_nested_folders(): assert result["tbox"] == ['2017-04-08', '2020-02-06'] +def test_png_file_extract_bbox(): + with tempfile.TemporaryDirectory() as tmp: + url = 'https://zenodo.org/record/820562/files/20160100_Hpakan_20151123_PRE.png?download=1' + url2 = 'https://zenodo.org/record/820562/files/20160100_Hpakan_20151123_PRE.pngw?download=1' + urllib.request.urlretrieve(url, os.path.join(tmp, "20160100_Hpakan_20151123_PRE.png")) + urllib.request.urlretrieve(url2, os.path.join(tmp, "20160100_Hpakan_20151123_PRE.pngw")) + result = geoextent.fromFile(os.path.join(tmp, "20160100_Hpakan_20151123_PRE.png"), bbox=True) + assert result["bbox"] == pytest.approx([96.21146, 25.55834, 96.35490, 25.63293], abs=tolerance) + assert result["crs"] == "4326" + + @pytest.mark.skip(reason="file format not implemented yet") def test_netcdf_extract_time(): assert geoextent.fromFile("tests/testdata/nc/ECMWF_ERA-40_subset.nc", tbox=True) == ['2002-07-01', '2002-07-31'] @@ -199,6 +211,18 @@ def test_gml_extract_bbox_time(): assert result['tbox'] == ['2005-12-31', '2013-11-30'] +def test_jpge_2000_extract_bbox(): + result = geoextent.fromFile("tests/testdata/jpge2000/MSK_SNWPRB_60m.jp2", bbox=True) + assert result['bbox'] == pytest.approx([-74.09868, 4.434354, -73.10649, 5.425259], abs=tolerance) + assert result['crs'] == "4326" + + +def test_esri_ascii_extract_bbox(): + result = geoextent.fromFile("tests/testdata/asc/Churfirsten_30m.asc", bbox=True) + assert result['bbox'] == pytest.approx([8.85620, 46.93996, 8.85699, 46.94050], abs=tolerance) + assert result['crs'] == "4326" + + def test_not_found_file(): result = geoextent.fromFile('tests/testdata/empt.geojson', bbox=True) assert result is None diff --git a/tests/testdata/data-sources.md b/tests/testdata/data-sources.md index fd3c81a..e9e564b 100644 --- a/tests/testdata/data-sources.md +++ b/tests/testdata/data-sources.md @@ -15,12 +15,13 @@ | [Geosoftware2] | wf_100m_klas | geotif | MIT | | [geoextent] | onePoint | geojson | PDDL | | [geoextent] | invalid_coordinate | geojson | PDDL | -| [geoextent] | onePoint | geojson | PDDL | | [Carto BCN / martgnz] | Barcelona districts | geojson | CC-BY 4.0 | | [Google] | abstractviews_timeprimitive_example | kml | CC-BY 4.0 | | [Tkrajina] | gpx1.1_with_all_fields.gpx | gpx | Apache License 2.0 | | [geoextent] | ifgi_to_denkpause.shp | shp | PDDL | | [geoextent] | wandelroute_maastricht.gpkg | gpkg | PDDL | +| [Copernicus] | MSK_SNWPRB_60m | jp2 | [Copernicus Sentinel Data] | +| [Zenodo](https://zenodo.org/record/4323616) | Churfirsten_30m | asc | CC-BY 4.0 | [sf]: https://github.com/r-spatial/sf [geoextent]: https://github.com/o2r-project/geoextent @@ -32,3 +33,5 @@ [Carto BCN / martgnz]: https://github.com/martgnz/bcn-geodata/tree/master/districtes [Google]: https://developers.google.com/kml/documentation/time#gps [Tkrajina]: https://github.com/tkrajina/gpxpy/blob/dev/test_files/gpx1.1_with_all_fields.gpx +[Copernicus]: https://scihub.copernicus.eu/dhus/odata/v1/Products('e6b0b515-cc16-4e70-94ba-12e80db73d19')/$value +[Copernicus Sentinel Data]: https://sentinel.esa.int/documents/247904/690755/Sentinel_Data_Legal_Notice From fe55b0b9d6afd83307a2fc73624fcb0d2fdcf1f3 Mon Sep 17 00:00:00 2001 From: sbastiangarzon Date: Fri, 5 Mar 2021 13:40:16 +0100 Subject: [PATCH 5/8] test files --- tests/testdata/asc/Churfirsten_30m.asc | 8 ++++++++ tests/testdata/asc/Churfirsten_30m.prj | 1 + tests/testdata/jpge2000/MSK_SNWPRB_60m.jp2 | Bin 0 -> 32222 bytes 3 files changed, 9 insertions(+) create mode 100644 tests/testdata/asc/Churfirsten_30m.asc create mode 100644 tests/testdata/asc/Churfirsten_30m.prj create mode 100644 tests/testdata/jpge2000/MSK_SNWPRB_60m.jp2 diff --git a/tests/testdata/asc/Churfirsten_30m.asc b/tests/testdata/asc/Churfirsten_30m.asc new file mode 100644 index 0000000..962957d --- /dev/null +++ b/tests/testdata/asc/Churfirsten_30m.asc @@ -0,0 +1,8 @@ +ncols 2 +nrows 2 +xllcorner -41404.534638399433 +yllcorner -34323.166541740298 +cellsize 30.000000000000 +NODATA_value -9999.0 + 806.7 798.9 +790.4 781.9 diff --git a/tests/testdata/asc/Churfirsten_30m.prj b/tests/testdata/asc/Churfirsten_30m.prj new file mode 100644 index 0000000..ccc003f --- /dev/null +++ b/tests/testdata/asc/Churfirsten_30m.prj @@ -0,0 +1 @@ +PROJCS["Bonne_47_25N_9_4E",GEOGCS["GCS_WGS_1984",DATUM["D_wgs_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Bonne"],PARAMETER["false_easting",0],PARAMETER["false_northing",0],PARAMETER["standard_parallel_1",47.25],PARAMETER["central_meridian",9.4],UNIT["Meter",1]] \ No newline at end of file diff --git a/tests/testdata/jpge2000/MSK_SNWPRB_60m.jp2 b/tests/testdata/jpge2000/MSK_SNWPRB_60m.jp2 new file mode 100644 index 0000000000000000000000000000000000000000..91aa15998d77c6e20d82055e7c22eea1650bedc8 GIT binary patch literal 32222 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 Date: Fri, 12 Mar 2021 13:20:44 +0100 Subject: [PATCH 6/8] Fixes #24 with test / Fix doc typos --- geoextent/lib/handleCSV.py | 2 +- geoextent/lib/handleRaster.py | 3 ++- tests/test_api.py | 5 +++-- tests/test_cli.py | 5 ++--- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/geoextent/lib/handleCSV.py b/geoextent/lib/handleCSV.py index 52c808a..b3a1103 100644 --- a/geoextent/lib/handleCSV.py +++ b/geoextent/lib/handleCSV.py @@ -130,7 +130,7 @@ def getCRS(filepath): param = hf.searchForParameters(elements, ["crs", "srsID", "EPSG"]) if param is None: - logger.debug("{} : There is no identifiable coordinate reference system. We will try to use EPSG: 4236".format(filepath)) + logger.debug("{} : There is no identifiable coordinate reference system. We will try to use EPSG: 4326".format(filepath)) crs = "4326" elif len(list(set(param))) > 1: diff --git a/geoextent/lib/handleRaster.py b/geoextent/lib/handleRaster.py index a97a4af..e139b6f 100644 --- a/geoextent/lib/handleRaster.py +++ b/geoextent/lib/handleRaster.py @@ -71,7 +71,8 @@ def getBoundingBox(filepath): lat_long_max = transform.TransformPoint(max_x, max_y) except: # Assume that coordinates are in EPSG:4236 - logger.debug("{}: There is no identifiable coordinate reference system. We will try to use EPSG: 4236 ".format(filepath)) + logger.debug("{}: There is no identifiable coordinate reference system. We will try to use EPSG: 4326 " + .format(filepath)) lat_long_min = [min_y, min_x] lat_long_max = [max_y, max_x] diff --git a/tests/test_api.py b/tests/test_api.py index 9ca19e1..176f843 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -25,9 +25,10 @@ def test_defaults(): assert "crs" not in result -@pytest.mark.skip(reason="file format not implemented yet") def test_netcdf_extract_bbox(): - assert geoextent.fromFile("tests/testdata/nc/ECMWF_ERA-40_subset.nc") == [-90.0, 0.0, 90.0, 357.5] + result = geoextent.fromFile("tests/testdata/nc/zeroes.nc") + assert result["bbox"] == pytest.approx([19.86842, -52.63157, 25.13157, 52.63157], abs=tolerance) + assert result["crs"] == "4326" def test_kml_extract_bbox(): diff --git a/tests/test_cli.py b/tests/test_cli.py index 8b1201a..b48f9db 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -138,15 +138,14 @@ def test_print_supported_formats(script_runner): assert "Supported formats:" in ret.stdout, "list of supported formats is printed to console" -@pytest.mark.skip(reason="file format not implemented yet") def test_netcdf_bbox(script_runner): ret = script_runner.run('geoextent', - '-b', 'tests/testdata/nc/ECMWF_ERA-40_subset.nc') + '-b', 'tests/testdata/nc/zeroes.nc') assert ret.success, "process should return success" assert ret.stderr == '', "stderr should be empty" result = ret.stdout bboxList = parse_coordinates(result) - assert bboxList == pytest.approx([-90.0, 0.0, 90.0, 357.5], abs=tolerance) + assert bboxList == pytest.approx([19.86842, -52.63157, 25.13157, 52.63157], abs=tolerance) assert "4326" in result From 61379cec68eccb777416eb8306168255b61edcfc Mon Sep 17 00:00:00 2001 From: sbastiangarzon Date: Fri, 12 Mar 2021 13:23:31 +0100 Subject: [PATCH 7/8] NetCDF file test --- tests/testdata/nc/zeroes.nc | Bin 0 -> 24291 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/testdata/nc/zeroes.nc diff --git a/tests/testdata/nc/zeroes.nc b/tests/testdata/nc/zeroes.nc new file mode 100644 index 0000000000000000000000000000000000000000..924c97a046260c247ed9ce76832aa733f23e92c3 GIT binary patch literal 24291 zcmeHPYm8Gx6rS4_tk~rtF3UruRMb^V>1$smB;3BXD@%86OVHr56k4FtZ8vQ}iHgQV zjZy#jCK?2v8>3=Oh!`QT;2I@9qR~K9e1iHz5%C$K(Q{_zbSv3X1!C591}^hDb7tl{ z=gyt^?k%^61EHERQ^zn2W-~Lf@jOZY{2{{^i$w|LseTD1D#RV(K-6IQ)L`TFM$r#r z{o{muO!l@`#$yaj!EmRvr^>u7R# z?JJYZ8|JtiF1N#JXGW06aP?K@Mn2UVho()&5=|3*(+Ft%#+L~iIbUEkinogB^MfdctwzB`t%~WM6tj3?*ibZ<8>2hI(eeh; zJ?SKfjyKa3tdJXQ$}^1h9sFjBK+b*)a%V{iimM`LI6iVO)(eFnOTFY{ryRMNm5@VA z5^|YD@dSYr8baU2mi#-o-FMNj!Y!9QLEH>{8lN9HS}SmaTl6n?s&tFeeI)&D#t?TZ zzc2Al#WrTVDPXBG&@GOoXlimWV@V}RP;5D&TT?6qb8&rx&?h3sW>MmA$LYer`oAqa zv|xunJkPSElEcr1M&$7EmFa>N{wA!jocaSHYZBIuEUvKDrK^k9Y_2$1wI-2ICzfVX z4l4!c2^t+2=*tcrSU)06?uMll!%3L@TkpWmP%IW?kMO4nm}j)cj-t}g{tXvnTrCWD zi{qU)Jr_-m2#e2@8>W-6_?4N|Wz}qY{QBW;aomtRHS@jKM})=eEW#KkVezBCx(*!Q zqE%~$yUFp{_x9etBO}7(HDgcOpLP<9JA@VU`(U z7bT8qtF!510cvn>i9OKddib$cHi_4_Zw*DmoeY67l%L#b&hT*Ofu8mtB?84VOXqT# ztr)=sOD%$>|dVmAwcU&r}CjW(eM_XV}q|wvV?D90(-7U=ycSDog?P+NA*!2bRa7VN)e&r%turt|Y6Xacq{HcI z@-}$fE$#+aON-Yt)EHV^Zuih*@QN`kyyV*r=uVZ1NlPzm6#%bs@NAyU1}WC|wivkJ z6u=Oljkp6rlM`i3jzuxzy-#ja(3a(SB4eo@m!GcMA1-P2ceHam(J>#&G0*}uPa2Wd zn`6tVZz{h<3X(5TIq9KQkjhD(mP0DvPKw2F*b@07KxS2>5Kssx1QY@a0fm4RY!{K0NPOH6{JKC%YM zL@`lF6{~hi^hN1=4%vc^{FM}xQ(7oP^oL|7N;K0J`Ff1>-1P7h=kV!CnrpXP)O1RL z|K{vy*0b0Bysdn8g%L43qM4?7dv=7v0bl6@P_)^lH+=Ys{N@pICj6$5XeG@=xESGs zIU#K>Dd>BCg7qUY2@8 zzN^wq#Ndzag^xuOD|X2D^BQojA{g_94Ed;LB1->^GWPUNe9NGMLO>y)5Kssx1pem; zgm>L`#J#KL;5obQ-D}>}c<)#J{{hK%awsX&_dc5XBdM=ddP^W{8 z4zfD5@j+W3=$yY-rb13F``!KH#iKp~(IPzWdl6auFjfp|0+ z#9v|3=SdWof4^GZ=NFOk9Hixmo(}fM)T*pPKp~(IPzWdl6apgvflB)Y`T=ycDNclM zvdaU#QINmC;XmBLdbOV@M@gj>0tx|zfI>hapb$_9C Date: Fri, 12 Mar 2021 13:27:43 +0100 Subject: [PATCH 8/8] Documentation file source --- tests/testdata/data-sources.md | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/testdata/data-sources.md b/tests/testdata/data-sources.md index e9e564b..b6ec739 100644 --- a/tests/testdata/data-sources.md +++ b/tests/testdata/data-sources.md @@ -20,6 +20,7 @@ | [Tkrajina] | gpx1.1_with_all_fields.gpx | gpx | Apache License 2.0 | | [geoextent] | ifgi_to_denkpause.shp | shp | PDDL | | [geoextent] | wandelroute_maastricht.gpkg | gpkg | PDDL | +| [geoextent] | zeroes.nc | netcdf | PDDL | | [Copernicus] | MSK_SNWPRB_60m | jp2 | [Copernicus Sentinel Data] | | [Zenodo](https://zenodo.org/record/4323616) | Churfirsten_30m | asc | CC-BY 4.0 |