maps4fs 1.7.1__py3-none-any.whl → 1.7.6__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.

Potentially problematic release.


This version of maps4fs might be problematic. Click here for more details.

@@ -2,15 +2,9 @@
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
- import rasterio
9
7
  import requests
10
- from rasterio.enums import Resampling
11
- from rasterio.merge import merge
12
- from rasterio.warp import calculate_default_transform, reproject
13
- from rasterio.windows import from_bounds
14
8
 
15
9
  from maps4fs.generator.dtm.dtm import DTMProvider, DTMProviderSettings
16
10
 
@@ -18,7 +12,6 @@ from maps4fs.generator.dtm.dtm import DTMProvider, DTMProviderSettings
18
12
  class USGSProviderSettings(DTMProviderSettings):
19
13
  """Settings for the USGS provider."""
20
14
 
21
- max_local_elevation: int = 255
22
15
  dataset: tuple | str = (
23
16
  'Digital Elevation Model (DEM) 1 meter',
24
17
  'Alaska IFSAR 5 meter DEM',
@@ -43,17 +36,18 @@ class USGSProvider(DTMProvider):
43
36
  _author = "[ZenJakey](https://github.com/ZenJakey)"
44
37
  _contributors = "[kbrandwijk](https://github.com/kbrandwijk)"
45
38
  _is_community = True
46
- _instructions = (
47
- "ℹ️ Set the max local elevation to approx the local max elevation for your area in"
48
- " meters. This will allow you to use heightScale 255 in GE with minimal tweaking."
49
- " Setting this value too low can cause a flat map!"
50
- )
39
+ _instructions = None
51
40
 
52
41
  _url = (
53
42
  "https://tnmaccess.nationalmap.gov/api/v1/products?prodFormats=GeoTIFF,IMG"
54
43
 
55
44
  )
56
45
 
46
+ def download_tiles(self):
47
+ download_urls = self.get_download_urls()
48
+ all_tif_files = self.download_tif_files(download_urls, self.shared_tiff_path)
49
+ return all_tif_files
50
+
57
51
  def __init__(self, *args, **kwargs):
58
52
  super().__init__(*args, **kwargs)
59
53
  timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
@@ -93,259 +87,3 @@ class USGSProvider(DTMProvider):
93
87
  self.logger.error("Failed to get data. Error: %s", e)
94
88
  self.logger.debug("Received %s urls", len(urls))
95
89
  return urls
96
-
97
- def download_tif_files(self, urls: list[str]) -> list[str]:
98
- """Download GeoTIFF files from the given URLs.
99
-
100
- Arguments:
101
- urls (list): List of URLs to download GeoTIFF files from.
102
-
103
- Returns:
104
- list: List of paths to the downloaded GeoTIFF files.
105
- """
106
- tif_files = []
107
- for url in urls:
108
- file_name = os.path.basename(url)
109
- self.logger.debug("Retrieving TIFF: %s", file_name)
110
- file_path = os.path.join(self.shared_tiff_path, file_name)
111
- if not os.path.exists(file_path):
112
- try:
113
- # Send a GET request to the file URL
114
- response = requests.get(url, stream=True) # pylint: disable=W3101
115
- response.raise_for_status() # Raise an error for HTTP status codes 4xx/5xx
116
-
117
- # Write the content of the response to the file
118
- with open(file_path, "wb") as file:
119
- for chunk in response.iter_content(chunk_size=8192): # Download in chunks
120
- file.write(chunk)
121
- self.logger.info("File downloaded successfully: %s", file_path)
122
- if file_name.endswith('.zip'):
123
- with ZipFile(file_path, "r") as f_in:
124
- f_in.extract(file_name.replace('.zip', '.img'), self.shared_tiff_path)
125
- tif_files.append(file_path.replace('.zip', '.img'))
126
- else:
127
- tif_files.append(file_path)
128
- except requests.exceptions.RequestException as e:
129
- self.logger.error("Failed to download file: %s", e)
130
- else:
131
- self.logger.debug("File already exists: %s", file_name)
132
- if file_name.endswith('.zip'):
133
- if not os.path.exists(file_path.replace('.zip', '.img')):
134
- with ZipFile(file_path, "r") as f_in:
135
- f_in.extract(file_name.replace('.zip', '.img'), self.shared_tiff_path)
136
- tif_files.append(file_path.replace('.zip', '.img'))
137
- else:
138
- tif_files.append(file_path)
139
-
140
- return tif_files
141
-
142
- def merge_geotiff(self, input_files: list[str], output_file: str) -> None:
143
- """Merge multiple GeoTIFF files into a single GeoTIFF file.
144
-
145
- Arguments:
146
- input_files (list): List of input GeoTIFF files to merge.
147
- output_file (str): Path to save the merged GeoTIFF file.
148
- """
149
- # Open all input GeoTIFF files as datasets
150
- self.logger.debug("Merging tiff files...")
151
- datasets = [rasterio.open(file) for file in input_files]
152
-
153
- # Merge datasets
154
- mosaic, out_transform = merge(datasets, nodata=0)
155
-
156
- # Get metadata from the first file and update it for the output
157
- out_meta = datasets[0].meta.copy()
158
- out_meta.update(
159
- {
160
- "driver": "GTiff",
161
- "height": mosaic.shape[1],
162
- "width": mosaic.shape[2],
163
- "transform": out_transform,
164
- "count": mosaic.shape[0], # Number of bands
165
- }
166
- )
167
-
168
- # Write merged GeoTIFF to the output file
169
- with rasterio.open(output_file, "w", **out_meta) as dest:
170
- dest.write(mosaic)
171
-
172
- self.logger.debug("GeoTIFF images merged successfully into %s", output_file)
173
-
174
- def reproject_geotiff(self, input_tiff: str, output_tiff: str, target_crs: str) -> None:
175
- """Reproject a GeoTIFF file to a new coordinate reference system (CRS).
176
-
177
- Arguments:
178
- input_tiff (str): Path to the input GeoTIFF file.
179
- output_tiff (str): Path to save the reprojected GeoTIFF file.
180
- target_crs (str): Target CRS (e.g., EPSG:4326 for CRS:84).
181
- """
182
- # Open the source GeoTIFF
183
- self.logger.debug("Reprojecting GeoTIFF to %s CRS...", target_crs)
184
- with rasterio.open(input_tiff) as src:
185
- # Get the transform, width, and height of the target CRS
186
- transform, width, height = calculate_default_transform(
187
- src.crs, target_crs, src.width, src.height, *src.bounds
188
- )
189
-
190
- # Update the metadata for the target GeoTIFF
191
- kwargs = src.meta.copy()
192
- kwargs.update(
193
- {"crs": target_crs, "transform": transform, "width": width, "height": height}
194
- )
195
-
196
- # Open the destination GeoTIFF file and reproject
197
- with rasterio.open(output_tiff, "w", **kwargs) as dst:
198
- for i in range(1, src.count + 1): # Iterate over all raster bands
199
- reproject(
200
- source=rasterio.band(src, i),
201
- destination=rasterio.band(dst, i),
202
- src_transform=src.transform,
203
- src_crs=src.crs,
204
- dst_transform=transform,
205
- dst_crs=target_crs,
206
- resampling=Resampling.nearest, # Choose resampling method
207
- )
208
- self.logger.debug("Reprojected GeoTIFF saved to %s", output_tiff)
209
-
210
- def extract_roi(self, input_tiff: str) -> np.ndarray: # pylint: disable=W0237
211
- """
212
- Crop a GeoTIFF based on given geographic bounding box and save to a new file.
213
-
214
- Arguments:
215
- input_tiff (str): Path to the input GeoTIFF file.
216
-
217
- Returns:
218
- np.ndarray: Numpy array of the cropped GeoTIFF.
219
- """
220
- self.logger.debug("Extracting ROI...")
221
- # Open the input GeoTIFF
222
- with rasterio.open(input_tiff) as src:
223
-
224
- # Create a rasterio window from the bounding box
225
- (north, south, east, west) = self.get_bbox()
226
- window = from_bounds(west, south, east, north, transform=src.transform)
227
-
228
- data = src.read(1, window=window)
229
- self.logger.debug("Extracted ROI")
230
- return data
231
-
232
- # pylint: disable=R0914, R0917, R0913
233
- def convert_geotiff_to_geotiff(
234
- self,
235
- input_tiff: str,
236
- output_tiff: str,
237
- min_height: float,
238
- max_height: float,
239
- target_crs: str,
240
- ) -> None:
241
- """
242
- Convert a GeoTIFF to a scaled GeoTIFF with UInt16 values using a specific coordinate
243
- system and output size.
244
-
245
- Arguments:
246
- input_tiff (str): Path to the input GeoTIFF file.
247
- output_tiff (str): Path to save the output GeoTIFF file.
248
- min_height (float): Minimum terrain height (input range).
249
- max_height (float): Maximum terrain height (input range).
250
- target_crs (str): Target CRS (e.g., EPSG:4326 for CRS:84).
251
- """
252
- # Open the input GeoTIFF file
253
- self.logger.debug("Converting to uint16")
254
- with rasterio.open(input_tiff) as src:
255
- # Ensure the input CRS matches the target CRS (reprojection may be required)
256
- if str(src.crs) != str(target_crs):
257
- raise ValueError(
258
- f"The GeoTIFF CRS is {src.crs}, but the target CRS is {target_crs}. "
259
- "Reprojection may be required."
260
- )
261
-
262
- # Read the data from the first band
263
- data = src.read(1) # Assuming the input GeoTIFF has only a single band
264
-
265
- # Identify the input file's NoData value
266
- input_nodata = src.nodata
267
- if input_nodata is None:
268
- input_nodata = -999999.0 # Default fallback if no NoData value is defined
269
- nodata_value = 0
270
- # Replace NoData values (e.g., -999999.0) with the new NoData value
271
- # (e.g., 65535 for UInt16)
272
- data[data == input_nodata] = nodata_value
273
-
274
- # Scale the data to the 0–65535 range (UInt16), avoiding NoData areas
275
- scaled_data = np.clip(
276
- (data - min_height) * (65535 / (max_height - min_height)), 0, 65535
277
- ).astype(np.uint16)
278
- scaled_data[data == nodata_value] = (
279
- nodata_value # Preserve NoData value in the scaled array
280
- )
281
-
282
- # Compute the proper transform to ensure consistency
283
- # Get the original transform, width, and height
284
- transform = src.transform
285
- width = src.width
286
- height = src.height
287
- left, bottom, right, top = src.bounds
288
-
289
- # Adjust the transform matrix to make sure bounds and transform align correctly
290
- transform = rasterio.transform.from_bounds(left, bottom, right, top, width, height)
291
-
292
- # Prepare metadata for the output GeoTIFF
293
- metadata = src.meta.copy()
294
- metadata.update(
295
- {
296
- "dtype": rasterio.uint16, # Update dtype for uint16
297
- "crs": target_crs, # Update CRS if needed
298
- "nodata": nodata_value, # Set the new NoData value
299
- "transform": transform, # Use the updated, consistent transform
300
- }
301
- )
302
-
303
- # Write the scaled data to the output GeoTIFF
304
- with rasterio.open(output_tiff, "w", **metadata) as dst:
305
- dst.write(scaled_data, 1) # Write the first band
306
-
307
- self.logger.debug(
308
- "GeoTIFF successfully converted and saved to %s, with nodata value: %s.",
309
- output_tiff,
310
- nodata_value,
311
- )
312
-
313
- def generate_data(self) -> np.ndarray:
314
- """Generate data from the USGS 1m provider.
315
-
316
- Returns:
317
- np.ndarray: Numpy array of the data.
318
- """
319
- download_urls = self.get_download_urls()
320
- all_tif_files = self.download_tif_files(download_urls)
321
- self.merge_geotiff(all_tif_files, os.path.join(self.output_path, "merged.tif"))
322
- self.reproject_geotiff(
323
- os.path.join(self.output_path, "merged.tif"),
324
- os.path.join(self.output_path, "reprojected.tif"),
325
- "EPSG:4326",
326
- )
327
- self.convert_geotiff_to_geotiff(
328
- os.path.join(self.output_path, "reprojected.tif"),
329
- os.path.join(self.output_path, "translated.tif"),
330
- min_height=0,
331
- max_height=self.user_settings.max_local_elevation, # type: ignore
332
- target_crs="EPSG:4326",
333
- )
334
- return self.extract_roi(os.path.join(self.output_path, "translated.tif"))
335
-
336
- def get_numpy(self) -> np.ndarray:
337
- """Get numpy array of the tile.
338
-
339
- Returns:
340
- np.ndarray: Numpy array of the tile.
341
- """
342
- if not self.user_settings:
343
- raise ValueError("user_settings is 'none'")
344
- if self.user_settings.max_local_elevation <= 0: # type: ignore
345
- raise ValueError(
346
- "Entered 'max_local_elevation' value is unable to be used. "
347
- "Use a value greater than 0."
348
- )
349
- if not self._data:
350
- self._data = self.generate_data()
351
- return self._data
@@ -421,7 +421,7 @@ class Texture(Component):
421
421
  ),
