maps4fs 2.0.2__py3-none-any.whl → 2.0.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. maps4fs/__init__.py +3 -2
  2. maps4fs/generator/component/dem.py +1 -2
  3. maps4fs/generator/map.py +2 -1
  4. {maps4fs-2.0.2.dist-info → maps4fs-2.0.4.dist-info}/METADATA +13 -54
  5. maps4fs-2.0.4.dist-info/RECORD +27 -0
  6. maps4fs/generator/dtm/__init__.py +0 -27
  7. maps4fs/generator/dtm/arctic.py +0 -74
  8. maps4fs/generator/dtm/baden.py +0 -31
  9. maps4fs/generator/dtm/base/wcs.py +0 -80
  10. maps4fs/generator/dtm/base/wms.py +0 -71
  11. maps4fs/generator/dtm/bavaria.py +0 -113
  12. maps4fs/generator/dtm/canada.py +0 -37
  13. maps4fs/generator/dtm/czech.py +0 -36
  14. maps4fs/generator/dtm/denmark.py +0 -50
  15. maps4fs/generator/dtm/dtm.py +0 -543
  16. maps4fs/generator/dtm/england.py +0 -31
  17. maps4fs/generator/dtm/finland.py +0 -56
  18. maps4fs/generator/dtm/flanders.py +0 -34
  19. maps4fs/generator/dtm/france.py +0 -69
  20. maps4fs/generator/dtm/hessen.py +0 -31
  21. maps4fs/generator/dtm/italy.py +0 -40
  22. maps4fs/generator/dtm/lithuania.py +0 -66
  23. maps4fs/generator/dtm/mv.py +0 -42
  24. maps4fs/generator/dtm/niedersachsen.py +0 -38
  25. maps4fs/generator/dtm/norway.py +0 -41
  26. maps4fs/generator/dtm/nrw.py +0 -30
  27. maps4fs/generator/dtm/rema.py +0 -74
  28. maps4fs/generator/dtm/sachsenanhalt.py +0 -36
  29. maps4fs/generator/dtm/scotland.py +0 -118
  30. maps4fs/generator/dtm/spain.py +0 -33
  31. maps4fs/generator/dtm/srtm.py +0 -122
  32. maps4fs/generator/dtm/switzerland.py +0 -104
  33. maps4fs/generator/dtm/thuringia.py +0 -60
  34. maps4fs/generator/dtm/usgs_wcs.py +0 -35
  35. maps4fs/generator/dtm/utils.py +0 -61
  36. maps4fs/generator/dtm/wales.py +0 -123
  37. maps4fs-2.0.2.dist-info/RECORD +0 -58
  38. {maps4fs-2.0.2.dist-info → maps4fs-2.0.4.dist-info}/WHEEL +0 -0
  39. {maps4fs-2.0.2.dist-info → maps4fs-2.0.4.dist-info}/licenses/LICENSE.md +0 -0
  40. {maps4fs-2.0.2.dist-info → maps4fs-2.0.4.dist-info}/top_level.txt +0 -0
