From 977e66565784fc36528e50dc86b0b98a75440609 Mon Sep 17 00:00:00 2001 From: Kim Brandwijk Date: Tue, 21 Jan 2025 05:59:09 -0500 Subject: [PATCH] ArcticDEM, REMA Antarctic, Czechia, Sachsen-Anhalt DTM providers * ArcticDEM DTM provider * Add Antarctic DTM provider * Add Czechia provider * Sachsen-Anhalt DTM provider * linting --- README.md | 6 ++- maps4fs/__init__.py | 4 ++ maps4fs/generator/dtm/arctic.py | 75 ++++++++++++++++++++++++++ maps4fs/generator/dtm/czech.py | 35 ++++++++++++ maps4fs/generator/dtm/rema.py | 75 ++++++++++++++++++++++++++ maps4fs/generator/dtm/sachsenanhalt.py | 34 ++++++++++++ 6 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 maps4fs/generator/dtm/arctic.py create mode 100644 maps4fs/generator/dtm/czech.py create mode 100644 maps4fs/generator/dtm/rema.py create mode 100644 maps4fs/generator/dtm/sachsenanhalt.py diff --git a/README.md b/README.md index fab88386..a4352c05 100644 --- a/README.md +++ b/README.md @@ -656,13 +656,15 @@ The generator supports adding the own DTM providers, please refer to the [DTM Pr ### Supported DTM providers -![coverage map](https://github.com/user-attachments/assets/e02a4b5e-c5a9-4e6f-826f-048081704ef9) +![coverage map](https://github.com/user-attachments/assets/be5c5ce1-7318-4352-97eb-efba7ec587cd) In addition to SRTM 30m, which provides global coverage, the map above highlights all countries and/or regions where higher resolution coverage is provided by one of the DTM providers. | Provider Name | Resolution | Developer | | ---------------------------------- | ------------ | ------------------------------------------- | | ๐ŸŒŽ SRTM30 | 30 meters | [iwatkot](https://github.com/iwatkot) | +| ๐ŸŒŽ ArcticDEM | 2 meters | [kbrandwijk](https://github.com/kbrandwijk) | +| ๐ŸŒŽ REMA Antarctica | 2 meters | [kbrandwijk](https://github.com/kbrandwijk) | | ๐Ÿ‡บ๐Ÿ‡ธ USGS | 1-90 meters | [ZenJakey](https://github.com/ZenJakey) | | ๐Ÿด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ England | 1 meter | [kbrandwijk](https://github.com/kbrandwijk) | | ๐Ÿด๓ ง๓ ข๓ ณ๓ ฃ๓ ด๓ ฟ Scotland | 0.25-1 meter | [kbrandwijk](https://github.com/kbrandwijk) | @@ -672,6 +674,7 @@ In addition to SRTM 30m, which provides global coverage, the map above highlight | ๐Ÿ‡ฉ๐Ÿ‡ช Nordrhein-Westfalen, Germany | 1 meter | [kbrandwijk](https://github.com/kbrandwijk) | | ๐Ÿ‡ฉ๐Ÿ‡ช Mecklenburg-Vorpommern, Germany | 1-25 meter | [kbrandwijk](https://github.com/kbrandwijk) | | ๐Ÿ‡ฉ๐Ÿ‡ช Baden-Wรผrttemberg, Germany | 1 meter | [kbrandwijk](https://github.com/kbrandwijk) | +| ๐Ÿ‡ฉ๐Ÿ‡ช Sachsen-Anhalt, Germany | 1 meter | [kbrandwijk](https://github.com/kbrandwijk) | | ๐Ÿ‡จ๐Ÿ‡ฆ Canada | 1 meter | [kbrandwijk](https://github.com/kbrandwijk) | | ๐Ÿ‡ง๐Ÿ‡ช Flanders, Belgium | 1 meter | [kbrandwijk](https://github.com/kbrandwijk) | | ๐Ÿ‡ซ๐Ÿ‡ท France | 1 meter | [kbrandwijk](https://github.com/kbrandwijk) | @@ -681,6 +684,7 @@ In addition to SRTM 30m, which provides global coverage, the map above highlight | ๐Ÿ‡ซ๐Ÿ‡ฎ Finland | 2 meter | [kbrandwijk](https://github.com/kbrandwijk) | | ๐Ÿ‡ฉ๐Ÿ‡ฐ Denmark | 0.4 meter | [kbrandwijk](https://github.com/kbrandwijk) | | ๐Ÿ‡จ๐Ÿ‡ญ Switzerland | 0.5-2 meter | [kbrandwijk](https://github.com/kbrandwijk) | +| ๐Ÿ‡จ๐Ÿ‡ฟ Czech Republic | 5 meter | [kbrandwijk](https://github.com/kbrandwijk) | ## Special thanks diff --git a/maps4fs/__init__.py b/maps4fs/__init__.py index b3fa7e4a..ffc48e02 100644 --- a/maps4fs/__init__.py +++ b/maps4fs/__init__.py @@ -19,6 +19,10 @@ from maps4fs.generator.dtm.switzerland import SwitzerlandProvider from maps4fs.generator.dtm.mv import MecklenburgVorpommernProvider from maps4fs.generator.dtm.baden import BadenWurttembergProvider +from maps4fs.generator.dtm.arctic import ArcticProvider +from maps4fs.generator.dtm.rema import REMAProvider +from maps4fs.generator.dtm.czech import CzechProvider +from maps4fs.generator.dtm.sachsenanhalt import SachsenAnhaltProvider from maps4fs.generator.game import Game from maps4fs.generator.map import Map from maps4fs.generator.settings import ( diff --git a/maps4fs/generator/dtm/arctic.py b/maps4fs/generator/dtm/arctic.py new file mode 100644 index 00000000..8fef08e7 --- /dev/null +++ b/maps4fs/generator/dtm/arctic.py @@ -0,0 +1,75 @@ +"""This module contains provider of Arctic data.""" + +import os + +import requests + +from maps4fs.generator.dtm.dtm import DTMProvider + + +class ArcticProvider(DTMProvider): + """Provider of Arctic data.""" + + _code = "arctic" + _name = "ArcticDEM" + _region = "Global" + _icon = "๐ŸŒ" + _resolution = 2 + _author = "[kbrandwijk](https://github.com/kbrandwijk)" + _is_community = True + + _extents = (83.98823036056658, 50.7492704708152, 179.99698443265999, -180) + + _instructions = ( + "This provider source includes 2 meter DEM data for the entire Arctic region above 50 " + "degrees North. The tiles are very big, around 1 GB each, so downloading and processing " + "them can take a long time." + ) + + _url = "https://stac.pgc.umn.edu/api/v1/collections/arcticdem-mosaics-v4.1-2m/items" + + def download_tiles(self): + download_urls = self.get_download_urls() + all_tif_files = self.download_tif_files(download_urls, self.shared_tiff_path) + return all_tif_files + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.shared_tiff_path = os.path.join(self._tile_directory, "shared") + os.makedirs(self.shared_tiff_path, exist_ok=True) + + def get_download_urls(self) -> list[str]: + """Get download URLs of the GeoTIFF files from the OGC API. + + Returns: + list: List of download URLs. + """ + urls = [] + + try: + # Make the GET request + north, south, east, west = self.get_bbox() + print(north, south, east, west) + response = requests.get( # pylint: disable=W3101 + self.url, # type: ignore + params={ + "bbox": f"{west},{south},{east},{north}", + "limit": "100", + }, + timeout=60, + ) + self.logger.debug("Getting file locations from ArcticDEM OGC API...") + + # Check if the request was successful (HTTP status code 200) + if response.status_code == 200: + # Parse the JSON response + json_data = response.json() + items = json_data["features"] + for item in items: + urls.append(item["assets"]["dem"]["href"]) + else: + self.logger.error("Failed to get data. HTTP Status Code: %s", response.status_code) + except requests.exceptions.RequestException as e: + self.logger.error("Failed to get data. Error: %s", e) + self.logger.debug("Received %s urls", len(urls)) + return urls diff --git a/maps4fs/generator/dtm/czech.py b/maps4fs/generator/dtm/czech.py new file mode 100644 index 00000000..47ea5f67 --- /dev/null +++ b/maps4fs/generator/dtm/czech.py @@ -0,0 +1,35 @@ +"""This module contains provider of Czech data.""" + +from maps4fs.generator.dtm.base.wcs import WCSProvider +from maps4fs.generator.dtm.dtm import DTMProvider + + +class CzechProvider(WCSProvider, DTMProvider): + """Provider of Czech data.""" + + _code = "czech" + _name = "Czech Republic" + _region = "CZ" + _icon = "๐Ÿ‡จ๐Ÿ‡ฟ" + _resolution = 5 + _author = "[kbrandwijk](https://github.com/kbrandwijk)" + _is_community = True + _instructions = None + _is_base = False + _extents = (51.0576876059846754, 48.4917065572081754, 18.9775933665038821, 12.0428143585602161) + + _url = "https://ags.cuzk.cz/arcgis2/services/INSPIRE_Nadmorska_vyska/ImageServer/WCSServer" # pylint: disable=line-too-long + _wcs_version = "1.0.0" + _source_crs = "EPSG:4326" + _tile_size = 0.05 + + def get_wcs_parameters(self, tile): + print("tile", tile) + return { + "identifier": "MD_LAS", + "crs": "EPSG:4326", + "bbox": tile, + "width": 1000, + "height": 1000, + "format": "GeoTIFF", + } diff --git a/maps4fs/generator/dtm/rema.py b/maps4fs/generator/dtm/rema.py new file mode 100644 index 00000000..ca47fed6 --- /dev/null +++ b/maps4fs/generator/dtm/rema.py @@ -0,0 +1,75 @@ +"""This module contains provider of Antarctic data.""" + +import os + +import requests + +from maps4fs.generator.dtm.dtm import DTMProvider + + +class REMAProvider(DTMProvider): + """Provider of Antarctic data.""" + + _code = "rema" + _name = "REMA Antarctica" + _region = "Global" + _icon = "๐ŸŒ" + _resolution = 2 + _author = "[kbrandwijk](https://github.com/kbrandwijk)" + _is_community = True + + _extents = (-53.5443873459092, -53.5443873459092, 179.99698443265999, -180) + + _instructions = ( + "This provider source includes 2 meter DEM data for the entire Antarctic region below 53 " + "degrees South. The tiles are very big, around 1 GB each, so downloading and processing " + "them can take a long time." + ) + + _url = "https://stac.pgc.umn.edu/api/v1/collections/rema-mosaics-v2.0-2m/items" + + def download_tiles(self): + download_urls = self.get_download_urls() + all_tif_files = self.download_tif_files(download_urls, self.shared_tiff_path) + return all_tif_files + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.shared_tiff_path = os.path.join(self._tile_directory, "shared") + os.makedirs(self.shared_tiff_path, exist_ok=True) + + def get_download_urls(self) -> list[str]: + """Get download URLs of the GeoTIFF files from the OGC API. + + Returns: + list: List of download URLs. + """ + urls = [] + + try: + # Make the GET request + north, south, east, west = self.get_bbox() + print(north, south, east, west) + response = requests.get( # pylint: disable=W3101 + self.url, # type: ignore + params={ + "bbox": f"{west},{south},{east},{north}", + "limit": "100", + }, + timeout=60, + ) + self.logger.debug("Getting file locations from REMA OGC API...") + + # Check if the request was successful (HTTP status code 200) + if response.status_code == 200: + # Parse the JSON response + json_data = response.json() + items = json_data["features"] + for item in items: + urls.append(item["assets"]["dem"]["href"]) + else: + self.logger.error("Failed to get data. HTTP Status Code: %s", response.status_code) + except requests.exceptions.RequestException as e: + self.logger.error("Failed to get data. Error: %s", e) + self.logger.debug("Received %s urls", len(urls)) + return urls diff --git a/maps4fs/generator/dtm/sachsenanhalt.py b/maps4fs/generator/dtm/sachsenanhalt.py new file mode 100644 index 00000000..51a70528 --- /dev/null +++ b/maps4fs/generator/dtm/sachsenanhalt.py @@ -0,0 +1,34 @@ +"""This module contains provider of Sachsen-Anhalt data.""" + +from maps4fs.generator.dtm.base.wcs import WCSProvider +from maps4fs.generator.dtm.dtm import DTMProvider + + +class SachsenAnhaltProvider(WCSProvider, DTMProvider): + """Provider of Sachsen-Anhalt data.""" + + _code = "sachsen-anhalt" + _name = "Sachsen-Anhalt" + _region = "DE" + _icon = "๐Ÿ‡ฉ๐Ÿ‡ช" + _resolution = 1 + _author = "[kbrandwijk](https://github.com/kbrandwijk)" + _is_community = True + _is_base = False + _extents = (53.0769416826493412, 50.8927195980075453, 13.3232545527125836, 10.5092298520646867) + + _url = "https://www.geodatenportal.sachsen-anhalt.de/wss/service/ST_LVermGeo_DGM1_WCS_OpenData/guest" # pylint: disable=line-too-long + _wcs_version = "1.0.0" + _source_crs = "EPSG:4326" + _tile_size = 0.02 + + def get_wcs_parameters(self, tile: tuple[float, float, float, float]) -> dict: + return { + "identifier": "1", + "bbox": tile, + "format": "GeoTIFF", + "crs": "EPSG:4326", + "width": 1000, + "height": 1000, + "timeout": 600, + }