422
422
  )
423
423
 
424
- # pylint: disable=no-member, R0912
424
+ # pylint: disable=no-member, R0912, R0915
425
425
  def draw(self) -> None:
426
426
  """Iterates over layers and fills them with polygons from OSM data."""
427
427
  layers = self.layers_by_priority()
@@ -461,12 +461,19 @@ class Texture(Component):
461
461
  for polygon in self.objects_generator( # type: ignore
462
462
  layer.tags, layer.width, layer.info_layer
463
463
  ):
464
+ if not len(polygon) > 2:
465
+ self.logger.debug("Skipping polygon with less than 3 points.")
466
+ continue
464
467
  if layer.info_layer:
465
468
  info_layer_data[layer.info_layer].append(
466
469
  self.np_to_polygon_points(polygon) # type: ignore
467
470
  )
468
471
  if not layer.invisible:
469
- cv2.fillPoly(layer_image, [polygon], color=255) # type: ignore
472
+ try:
473
+ cv2.fillPoly(layer_image, [polygon], color=255) # type: ignore
474
+ except Exception as e: # pylint: disable=W0718
475
+ self.logger.warning("Error drawing polygon: %s.", repr(e))
476
+ continue
470
477
 
471
478
  if layer.info_layer == "roads":
472
479
  for linestring in self.objects_generator(
@@ -0,0 +1,67 @@
1
+ """This module contains functions to work with custom OSM files."""
2
+
3
+ import json
4
+ from xml.etree import ElementTree as ET
5
+
6
+ import osmnx as ox
7
+ from osmnx._errors import InsufficientResponseError
8
+
9
+ from maps4fs.generator.game import FS25
10
+
11
+
12
+ def check_osm_file(file_path: str) -> bool:
13
+ """Tries to read the OSM file using OSMnx and returns True if the file is valid,
14
+ False otherwise.
15
+
16
+ Arguments:
17
+ file_path (str): Path to the OSM file.
18
+
19
+ Returns:
20
+ bool: True if the file is valid, False otherwise.
21
+ """
22
+ with open(FS25().texture_schema, encoding="utf-8") as f:
23
+ schema = json.load(f)
24
+
25
+ tags = []
26
+ for element in schema:
27
+ element_tags = element.get("tags")
28
+ if element_tags:
29
+ tags.append(element_tags)
30
+
31
+ for tag in tags:
32
+ try:
33
+ ox.features_from_xml(file_path, tags=tag)
34
+ except InsufficientResponseError:
35
+ continue
36
+ except Exception: # pylint: disable=W0718
37
+ return False
38
+ return True
39
+
40
+
41
+ def fix_osm_file(input_file_path: str, output_file_path: str) -> tuple[bool, int]:
42
+ """Fixes the OSM file by removing all the <relation> nodes and all the nodes with
43
+ action='delete'.
44
+
45
+ Arguments:
46
+ input_file_path (str): Path to the input OSM file.
47
+ output_file_path (str): Path to the output OSM file.
48
+
49
+ Returns:
50
+ tuple[bool, int]: A tuple containing the result of the check_osm_file function
51
+ and the number of fixed errors.
52
+ """
53
+ broken_entries = ["relation", ".//*[@action='delete']"]
54
+
55
+ tree = ET.parse(input_file_path)
56
+ root = tree.getroot()
57
+
58
+ fixed_errors = 0
59
+ for entry in broken_entries:
60
+ for element in root.findall(entry):
61
+ root.remove(element)
62
+ fixed_errors += 1
63
+
64
+ tree.write(output_file_path)
65
+ result = check_osm_file(output_file_path)
66
+
67
+ return result, fixed_errors
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: maps4fs
3
- Version: 1.7.1
3
+ Version: 1.7.6
4
4
  Summary: Generate map templates for Farming Simulator from real places.
5
5
  Author-email: iwatkot <iwatkot@gmail.com>
6
6
  License: MIT License
@@ -36,7 +36,6 @@ Requires-Dist: pydantic
36
36
  <a href="#How-To-Run">How-To-Run</a><br>
37
37
  <a href="docs/FAQ.md">FAQ</a> •
38
38
  <a href="docs/map_structure.md">Map Structure</a> •
39
- <a href="docs/tips_and_hints.md">Tips and Hints</a> •
40
39
  <a href="#Modder-Toolbox">Modder Toolbox</a><br>
41
40
  <a href="#Supported-objects">Supported objects</a> •
42
41
  <a href="#Generation-info">Generation info</a> •
@@ -141,7 +140,7 @@ Check out the [Docker FAQ](docs/FAQ_docker.md) if you have any questions.<br>
141
140
  ```bash
142
141
  pip install maps4fs
143
142
  ```
144
- And refer to the [Python package](#option-3-python-package) section to learn how to use it.<br>
143
+ And refer to the [Python package or run from the source](#option-3-python-package-or-source-code) section to learn how to use it.<br>
145
144
 
146
145
  ## Overview
147
146
  The core idea is coming from the awesome [maps4cim](https://github.com/klamann/maps4cim) project.<br>
@@ -201,7 +200,7 @@ docker run -d -p 8501:8501 --name maps4fs iwatkot/maps4fs
201
200
  4. Fill in the required fields and click on the `Generate` button.
202
201
  5. When the map is generated click on the `Download` button to get the map.
203
202
 
204
- ### Option 3: Python package
203
+ ### Option 3: Python package or source code
205
204
  🔴 Recommended for developers.
206
205
  🗺️ Supported map sizes: 2x2, 4x4, 8x8, 16x16 km and any custom size.
207
206
  ⚙️ Advanced settings: enabled.
@@ -212,11 +211,50 @@ You can use the Python package to generate maps. Follow these steps:
212
211
  ```bash
213
212
  pip install maps4fs
214
213
  ```
214
+
215
+ Or clone the repository and install the package from the source code:
216
+ ```bash
217
+ git clone https://github.com/iwatkot/maps4fs.git
218
+ cd maps4fs
219
+ dev/create_venv.ps1 # for Windows
220
+ sh dev/create_venv.sh # for Linux
221
+
222
+ # Activate the virtual environment.
223
+ ./venv/scripts/activate # for Windows
224
+ source venv/bin/activate # for Linux
225
+
226
+ # Edit the demo.py file to set the parameters.
227
+ python demo.py
228
+ ```
229
+
230
+
215
231
  2. Import the Game class and create an instance of it:
216
232
  ```python
217
233
  import maps4fs as mfs
218
234
 
219
- game = mfs.Game.from_code("FS25")
235
+ game_code = "fs25"
236
+ game = mfs.Game.from_code(game_code)
237
+
238
+ dtm_provider = mfs.SRTM30Provider
239
+ dtm_provider_settings = mfs.SRTM30ProviderSettings(easy_mode=True, power_factor=0)
240
+
241
+ lat, lon = 45.28, 20.23
242
+ coordinates = (lat, lon)
243
+ size = 2048
244
+ rotation = 25
245
+
246
+ map_directory = "map_directory"
247
+ os.makedirs(map_directory, exist_ok=True)
248
+
249
+ mp = mfs.Map(
250
+ game,
251
+ dtm_provider,
252
+ dtm_provider_settings,
253
+ coordinates,
254
+ size,
255
+ rotation,
256
+ map_directory,
257
+ )
220
258
  ```
221
259
  In this case, the library will use the default templates, which should be present in the `data` directory, which should be placed in the current working directory.<br>
222
260
  Structure example:<br>
@@ -229,28 +267,17 @@ Structure example:<br>
229
267
 
230
268
  So it's recommended to download the `data` directory from the repository and place it in the root of your project.<br>
231
269
 
232
- 3. Create an instance of the Map class:
233
- ```python
234
- import maps4fs as mfs
235
-
236
- map = mfs.Map(
237
- game,
238
- (52.5200, 13.4050), # Latitude and longitude of the map center.
239
- height=1024, # The height of the map in meters.
240
- width=1024, # The width of the map in meters.
241
- map_directory="path/to/your/map/directory", # The directory where the map will be saved.
242
- )
243
- ```
244
-
245
- 4. Generate the map:
270
+ 3. Launch the generation process.
246
271
  The `generate` method returns a generator, which yields the active component of the map. You can use it to track the progress of the generation process.
247
272
  ```python
248
- for active_component in map.generate():
249
- print(active_component)
273
+ for component_name in mp.generate():
274
+ print(f"Generating {component_name}...")
250
275
  ```
251
276
 
252
277
  The map will be saved in the `map_directory` directory.
253
278
 
279
+ ➡️ Check out the [demo.py](demo.py) file for a complete example.
280
+
254
281
  ## Modder Toolbox
255
282
  The tool now has a Modder Toolbox, which is a set of tools to help you with various tasks. You can open the toolbox by switching to the `🧰 Modder Toolbox` tab in the StreamLit app.<br>
256
283
 
@@ -265,6 +292,9 @@ Tools are divided into categories, which are listed below.
265
292
  - **Texture Schema Editor** - allows you to view all the supported textures and edit their parameters, such as priority, OSM tags and so on. After editing, you should click the Show updated schema button and copy the JSON schema to the clipboard. Then you can use it in the Expert settings to generate the map with the updated textures.
266
293
 
267
294
  #### For Textures and DEM
295
+
296
+ - **Fix custom OSM file** - this tool fixes the most common errors in the custom OSM file, but it can not guarantee that the file will be fixed completely if some non-common errors are present.
297
+
268
298
  - **GeoTIFF windowing** - allows you to upload your GeoTIFF file and select the region of interest to extract it from the image. It's useful when you have high-resolution DEM data and want to create a height map using it.
269
299
 
270
300
  #### For Background terrain
@@ -1,4 +1,4 @@
1
- maps4fs/__init__.py,sha256=LrWSsyWaU28Dzcs7sRycywO_LvM-j34UvtafyBhvdx4,490
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
@@ -12,16 +12,19 @@ maps4fs/generator/map.py,sha256=a50KQEr1XZKjS_WKXywGwh4OC3gyjY6M8FTc0eNcxpg,1018
12
12
  maps4fs/generator/qgis.py,sha256=Es8hLuqN_KH8lDfnJE6He2rWYbAKJ3RGPn-o87S6CPI,6116
13
13
  maps4fs/generator/satellite.py,sha256=_7RcuNmR1mjxEJWMDsjnzKUIqWxnGUn50XtjB7HmSPg,3661
14
14
  maps4fs/generator/settings.py,sha256=9vbXISQrE-aDY7ATpvZ7LVJMqjfwa3-gNl-huI8XLO0,5666
15
- maps4fs/generator/texture.py,sha256=tDC9lIx2qn8d09Gu6PW_Lbq7EK7s1N4l25p50v92xl8,33548
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/dtm.py,sha256=nCQKQygARLxaz4HkREQQd0Yb03oKOf1Iav5_VoZsFWI,9819
18
- maps4fs/generator/dtm/srtm.py,sha256=2-pX6bWrJX6gr8IM7ueX6mm_PW7_UQ58MtdzDHae2OQ,9030
19
- maps4fs/generator/dtm/usgs.py,sha256=hwVjoSNTNRU6hwnfwJ2d3rOdtOjadCmx2QESA2REn6s,14493
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
20
+ maps4fs/generator/dtm/srtm.py,sha256=RsvVa7ErajPwXoetG7mO_rldji9GR97HFaazH-PkdHw,4399
21
+ maps4fs/generator/dtm/usgs.py,sha256=dyy2NT0USlRkYL2qfXQzFT_q3VfkVZUSmKBzPkDNvV4,3202
20
22
  maps4fs/toolbox/__init__.py,sha256=zZMLEkGzb4z0xql650gOtGSvcgX58DnJ2yN3vC2daRk,43
21
23
  maps4fs/toolbox/background.py,sha256=9BXWNqs_n3HgqDiPztWylgYk_QM4YgBpe6_ZNQAWtSc,2154
24
+ maps4fs/toolbox/custom_osm.py,sha256=X6ZlPqiOhNjkmdD_qVroIfdOl9Rb90cDwVSLDVYgx80,1892
22
25
  maps4fs/toolbox/dem.py,sha256=z9IPFNmYbjiigb3t02ZenI3Mo8odd19c5MZbjDEovTo,3525
23
- maps4fs-1.7.1.dist-info/LICENSE.md,sha256=pTKD_oUexcn-yccFCTrMeLkZy0ifLRa-VNcDLqLZaIw,10749
24
- maps4fs-1.7.1.dist-info/METADATA,sha256=QMIGgmKUnYvtc-Ln_rxPm7WeF8Q9L82Eo_aY2g2Uc8c,39697
25
- maps4fs-1.7.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
26
- maps4fs-1.7.1.dist-info/top_level.txt,sha256=Ue9DSRlejRQRCaJueB0uLcKrWwsEq9zezfv5dI5mV1M,8
27
- maps4fs-1.7.1.dist-info/RECORD,,
26
+ maps4fs-1.7.6.dist-info/LICENSE.md,sha256=pTKD_oUexcn-yccFCTrMeLkZy0ifLRa-VNcDLqLZaIw,10749
27
+ maps4fs-1.7.6.dist-info/METADATA,sha256=JJrc4bG4NmytUf6tI4QdMF2_a2GJjKLzUnHOGLIuE28,40436
28
+ maps4fs-1.7.6.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
29
+ maps4fs-1.7.6.dist-info/top_level.txt,sha256=Ue9DSRlejRQRCaJueB0uLcKrWwsEq9zezfv5dI5mV1M,8
30
+ maps4fs-1.7.6.dist-info/RECORD,,