@@ -1,118 +0,0 @@
1
- """This module contains provider of Scotland data."""
2
-
3
- import os
4
-
5
- import requests
6
-
7
- from maps4fs.generator.dtm.dtm import DTMProvider, DTMProviderSettings
8
-
9
-
10
- class ScotlandProviderSettings(DTMProviderSettings):
11
- """Settings for the Scotland provider."""
12
-
13
- dataset: dict | str = {
14
- "scotland-gov/lidar/phase-1/dtm": "LiDAR for Scotland Phase I DTM",
15
- "scotland-gov/lidar/phase-2/dtm": "LiDAR for Scotland Phase II DTM",
16
- "scotland-gov/lidar/phase-3/dtm": "LiDAR for Scotland Phase III DTM",
17
- "scotland-gov/lidar/phase-4/dtm": "LiDAR for Scotland Phase IV DTM",
18
- "scotland-gov/lidar/phase-5/dtm": "LiDAR for Scotland Phase V DTM",
19
- "scotland-gov/lidar/phase-6/dtm": "LiDAR for Scotland Phase VI DTM",
20
- "scotland-gov/lidar/hes/hes-2010/dtm": (
21
- "HES LiDAR Data Stirling City and surrounding area (2010) DTM"
22
- ),
23
- "scotland-gov/lidar/hes/hes-2010s10/dtm": (
24
- "LiDAR for Historic Environment Scotland Scottish Ten Project (2010) DTM"
25
- ),
26
- "scotland-gov/lidar/hes/hes-2016-2017/dtm": (
27
- "LiDAR for Historic Environment Scotland Projects (2016-2017 sub project 4) DTM"
28
- ),
29
- "scotland-gov/lidar/hes/hes-2016/dtm": (
30
- "LiDAR for Historic Environment Scotland Projects (2016) DTM"
31
- ),
32
- "scotland-gov/lidar/hes/hes-2017/dtm": (
33
- "LiDAR for Historic Environment Scotland Projects (2017) DTM"
34
- ),
35
- "scotland-gov/lidar/hes/hes-2017sp3/dtm": (
36
- "LiDAR for Historic Environment Scotland Project (2017 Sub Project 3) DTM"
37
- ),
38
- "scotland-gov/lidar/hes/hes-luing/dtm": (
39
- "LiDAR for Historic Environment Scotland Projects Isle of Luing DTM"
40
- ),
41
- "scotland-gov/lidar/outerheb-2019/dtm/25cm": "LiDAR for Outer Hebrides 2019 - 25cm DTM",
42
- "scotland-gov/lidar/outerheb-2019/dtm/50cm": "LiDAR for Outer Hebrides 2019 - 50cm DTM",
43
- }
44
-
45
-
46
- class ScotlandProvider(DTMProvider):
47
- """Provider of Scotland."""
48
-
49
- _code = "scotland"
50
- _name = "Scotland LiDAR"
51
- _region = "UK"
52
- _icon = "🏴󠁧󠁢󠁳󠁣󠁴󠁿"
53
- _resolution = "variable"
54
- _settings = ScotlandProviderSettings
55
- _author = "[kbrandwijk](https://github.com/kbrandwijk)"
56
- _is_community = True
57
- _instructions = (
58
- "Coverage for Scotland is very limited. "
59
- "Make sure to check the [coverage map](https://remotesensingdata.gov.scot/data#/map)."
60
- )
61
- _extents = [
62
- (60.2151105070992756, 54.5525982243521881, -1.1045617513147328, -6.7070796770431951)
63
- ]
64
-
65
- _url = "https://srsp-catalog.jncc.gov.uk/search/product"
66
-
67
- def download_tiles(self):
68
- download_urls = self.get_download_urls()
69
- all_tif_files = self.download_tif_files(download_urls, self.shared_tiff_path)
70
- return all_tif_files
71
-
72
- def __init__(self, *args, **kwargs):
73
- super().__init__(*args, **kwargs)
74
- self.shared_tiff_path = os.path.join(self._tile_directory, "shared")
75
- os.makedirs(self.shared_tiff_path, exist_ok=True)
76
-
77
- def get_download_urls(self) -> list[str]:
78
- """Get download URLs of the GeoTIFF files from the USGS API.
79
-
80
- Returns:
81
- list: List of download URLs.
82
- """
83
- urls = []
84
- try:
85
- # Make the GET request
86
- (north, south, east, west) = self.get_bbox()
87
- response = requests.post( # pylint: disable=W3101
88
- self.url, # type: ignore
89
- json={
90
- "collections": (
91
- [self.user_settings.dataset] if self.user_settings else [] # type: ignore
92
- ),
93
- "footprint": (
94
- f"POLYGON(({west} {south}, {west} {north}, "
95
- f"{east} {north}, {east} {south}, {west} {south}))"
96
- ),
97
- "offset": 0,
98
- "limit": 100,
99
- "spatialop": "intersects",
100
- },
101
- timeout=60,
102
- )
103
- self.logger.debug("Getting file locations from JNCC...")
104
-
105
- # Check if the request was successful (HTTP status code 200)
106
- if response.status_code == 200:
107
- # Parse the JSON response
108
- json_data = response.json()
109
- items = json_data["result"]
110
- for item in items:
111
- urls.append(item["data"]["product"]["http"]["url"])
112
- # self.download_tif_files(urls)
113
- else:
114
- self.logger.error("Failed to get data. HTTP Status Code: %s", response.status_code)
115
- except requests.exceptions.RequestException as e:
116
- self.logger.error("Failed to get data. Error: %s", e)
117
- self.logger.debug("Received %s urls", len(urls))
118
- return urls
@@ -1,33 +0,0 @@
1
- """This module contains provider of Spain data."""
2
-
3
- from maps4fs.generator.dtm.base.wcs import WCSProvider
4
- from maps4fs.generator.dtm.dtm import DTMProvider
5
-
6
-
7
- class SpainProvider(WCSProvider, DTMProvider):
8
- """Provider of Spain data."""
9
-
10
- _code = "spain"
11
- _name = "Spain"
12
- _region = "ES"
13
- _icon = "🇪🇸"
14
- _resolution = 5
15
- _author = "[kbrandwijk](https://github.com/kbrandwijk)"
16
- _is_community = True
17
- _is_base = False
18
- _extents = [
19
- (43.9299999999999997, 27.6299999999999990, 4.9400000000000004, -18.2100000000000009)
20
- ]
21
-
22
- _url = "https://servicios.idee.es/wcs-inspire/mdt"
23
- _wcs_version = "2.0.1"
24
- _source_crs = "EPSG:25830"
25
- _tile_size = 1000
26
-
27
- def get_wcs_parameters(self, tile: tuple[float, float, float, float]) -> dict:
28
- return {
29
- "identifier": ["Elevacion25830_5"],
30
- "subsets": [("y", str(tile[0]), str(tile[2])), ("x", str(tile[1]), str(tile[3]))],
31
- "format": "GEOTIFFINT16",
32
- "timeout": 600,
33
- }
@@ -1,122 +0,0 @@
1
- """This module contains provider of Shuttle Radar Topography Mission (SRTM) 30m data."""
2
-
3
- # Author: https://github.com/iwatkot
4
-
5
- import gzip
6
- import math
7
- import os
8
- import shutil
9
-
10
- import requests
11
-
12
- from maps4fs.generator.dtm.dtm import DTMProvider
13
-
14
-
15
- class SRTM30Provider(DTMProvider):
16
- """Provider of Shuttle Radar Topography Mission (SRTM) 30m data."""
17
-
18
- _code = "srtm30"
19
- _name = "SRTM 30 m"
20
- _region = "Global"
21
- _icon = "🌎"
22
- _resolution = 30.0
23
-
24
- _url = "https://elevation-tiles-prod.s3.amazonaws.com/skadi/{latitude_band}/{tile_name}.hgt.gz"
25
-
26
- _author = "[iwatkot](https://github.com/iwatkot)"
27
-
28
- # _instructions = "ℹ️ Recommended settings: \nDEM Settings -> Blur Radius: **35**"
29
-
30
- _default_settings = {"DEMSettings": {"blur_radius": 35}}
31
-
32
- def __init__(self, *args, **kwargs):
33
- super().__init__(*args, **kwargs)
34
- self.hgt_directory = os.path.join(self._tile_directory, "hgt")
35
- self.gz_directory = os.path.join(self._tile_directory, "gz")
36
- os.makedirs(self.hgt_directory, exist_ok=True)
37
- os.makedirs(self.gz_directory, exist_ok=True)
38
-
39
- def download_tiles(self):
40
- """Download SRTM tiles."""
41
- north, south, east, west = self.get_bbox()
42
-
43
- tiles = []
44
- # Look at each corner of the bbox in case the bbox spans across multiple tiles
45
- for pair in [(north, east), (south, west), (south, east), (north, west)]:
46
- tile_parameters = self.get_tile_parameters(*pair)
47
- tile_name = tile_parameters["tile_name"]
48
- decompressed_tile_path = os.path.join(self.hgt_directory, f"{tile_name}.hgt")
49
-
50
- if not os.path.isfile(decompressed_tile_path):
51
- compressed_tile_path = os.path.join(self.gz_directory, f"{tile_name}.hgt.gz")
52
- if not self.get_or_download_tile(compressed_tile_path, **tile_parameters):
53
- raise FileNotFoundError(f"Tile {tile_name} not found.")
54
-
55
- with gzip.open(compressed_tile_path, "rb") as f_in:
56
- with open(decompressed_tile_path, "wb") as f_out:
57
- shutil.copyfileobj(f_in, f_out)
58
- tiles.append(decompressed_tile_path)
59
-
60
- return list(set(tiles))
61
-
62
- # region provider specific helpers
63
- def download_tile(self, output_path: str, **kwargs) -> bool:
64
- """Download a tile from the provider.
65
-
66
- Arguments:
67
- output_path (str): Path to save the downloaded tile.
68
-
69
- Returns:
70
- bool: True if the tile was downloaded successfully, False otherwise.
71
- """
72
- url = self.formatted_url(**kwargs)
73
- response = requests.get(url, stream=True, timeout=10)
74
- if response.status_code == 200:
75
- with open(output_path, "wb") as file:
76
- for chunk in response.iter_content(chunk_size=1024):
77
- file.write(chunk)
78
- return True
79
- return False
80
-
81
- def get_or_download_tile(self, output_path: str, **kwargs) -> str | None:
82
- """Get or download a tile from the provider.
83
-
84
- Arguments:
85
- output_path (str): Path to save the downloaded tile.
86
-
87
- Returns:
88
- str: Path to the downloaded tile or None if the tile not exists and was
89
- not downloaded.
90
- """
91
- if not os.path.exists(output_path):
92
- if not self.download_tile(output_path, **kwargs):
93
- return None
94
- return output_path
95
-
96
- def get_tile_parameters(self, *args) -> dict[str, str]:
97
- """Returns latitude band and tile name for SRTM tile from coordinates.
98
-
99
- Arguments:
100
- lat (float): Latitude.
101
- lon (float): Longitude.
102
-
103
- Returns:
104
- dict: Tile parameters.
105
- """
106
- lat, lon = args
107
-
108
- tile_latitude = math.floor(lat)
109
- tile_longitude = math.floor(lon)
110
-
111
- latitude_band = f"N{abs(tile_latitude):02d}" if lat >= 0 else f"S{abs(tile_latitude):02d}"
112
- if lon < 0:
113
- tile_name = f"{latitude_band}W{abs(tile_longitude):03d}"
114
- else:
115
- tile_name = f"{latitude_band}E{abs(tile_longitude):03d}"
116
-
117
- self.logger.debug(
118
- "Detected tile name: %s for coordinates: lat %s, lon %s.", tile_name, lat, lon
119
- )
120
- return {"latitude_band": latitude_band, "tile_name": tile_name}
121
-
122
- # endregion
@@ -1,104 +0,0 @@
1
- """This module contains provider of Switzerland data."""
2
-
3
- import json
4
- import os
5
-
6
- import requests
7
-
8
- from maps4fs.generator.dtm import utils
9
- from maps4fs.generator.dtm.dtm import DTMProvider, DTMProviderSettings
10
-
11
-
12
- class SwitzerlandProviderSettings(DTMProviderSettings):
13
- """Settings for the Switzerland provider."""
14
-
15
- resolution: tuple | str = ("0.5", "2.0")
16
-
17
-
18
- class SwitzerlandProvider(DTMProvider):
19
- """Provider of Switzerland."""
20
-
21
- _code = "switzerland"
22
- _name = "Switzerland"
23
- _region = "CH"
24
- _icon = "🇨🇭"
25
- _resolution = "0.5-2"
26
- _settings = SwitzerlandProviderSettings
27
- _author = "[kbrandwijk](https://github.com/kbrandwijk)"
28
- _is_community = True
29
-
30
- _extents = [(47.8308275417, 45.7769477403, 10.4427014502, 6.02260949059)]
31
-
32
- _url = (
33
- "https://ogd.swisstopo.admin.ch/services/swiseld/"
34
- "services/assets/ch.swisstopo.swissalti3d/search"
35
- )
36
-
37
- def download_tiles(self):
38
- download_urls = self.get_download_urls()
39
- all_tif_files = self.download_tif_files(download_urls, self.shared_tiff_path)
40
- return all_tif_files
41
-
42
- def __init__(self, *args, **kwargs):
43
- super().__init__(*args, **kwargs)
44
- self.shared_tiff_path = os.path.join(self._tile_directory, "shared")
45
- os.makedirs(self.shared_tiff_path, exist_ok=True)
46
-
47
- def get_download_urls(self) -> list[str]:
48
- """Get download URLs of the GeoTIFF files from the USGS API.
49
-
50
- Returns:
51
- list: List of download URLs.
52
- """
53
- urls = []
54
- try:
55
- bbox = self.get_bbox()
56
- north, south, east, west = utils.transform_bbox(bbox, "EPSG:2056")
57
-
58
- params = {
59
- "format": "image/tiff; application=geotiff; profile=cloud-optimized",
60
- "resolution": self.user_settings.resolution, # type: ignore
61
- "srid": 2056,
62
- "state": "current",
63
- }
64
-
65
- data = {
66
- "geometry": json.dumps(
67
- {
68
- "type": "Polygon",
69
- "crs": {"type": "name", "properties": {"name": "EPSG:2056"}},
70
- "coordinates": [
71
- [
72
- [north, east],
73
- [south, east],
74
- [south, west],
75
- [north, west],
76
- [north, east],
77
- ]
78
- ],
79
- }
80
- )
81
- }
82
-
83
- response = requests.post( # pylint: disable=W3101
84
- self.url, # type: ignore
85
- params=params,
86
- data=data,
87
- headers={"Content-Type": "application/x-www-form-urlencoded"},
88
- timeout=60,
89
- )
90
- self.logger.debug("Getting file locations...")
91
-
92
- # Check if the request was successful (HTTP status code 200)
93
- if response.status_code == 200:
94
- # Parse the JSON response
95
- json_data = response.json()
96
- items = json_data["items"]
97
- for item in items:
98
- urls.append(item["ass_asset_href"])
99
- else:
100
- self.logger.error("Failed to get data. HTTP Status Code: %s", response.status_code)
101
- except requests.exceptions.RequestException as e:
102
- self.logger.error("Failed to get data. Error: %s", e)
103
- self.logger.debug("Received %s urls", len(urls))
104
- return urls
@@ -1,60 +0,0 @@
1
- """This module contains provider of Thuringia data."""
2
-
3
- import os
4
- from maps4fs.generator.dtm import utils
5
- from maps4fs.generator.dtm.dtm import DTMProvider
6
-
7
- class ThuringiaProvider(DTMProvider):
8
- """Provider of Thuringia data.
9
- Data is provided by the Kompetenzzentrum Geodateninfrastruktur Thüringen (© GDI-Th) and available
10
- at https://geoportal.thueringen.de/gdi-th/download-offene-geodaten/download-hoehendaten under BY 2.0 license.
11
- """
12
- _code = "thuringia"
13
- _name = "Thüringen DGM1"
14
- _region = "DE"
15
- _icon = "🇩🇪󠁥󠁢󠁹󠁿"
16
- _resolution = 1
17
- _author = "[H4rdB4se](https://github.com/H4rdB4se)"
18
- _is_community = True
19
- _instructions = None
20
- _extents = [(51.5997, 50.2070, 12.69674, 9.8548)]
21
-
22
- def __init__(self, *args, **kwargs):
23
- super().__init__(*args, **kwargs)
24
- self.tiff_path = os.path.join(self._tile_directory, "tiffs")
25
- os.makedirs(self.tiff_path, exist_ok=True)
26
-
27
- def download_tiles(self) -> list[str]:
28
- bbox = self.get_bbox()
29
- west, east, north, south = utils.transform_bbox(bbox, "EPSG:25832")
30
- download_urls = self.get_download_urls(north, south, east, west)
31
- all_tif_files = self.download_tif_files(download_urls, self.tiff_path)
32
- return all_tif_files
33
-
34
- @staticmethod
35
- def get_first_n_digits(value: float, digits: int) -> int:
36
- """Get the first n digits of a number."""
37
- return int(str(value)[:digits])
38
-
39
- def get_download_urls(self, north: float, south: float, east: float, west: float) -> list[str]:
40
- """Calculate all possible tiles within the bounding box.
41
-
42
- Args:
43
- north (float): Northern boundary.
44
- south (float): Southern boundary.
45
- east (float): Eastern boundary.
46
- west (float): Western boundary.
47
-
48
- Returns:
49
- list: List of tile names.
50
- """
51
- urls = []
52
- lat = self.get_first_n_digits(south, 4)
53
- while lat <= self.get_first_n_digits(north, 4):
54
- lon = self.get_first_n_digits(west, 3)
55
- while lon <= self.get_first_n_digits(east, 3):
56
- tile_url = f"https://geoportal.geoportal-th.de/hoehendaten/DGM/dgm_2020-2025/dgm1_32_{lon}_{lat}_1_th_2020-2025.zip"
57
- urls.append(tile_url)
58
- lon += 1
59
- lat += 1
60
- return urls
@@ -1,35 +0,0 @@
1
- """This module contains provider of USGS data."""
2
-
3
- from maps4fs.generator.dtm.base.wcs import WCSProvider
4
- from maps4fs.generator.dtm.dtm import DTMProvider
5
-
6
-
7
- class USGSWCSProvider(WCSProvider, DTMProvider):
8
- """Provider of USGS data."""
9
-
10
- _code = "usgs_wcs"
11
- _name = "USGS"
12
- _region = "USA"
13
- _icon = "🇺🇸"
14
- _resolution = "1-90"
15
- _author = "[kbrandwijk](https://github.com/kbrandwijk)"
16
- _is_community = True
17
- _instructions = None
18
- _is_base = False
19
- _extents = [(50.0, 17.0, -64.0, -162.0)]
20
-
21
- _url = "https://elevation.nationalmap.gov/arcgis/services/3DEPElevation/ImageServer/WCSServer"
22
- _wcs_version = "1.0.0"
23
- _source_crs = "EPSG:3857"
24
- _tile_size = 1000
25
- _is_multipart = False
26
-
27
- def get_wcs_parameters(self, tile):
28
- return {
29
- "identifier": "DEP3Elevation",
30
- "bbox": (tile[1], tile[0], tile[3], tile[2]),
31
- "crs": "EPSG:3857",
32
- "width": 1000,
33
- "height": 1000,
34
- "format": "GeoTIFF",
35
- }
@@ -1,61 +0,0 @@
1
- """Utility functions for the DTM generator."""
2
-
3
- import numpy as np
4
- from pyproj import Transformer
5
-
6
-
7
- def tile_bbox(
8
- bbox: tuple[float, float, float, float], tile_size: float
9
- ) -> list[tuple[float, float, float, float]]:
10
- """Tile the bounding box into smaller bounding boxes of a specified size.
11
-
12
- Arguments:
13
- bbox (tuple): Bounding box to tile (north, south, east, west).
14
- tile_size (int): Size of the tiles in meters.
15
-
16
- Returns:
17
- list: List of smaller bounding boxes (north, south, east, west).
18
- """
19
- north, south, east, west = bbox
20
- x_coords = np.arange(west, east, tile_size if east > west else -tile_size)
21
- y_coords = np.arange(north, south, tile_size if south > north else -tile_size)
22
- x_coords = np.append(x_coords, east).astype(x_coords.dtype)
23
- y_coords = np.append(y_coords, south).astype(y_coords.dtype)
24
-
25
- x_min, y_min = np.meshgrid(x_coords[:-1], y_coords[:-1], indexing="ij")
26
- x_max, y_max = np.meshgrid(x_coords[1:], y_coords[1:], indexing="ij")
27
-
28
- tiles = np.stack(
29
- [x_min.ravel(), y_min.ravel(), x_max.ravel(), y_max.ravel()], axis=1, dtype=float
30
- )
31
-
32
- return [tuple(tile[i].item() for i in range(4)) for tile in tiles]
33
-
34
-
35
- def transform_bbox(
36
- bbox: tuple[float, float, float, float], to_crs: str
37
- ) -> tuple[float, float, float, float]:
38
- """Transform the bounding box to a different coordinate reference system (CRS).
39
-
40
- Arguments:
41
- bbox (tuple): Bounding box to transform (north, south, east, west).
42
- to_crs (str): Target CRS (e.g., EPSG:4326 for CRS:84).
43
-
44
- Returns:
45
- tuple: Transformed bounding box (north, south, east, west).
46
- """
47
- transformer = Transformer.from_crs("epsg:4326", to_crs)
48
- north, south, east, west = bbox
49
-
50
- # EPSG:4326 is lat, lon, so xx is lat and yy is lon
51
- bottom_left_x, bottom_left_y = transformer.transform(xx=south, yy=west)
52
- top_left_x, top_left_y = transformer.transform(xx=north, yy=west)
53
- top_right_x, top_right_y = transformer.transform(xx=north, yy=east)
54
- bottom_right_x, bottom_right_y = transformer.transform(xx=south, yy=east)
55
-
56
- west = min(bottom_left_y, bottom_right_y)
57
- east = max(top_left_y, top_right_y)
58
- north = min(bottom_left_x, top_left_x)
59
- south = max(bottom_right_x, top_right_x)
60
-
61
- return north, south, east, west
@@ -1,123 +0,0 @@
1
- """This module contains provider of Wales data."""
2
-
3
- import os
4
- from math import floor, ceil
5
-
6
- import requests
7
- from pyproj import Transformer
8
-
9
- from maps4fs.generator.dtm.dtm import DTMProvider
10
-
11
-
12
- class WalesProvider(DTMProvider):
13
- """Provider of Wales data."""
14
-
15
- _code = "wales"
16
- _name = "Wales 1M"
17
- _region = "UK"
18
- _icon = "🏴󠁧󠁢󠁷󠁬󠁳󠁿󠁧󠁢󠁷󠁬󠁳󠁿"
19
- _resolution = 1
20
- _author = "[garnshared](https://github.com/garnshared)"
21
- _is_community = True
22
- _instructions = None
23
- _is_base = False
24
- _extents = [(55.87708724246775, 49.85060473351981, 2.0842821419111135, -7.104775741839742)]
25
-
26
- _url = "https://datamap.gov.wales/geoserver/ows" # pylint: disable=line-too-long
27
- _wms_version = "1.1.1"
28
- _source_crs = "EPSG:27700"
29
- _size = 1000
30
-
31
- def download_tiles(self):
32
- download_urls = self.get_download_urls()
33
- all_tif_files = self.download_tif_files(download_urls, self.shared_tiff_path)
34
- return all_tif_files
35
-
36
- def __init__(self, *args, **kwargs):
37
- super().__init__(*args, **kwargs)
38
- self.shared_tiff_path = os.path.join(self._tile_directory, "shared")
39
- os.makedirs(self.shared_tiff_path, exist_ok=True)
40
-
41
- def get_download_urls(self) -> list[str]:
42
- """Get download URLs of the GeoTIFF files from the tile catalogue.
43
-
44
- Returns:
45
- list: List of download URLs.
46
- """
47
- urls = []
48
-
49
- transformer = Transformer.from_crs("EPSG:4326", "EPSG:27700", always_xy=True)
50
-
51
-
52
- # Make the GET request
53
- north, south, east, west = self.get_bbox()
54
-
55
- # Transform the coordinates
56
- west_transformed, south_transformed = transformer.transform(west, south)
57
- east_transformed, north_transformed = transformer.transform(east, north)
58
-
59
- # Helper function to snap coordinate to nearest 1000 grid
60
- def snap_to_grid(value, func):
61
- return int(func(value * 0.001) * 1000)
62
-
63
- # Snap bounding box coordinates to a 1000-unit grid
64
- x_min = snap_to_grid(west_transformed, floor)
65
- y_min = snap_to_grid(south_transformed, floor)
66
- x_max = snap_to_grid(east_transformed, ceil)
67
- y_max = snap_to_grid(north_transformed, ceil)
68
-
69
- # Calculate the number of tiles in x and y directions
70
- x_tiles = abs(x_max - x_min) // 1000
71
- y_tiles = abs(y_max - y_min) // 1000
72
-
73
-
74
- for x_tile in range(x_tiles):
75
- for y_tile in range(y_tiles):
76
- b_west = x_min + 1000 * (x_tile + 1) - 855
77
- b_south = y_min + 1000 * (y_tile + 1) - 855
78
- b_east = b_west + 145
79
- b_north = b_south + 145
80
-
81
- try:
82
- params = {
83
- "service": "WMS",
84
- "version": self._wms_version,
85
- "request": "GetFeatureInfo",
86
- "exceptions": "application/json",
87
- "layers": "geonode:welsh_government_lidar_tile_catalogue_2020_2023",
88
- "query_layers": "geonode:welsh_government_lidar_tile_catalogue_2020_2023",
89
- "styles": "",
90
- "x": 51,
91
- "y": 51,
92
- "height": 101,
93
- "width": 101,
94
- "srs": self._source_crs,
95
- "bbox": f"{b_west},{b_south},{b_east},{b_north}",
96
- "feature_count": 10,
97
- "info_format": "application/json",
98
- "ENV": "mapstore_language:en"
99
- }
100
-
101
- response = requests.get(# pylint: disable=W3101
102
- self.url, # type: ignore
103
- params=params, # type: ignore
104
- timeout=60
105
- )
106
-
107
- self.logger.debug("Getting file locations from Welsh Government WMS GetFeatureInfo...")
108
-
109
- # Check if the request was successful (HTTP status code 200)
110
- if response.status_code == 200:
111
- json_data = response.json()
112
- features = json_data.get("features", [])
113
- for feature in features:
114
- dtm_link = feature.get("properties", {}).get("dtm_link")
115
- if dtm_link:
116
- urls.append("https://"+dtm_link)
117
- else:
118
- self.logger.error("Failed to get data. HTTP Status Code: %s", response.status_code)
119
- except Exception as e:
120
- self.logger.error("Failed to get data. Error: %s", e)
121
-
122
- self.logger.debug("Received %s urls", len(urls))
123
- return urls