maps4fs 1.7.5__py3-none-any.whl → 1.7.7__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.
- maps4fs/__init__.py +1 -0
- maps4fs/generator/dtm/bavaria.py +115 -0
- maps4fs/generator/dtm/dtm.py +70 -10
- maps4fs/generator/dtm/nrw.py +2 -2
- maps4fs/generator/dtm/usgs.py +1 -47
- maps4fs/generator/game.py +3 -2
- {maps4fs-1.7.5.dist-info → maps4fs-1.7.7.dist-info}/METADATA +1 -1
- {maps4fs-1.7.5.dist-info → maps4fs-1.7.7.dist-info}/RECORD +11 -10
- {maps4fs-1.7.5.dist-info → maps4fs-1.7.7.dist-info}/LICENSE.md +0 -0
- {maps4fs-1.7.5.dist-info → maps4fs-1.7.7.dist-info}/WHEEL +0 -0
- {maps4fs-1.7.5.dist-info → maps4fs-1.7.7.dist-info}/top_level.txt +0 -0
maps4fs/__init__.py
CHANGED
@@ -3,6 +3,7 @@ from maps4fs.generator.dtm.dtm import DTMProvider
|
|
3
3
|
from maps4fs.generator.dtm.srtm import SRTM30Provider, SRTM30ProviderSettings
|
4
4
|
from maps4fs.generator.dtm.usgs import USGSProvider, USGSProviderSettings
|
5
5
|
from maps4fs.generator.dtm.nrw import NRWProvider, NRWProviderSettings
|
6
|
+
from maps4fs.generator.dtm.bavaria import BavariaProvider, BavariaProviderSettings
|
6
7
|
from maps4fs.generator.game import Game
|
7
8
|
from maps4fs.generator.map import Map
|
8
9
|
from maps4fs.generator.settings import (
|
@@ -0,0 +1,115 @@
|
|
1
|
+
"""This module contains provider of Bavaria data."""
|
2
|
+
|
3
|
+
import os
|
4
|
+
|
5
|
+
from xml.etree import ElementTree as ET
|
6
|
+
import hashlib
|
7
|
+
import numpy as np
|
8
|
+
import requests
|
9
|
+
from maps4fs.generator.dtm.dtm import DTMProvider, DTMProviderSettings
|
10
|
+
|
11
|
+
class BavariaProviderSettings(DTMProviderSettings):
|
12
|
+
"""Settings for the Bavaria provider."""
|
13
|
+
|
14
|
+
|
15
|
+
class BavariaProvider(DTMProvider):
|
16
|
+
"""Provider of Bavaria Digital terrain model (DTM) 1m data.
|
17
|
+
Data is provided by the 'Bayerische Vermessungsverwaltung' and available
|
18
|
+
at https://geodaten.bayern.de/opengeodata/OpenDataDetail.html?pn=dgm1 under CC BY 4.0 license.
|
19
|
+
"""
|
20
|
+
|
21
|
+
_code = "bavaria"
|
22
|
+
_name = "Bavaria DGM1"
|
23
|
+
_region = "DE"
|
24
|
+
_icon = "🇩🇪"
|
25
|
+
_resolution = 1
|
26
|
+
_data: np.ndarray | None = None
|
27
|
+
_settings = BavariaProviderSettings
|
28
|
+
_author = "[H4rdB4se](https://github.com/H4rdB4se)"
|
29
|
+
_is_community = True
|
30
|
+
_instructions = None
|
31
|
+
|
32
|
+
def __init__(self, *args, **kwargs):
|
33
|
+
super().__init__(*args, **kwargs)
|
34
|
+
self.tiff_path = os.path.join(self._tile_directory, "tiffs")
|
35
|
+
os.makedirs(self.tiff_path, exist_ok=True)
|
36
|
+
self.meta4_path = os.path.join(self._tile_directory, "meta4")
|
37
|
+
os.makedirs(self.meta4_path, exist_ok=True)
|
38
|
+
|
39
|
+
def download_tiles(self) -> list[str]:
|
40
|
+
download_urls = self.get_meta_file_from_coords()
|
41
|
+
all_tif_files = self.download_tif_files(download_urls, self.tiff_path)
|
42
|
+
return all_tif_files
|
43
|
+
|
44
|
+
@staticmethod
|
45
|
+
def get_meta_file_name(north: float, south: float, east: float, west: float) -> str:
|
46
|
+
"""Generate a hashed file name for the .meta4 file.
|
47
|
+
|
48
|
+
Arguments:
|
49
|
+
north (float): Northern latitude.
|
50
|
+
south (float): Southern latitude.
|
51
|
+
east (float): Eastern longitude.
|
52
|
+
west (float): Western longitude.
|
53
|
+
|
54
|
+
Returns:
|
55
|
+
str: Hashed file name.
|
56
|
+
"""
|
57
|
+
coordinates = f"{north}_{south}_{east}_{west}"
|
58
|
+
hash_object = hashlib.md5(coordinates.encode())
|
59
|
+
hashed_file_name = "download_" + hash_object.hexdigest() + ".meta4"
|
60
|
+
return hashed_file_name
|
61
|
+
|
62
|
+
def get_meta_file_from_coords(self) -> list[str]:
|
63
|
+
"""Download .meta4 (xml format) file
|
64
|
+
|
65
|
+
Returns:
|
66
|
+
list: List of download URLs.
|
67
|
+
"""
|
68
|
+
(north, south, east, west) = self.get_bbox()
|
69
|
+
file_path = os.path.join(self.meta4_path, self.get_meta_file_name(north, south, east, west))
|
70
|
+
if not os.path.exists(file_path):
|
71
|
+
try:
|
72
|
+
# Make the GET request
|
73
|
+
response = requests.post(
|
74
|
+
"https://geoservices.bayern.de/services/poly2metalink/metalink/dgm1",
|
75
|
+
(f"SRID=4326;POLYGON(({west} {south},{east} {south},"
|
76
|
+
f"{east} {north},{west} {north},{west} {south}))"),
|
77
|
+
stream=True,
|
78
|
+
timeout=60
|
79
|
+
)
|
80
|
+
|
81
|
+
# Check if the request was successful (HTTP status code 200)
|
82
|
+
if response.status_code == 200:
|
83
|
+
# Write the content of the response to the file
|
84
|
+
with open(file_path, "wb") as meta_file:
|
85
|
+
for chunk in response.iter_content(chunk_size=8192): # Download in chunks
|
86
|
+
meta_file.write(chunk)
|
87
|
+
self.logger.info("File downloaded successfully: %s", file_path)
|
88
|
+
else:
|
89
|
+
self.logger.error("Download error. HTTP Status Code: %s", response.status_code)
|
90
|
+
except requests.exceptions.RequestException as e:
|
91
|
+
self.logger.error("Failed to get data. Error: %s", e)
|
92
|
+
else:
|
93
|
+
self.logger.debug("File already exists: %s", file_path)
|
94
|
+
return self.extract_urls_from_xml(file_path)
|
95
|
+
|
96
|
+
def extract_urls_from_xml(self, file_path: str) -> list[str]:
|
97
|
+
"""Extract URLs from the XML file.
|
98
|
+
|
99
|
+
Arguments:
|
100
|
+
file_path (str): Path to the XML file.
|
101
|
+
|
102
|
+
Returns:
|
103
|
+
list: List of URLs.
|
104
|
+
"""
|
105
|
+
urls: list[str] = []
|
106
|
+
root = ET.parse(file_path).getroot()
|
107
|
+
namespace = {'ml': 'urn:ietf:params:xml:ns:metalink'}
|
108
|
+
|
109
|
+
for file in root.findall('.//ml:file', namespace):
|
110
|
+
url = file.find('ml:url', namespace)
|
111
|
+
if url is not None:
|
112
|
+
urls.append(str(url.text))
|
113
|
+
|
114
|
+
self.logger.debug("Received %s urls", len(urls))
|
115
|
+
return urls
|
maps4fs/generator/dtm/dtm.py
CHANGED
@@ -7,10 +7,12 @@ from __future__ import annotations
|
|
7
7
|
from abc import ABC, abstractmethod
|
8
8
|
import os
|
9
9
|
from typing import TYPE_CHECKING, Type
|
10
|
+
from zipfile import ZipFile
|
10
11
|
|
11
12
|
import numpy as np
|
12
13
|
import osmnx as ox # type: ignore
|
13
14
|
import rasterio # type: ignore
|
15
|
+
import requests
|
14
16
|
from rasterio.warp import calculate_default_transform, reproject
|
15
17
|
from rasterio.enums import Resampling
|
16
18
|
from rasterio.merge import merge
|
@@ -300,7 +302,7 @@ class DTMProvider(ABC):
|
|
300
302
|
self.data_info = {}
|
301
303
|
self.add_numpy_params(data, "original")
|
302
304
|
|
303
|
-
data = self.
|
305
|
+
data = self.ground_height_data(data)
|
304
306
|
self.add_numpy_params(data, "grounded")
|
305
307
|
|
306
308
|
original_deviation = int(self.data_info["original_deviation"])
|
@@ -339,7 +341,7 @@ class DTMProvider(ABC):
|
|
339
341
|
"Failed to normalize DEM data. Error: %s. Using original data.", e
|
340
342
|
)
|
341
343
|
|
342
|
-
return data
|
344
|
+
return data.astype(np.uint16)
|
343
345
|
|
344
346
|
def info_sequence(self) -> dict[str, int | str | float] | None:
|
345
347
|
"""Returns the information sequence for the component. Must be implemented in the child
|
@@ -364,20 +366,75 @@ class DTMProvider(ABC):
|
|
364
366
|
bbox = north, south, east, west
|
365
367
|
return bbox
|
366
368
|
|
369
|
+
def download_tif_files(self, urls: list[str], output_path: str) -> list[str]:
|
370
|
+
"""Download GeoTIFF files from the given URLs.
|
371
|
+
|
372
|
+
Arguments:
|
373
|
+
urls (list): List of URLs to download GeoTIFF files from.
|
374
|
+
output_path (str): Path to save the downloaded GeoTIFF files.
|
375
|
+
|
376
|
+
Returns:
|
377
|
+
list: List of paths to the downloaded GeoTIFF files.
|
378
|
+
"""
|
379
|
+
tif_files: list[str] = []
|
380
|
+
for url in urls:
|
381
|
+
file_name = os.path.basename(url)
|
382
|
+
self.logger.debug("Retrieving TIFF: %s", file_name)
|
383
|
+
file_path = os.path.join(output_path, file_name)
|
384
|
+
if not os.path.exists(file_path):
|
385
|
+
try:
|
386
|
+
# Send a GET request to the file URL
|
387
|
+
response = requests.get(url, stream=True, timeout=60)
|
388
|
+
response.raise_for_status() # Raise an error for HTTP status codes 4xx/5xx
|
389
|
+
|
390
|
+
# Write the content of the response to the file
|
391
|
+
with open(file_path, "wb") as file:
|
392
|
+
for chunk in response.iter_content(chunk_size=8192): # Download in chunks
|
393
|
+
file.write(chunk)
|
394
|
+
self.logger.info("File downloaded successfully: %s", file_path)
|
395
|
+
except requests.exceptions.RequestException as e:
|
396
|
+
self.logger.error("Failed to download file: %s", e)
|
397
|
+
else:
|
398
|
+
self.logger.debug("File already exists: %s", file_name)
|
399
|
+
if file_name.endswith('.zip'):
|
400
|
+
file_path = self.unzip_img_from_tif(file_name, output_path)
|
401
|
+
tif_files.append(file_path)
|
402
|
+
return tif_files
|
403
|
+
|
404
|
+
def unzip_img_from_tif(self, file_name: str, output_path: str) -> str:
|
405
|
+
"""Unpacks the .img file from the zip file.
|
406
|
+
|
407
|
+
Arguments:
|
408
|
+
file_name (str): Name of the file to unzip.
|
409
|
+
output_path (str): Path to the output directory.
|
410
|
+
|
411
|
+
Returns:
|
412
|
+
str: Path to the unzipped file.
|
413
|
+
"""
|
414
|
+
file_path = os.path.join(output_path, file_name)
|
415
|
+
img_file_name = file_name.replace('.zip', '.img')
|
416
|
+
img_file_path = os.path.join(output_path, img_file_name)
|
417
|
+
if not os.path.exists(img_file_path):
|
418
|
+
with ZipFile(file_path, "r") as f_in:
|
419
|
+
f_in.extract(img_file_name, output_path)
|
420
|
+
self.logger.debug("Unzipped file %s to %s", file_name, img_file_name)
|
421
|
+
else:
|
422
|
+
self.logger.debug("File already exists: %s", img_file_name)
|
423
|
+
return img_file_path
|
424
|
+
|
367
425
|
def reproject_geotiff(self, input_tiff: str) -> str:
|
368
426
|
"""Reproject a GeoTIFF file to a new coordinate reference system (CRS).
|
369
427
|
|
370
428
|
Arguments:
|
371
429
|
input_tiff (str): Path to the input GeoTIFF file.
|
372
|
-
target_crs (str): Target CRS (e.g., EPSG:4326 for CRS:84).
|
373
430
|
|
374
431
|
Returns:
|
375
432
|
str: Path to the reprojected GeoTIFF file.
|
376
433
|
"""
|
377
|
-
output_tiff = os.path.join(self._tile_directory, "
|
434
|
+
output_tiff = os.path.join(self._tile_directory, "reprojected.tif")
|
378
435
|
|
379
436
|
# Open the source GeoTIFF
|
380
|
-
self.logger.debug("Reprojecting GeoTIFF to
|
437
|
+
self.logger.debug("Reprojecting GeoTIFF to EPSG:4326 CRS...")
|
381
438
|
with rasterio.open(input_tiff) as src:
|
382
439
|
# Get the transform, width, and height of the target CRS
|
383
440
|
transform, width, height = calculate_default_transform(
|
@@ -411,7 +468,6 @@ class DTMProvider(ABC):
|
|
411
468
|
|
412
469
|
Arguments:
|
413
470
|
input_files (list): List of input GeoTIFF files to merge.
|
414
|
-
output_file (str): Path to save the merged GeoTIFF file.
|
415
471
|
"""
|
416
472
|
output_file = os.path.join(self._tile_directory, "merged.tif")
|
417
473
|
# Open all input GeoTIFF files as datasets
|
@@ -516,11 +572,15 @@ class DTMProvider(ABC):
|
|
516
572
|
)
|
517
573
|
return normalized_data
|
518
574
|
|
519
|
-
|
520
|
-
|
575
|
+
@staticmethod
|
576
|
+
def ground_height_data(data: np.ndarray, add_one: bool = True) -> np.ndarray:
|
577
|
+
"""Shift the data to ground level (0 meter).
|
578
|
+
Optionally add one meter to the data to leave some room
|
579
|
+
for the water level and pit modifications.
|
521
580
|
|
522
581
|
Arguments:
|
523
|
-
data (np.ndarray): DEM data
|
582
|
+
data (np.ndarray): DEM data after cropping.
|
583
|
+
add_one (bool): Add one meter to the data
|
524
584
|
|
525
585
|
Returns:
|
526
586
|
np.ndarray: Unsigned DEM data.
|
@@ -528,7 +588,7 @@ class DTMProvider(ABC):
|
|
528
588
|
data = data - data.min()
|
529
589
|
if add_one:
|
530
590
|
data = data + 1
|
531
|
-
return data
|
591
|
+
return data
|
532
592
|
|
533
593
|
def add_numpy_params(
|
534
594
|
self,
|
maps4fs/generator/dtm/nrw.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
"""This module contains provider of
|
1
|
+
"""This module contains provider of NRW data."""
|
2
2
|
|
3
3
|
import os
|
4
4
|
|
@@ -11,7 +11,7 @@ from maps4fs.generator.dtm.dtm import DTMProvider, DTMProviderSettings
|
|
11
11
|
|
12
12
|
|
13
13
|
class NRWProviderSettings(DTMProviderSettings):
|
14
|
-
"""Settings for the
|
14
|
+
"""Settings for the NRW provider."""
|
15
15
|
|
16
16
|
|
17
17
|
# pylint: disable=too-many-locals
|
maps4fs/generator/dtm/usgs.py
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
import os
|
4
4
|
from datetime import datetime
|
5
|
-
from zipfile import ZipFile
|
6
5
|
|
7
6
|
import numpy as np
|
8
7
|
import requests
|
@@ -46,7 +45,7 @@ class USGSProvider(DTMProvider):
|
|
46
45
|
|
47
46
|
def download_tiles(self):
|
48
47
|
download_urls = self.get_download_urls()
|
49
|
-
all_tif_files = self.download_tif_files(download_urls)
|
48
|
+
all_tif_files = self.download_tif_files(download_urls, self.shared_tiff_path)
|
50
49
|
return all_tif_files
|
51
50
|
|
52
51
|
def __init__(self, *args, **kwargs):
|
@@ -88,48 +87,3 @@ class USGSProvider(DTMProvider):
|
|
88
87
|
self.logger.error("Failed to get data. Error: %s", e)
|
89
88
|
self.logger.debug("Received %s urls", len(urls))
|
90
89
|
return urls
|
91
|
-
|
92
|
-
def download_tif_files(self, urls: list[str]) -> list[str]:
|
93
|
-
"""Download GeoTIFF files from the given URLs.
|
94
|
-
|
95
|
-
Arguments:
|
96
|
-
urls (list): List of URLs to download GeoTIFF files from.
|
97
|
-
|
98
|
-
Returns:
|
99
|
-
list: List of paths to the downloaded GeoTIFF files.
|
100
|
-
"""
|
101
|
-
tif_files = []
|
102
|
-
for url in urls:
|
103
|
-
file_name = os.path.basename(url)
|
104
|
-
self.logger.debug("Retrieving TIFF: %s", file_name)
|
105
|
-
file_path = os.path.join(self.shared_tiff_path, file_name)
|
106
|
-
if not os.path.exists(file_path):
|
107
|
-
try:
|
108
|
-
# Send a GET request to the file URL
|
109
|
-
response = requests.get(url, stream=True) # pylint: disable=W3101
|
110
|
-
response.raise_for_status() # Raise an error for HTTP status codes 4xx/5xx
|
111
|
-
|
112
|
-
# Write the content of the response to the file
|
113
|
-
with open(file_path, "wb") as file:
|
114
|
-
for chunk in response.iter_content(chunk_size=8192): # Download in chunks
|
115
|
-
file.write(chunk)
|
116
|
-
self.logger.info("File downloaded successfully: %s", file_path)
|
117
|
-
if file_name.endswith('.zip'):
|
118
|
-
with ZipFile(file_path, "r") as f_in:
|
119
|
-
f_in.extract(file_name.replace('.zip', '.img'), self.shared_tiff_path)
|
120
|
-
tif_files.append(file_path.replace('.zip', '.img'))
|
121
|
-
else:
|
122
|
-
tif_files.append(file_path)
|
123
|
-
except requests.exceptions.RequestException as e:
|
124
|
-
self.logger.error("Failed to download file: %s", e)
|
125
|
-
else:
|
126
|
-
self.logger.debug("File already exists: %s", file_name)
|
127
|
-
if file_name.endswith('.zip'):
|
128
|
-
if not os.path.exists(file_path.replace('.zip', '.img')):
|
129
|
-
with ZipFile(file_path, "r") as f_in:
|
130
|
-
f_in.extract(file_name.replace('.zip', '.img'), self.shared_tiff_path)
|
131
|
-
tif_files.append(file_path.replace('.zip', '.img'))
|
132
|
-
else:
|
133
|
-
tif_files.append(file_path)
|
134
|
-
|
135
|
-
return tif_files
|
maps4fs/generator/game.py
CHANGED
@@ -58,18 +58,19 @@ class Game:
|
|
58
58
|
return os.path.join(map_directory, "maps", "map", "map.xml")
|
59
59
|
|
60
60
|
@classmethod
|
61
|
-
def from_code(cls, code: str) -> Game:
|
61
|
+
def from_code(cls, code: str, map_template_path: str | None = None) -> Game:
|
62
62
|
"""Returns the game instance based on the game code.
|
63
63
|
|
64
64
|
Arguments:
|
65
65
|
code (str): The code of the game.
|
66
|
+
map_template_path (str, optional): Path to the map template file. Defaults to None.
|
66
67
|
|
67
68
|
Returns:
|
68
69
|
Game: The game instance.
|
69
70
|
"""
|
70
71
|
for game in cls.__subclasses__():
|
71
72
|
if game.code and game.code.lower() == code.lower():
|
72
|
-
return game()
|
73
|
+
return game(map_template_path)
|
73
74
|
raise ValueError(f"Game with code {code} not found.")
|
74
75
|
|
75
76
|
@property
|
@@ -1,11 +1,11 @@
|
|
1
|
-
maps4fs/__init__.py,sha256=
|
1
|
+
maps4fs/__init__.py,sha256=I-WDbZBb1l6us3QxDajPGzjVJe9PK0QrE5DqZwSsd_w,713
|
2
2
|
maps4fs/logger.py,sha256=B-NEYpMjPAAqlV4VpfTi6nbBFnEABVtQOaYe6nMpidg,1489
|
3
3
|
maps4fs/generator/__init__.py,sha256=zZMLEkGzb4z0xql650gOtGSvcgX58DnJ2yN3vC2daRk,43
|
4
4
|
maps4fs/generator/background.py,sha256=tV4UXvtkNN-OSvv6ujp4jFWRU1xGBgEvSakVGZ1H4nc,24877
|
5
5
|
maps4fs/generator/component.py,sha256=pbpGaWy5C0UzxpcJ72HPY2gMol98snDr-bvNZSX4yY0,20823
|
6
6
|
maps4fs/generator/config.py,sha256=0QmK052B8bxyHVhg3jzCORLfOBMMmqVfhhbqXKf6OMk,4383
|
7
7
|
maps4fs/generator/dem.py,sha256=20gx0dzX0LyO6ipvDitst-BwGfcKogFqgQf9Q2qMH5U,10933
|
8
|
-
maps4fs/generator/game.py,sha256=
|
8
|
+
maps4fs/generator/game.py,sha256=GmCl_KQ9D-UwKao4HFEb0PRAm829ThtSZfkgzK3Oh2g,8143
|
9
9
|
maps4fs/generator/grle.py,sha256=hcbVBJ4j_Zr2QvEVo2cYNh2jARVXp_X3onifBtp9Zxs,20922
|
10
10
|
maps4fs/generator/i3d.py,sha256=pUyHKWKcw43xVCf3Y8iabtbQba05LYxMHi8vziGksIA,24843
|
11
11
|
maps4fs/generator/map.py,sha256=a50KQEr1XZKjS_WKXywGwh4OC3gyjY6M8FTc0eNcxpg,10183
|
@@ -14,16 +14,17 @@ maps4fs/generator/satellite.py,sha256=_7RcuNmR1mjxEJWMDsjnzKUIqWxnGUn50XtjB7HmSP
|
|
14
14
|
maps4fs/generator/settings.py,sha256=9vbXISQrE-aDY7ATpvZ7LVJMqjfwa3-gNl-huI8XLO0,5666
|
15
15
|
maps4fs/generator/texture.py,sha256=L_j5GTTJXbp7OCT4-TWGFcY_zyAI_fNzDFLvXYiyKPI,33921
|
16
16
|
maps4fs/generator/dtm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
|
-
maps4fs/generator/dtm/
|
18
|
-
maps4fs/generator/dtm/
|
17
|
+
maps4fs/generator/dtm/bavaria.py,sha256=r6-3DcKY4JeFQ-8jbf0xxtB5SPbbZc7KSGYxllqOCo4,4412
|
18
|
+
maps4fs/generator/dtm/dtm.py,sha256=DXRxpRuzy5l00yGVMkxamJE2zRygwpi6xcEe29y7LsA,21714
|
19
|
+
maps4fs/generator/dtm/nrw.py,sha256=8h33743_FvfScnABSFWgV7zPE5L1i6vL2uwpIMZey6g,4610
|
19
20
|
maps4fs/generator/dtm/srtm.py,sha256=RsvVa7ErajPwXoetG7mO_rldji9GR97HFaazH-PkdHw,4399
|
20
|
-
maps4fs/generator/dtm/usgs.py,sha256=
|
21
|
+
maps4fs/generator/dtm/usgs.py,sha256=dyy2NT0USlRkYL2qfXQzFT_q3VfkVZUSmKBzPkDNvV4,3202
|
21
22
|
maps4fs/toolbox/__init__.py,sha256=zZMLEkGzb4z0xql650gOtGSvcgX58DnJ2yN3vC2daRk,43
|
22
23
|
maps4fs/toolbox/background.py,sha256=9BXWNqs_n3HgqDiPztWylgYk_QM4YgBpe6_ZNQAWtSc,2154
|
23
24
|
maps4fs/toolbox/custom_osm.py,sha256=X6ZlPqiOhNjkmdD_qVroIfdOl9Rb90cDwVSLDVYgx80,1892
|
24
25
|
maps4fs/toolbox/dem.py,sha256=z9IPFNmYbjiigb3t02ZenI3Mo8odd19c5MZbjDEovTo,3525
|
25
|
-
maps4fs-1.7.
|
26
|
-
maps4fs-1.7.
|
27
|
-
maps4fs-1.7.
|
28
|
-
maps4fs-1.7.
|
29
|
-
maps4fs-1.7.
|
26
|
+
maps4fs-1.7.7.dist-info/LICENSE.md,sha256=pTKD_oUexcn-yccFCTrMeLkZy0ifLRa-VNcDLqLZaIw,10749
|
27
|
+
maps4fs-1.7.7.dist-info/METADATA,sha256=rf4b6SCuVflM7i2t3N2FrGKvgJJetsnKIhMroi5kq0k,40436
|
28
|
+
maps4fs-1.7.7.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
29
|
+
maps4fs-1.7.7.dist-info/top_level.txt,sha256=Ue9DSRlejRQRCaJueB0uLcKrWwsEq9zezfv5dI5mV1M,8
|
30
|
+
maps4fs-1.7.7.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|