maps4fs 0.8.2__py3-none-any.whl → 0.8.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.
- maps4fs/generator/background.py +281 -0
- maps4fs/generator/component.py +100 -3
- maps4fs/generator/config.py +31 -0
- maps4fs/generator/dem.py +67 -24
- maps4fs/generator/game.py +2 -1
- maps4fs/generator/map.py +41 -27
- maps4fs/generator/path_steps.py +72 -0
- maps4fs/generator/texture.py +5 -25
- maps4fs/generator/tile.py +55 -0
- maps4fs-0.8.4.dist-info/METADATA +422 -0
- maps4fs-0.8.4.dist-info/RECORD +18 -0
- maps4fs-0.8.2.dist-info/METADATA +0 -219
- maps4fs-0.8.2.dist-info/RECORD +0 -15
- {maps4fs-0.8.2.dist-info → maps4fs-0.8.4.dist-info}/LICENSE.md +0 -0
- {maps4fs-0.8.2.dist-info → maps4fs-0.8.4.dist-info}/WHEEL +0 -0
- {maps4fs-0.8.2.dist-info → maps4fs-0.8.4.dist-info}/top_level.txt +0 -0
maps4fs/generator/map.py
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
"""This module contains Map class, which is used to generate map using all components."""
|
2
2
|
|
3
|
+
from __future__ import annotations
|
4
|
+
|
3
5
|
import os
|
4
6
|
import shutil
|
5
|
-
from typing import Any
|
6
|
-
|
7
|
-
from tqdm import tqdm
|
7
|
+
from typing import Any, Generator
|
8
8
|
|
9
9
|
from maps4fs.generator.component import Component
|
10
10
|
from maps4fs.generator.game import Game
|
@@ -58,31 +58,45 @@ class Map:
|
|
58
58
|
except Exception as e:
|
59
59
|
raise RuntimeError(f"Can not unpack map template due to error: {e}") from e
|
60
60
|
|
61
|
-
def generate(self) -> None:
|
62
|
-
"""Launch map generation using all components.
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
61
|
+
def generate(self) -> Generator[str, None, None]:
|
62
|
+
"""Launch map generation using all components. Yield component names during the process.
|
63
|
+
|
64
|
+
Yields:
|
65
|
+
Generator[str, None, None]: Component names.
|
66
|
+
"""
|
67
|
+
for game_component in self.game.components:
|
68
|
+
component = game_component(
|
69
|
+
self.game,
|
70
|
+
self.coordinates,
|
71
|
+
self.height,
|
72
|
+
self.width,
|
73
|
+
self.map_directory,
|
74
|
+
self.logger,
|
75
|
+
**self.kwargs,
|
76
|
+
)
|
77
|
+
|
78
|
+
yield component.__class__.__name__
|
79
|
+
|
80
|
+
try:
|
81
|
+
component.process()
|
82
|
+
except Exception as e: # pylint: disable=W0718
|
83
|
+
self.logger.error(
|
84
|
+
"Error processing component %s: %s",
|
85
|
+
component.__class__.__name__,
|
86
|
+
e,
|
87
|
+
)
|
88
|
+
raise e
|
89
|
+
|
90
|
+
try:
|
91
|
+
component.commit_generation_info()
|
92
|
+
except Exception as e: # pylint: disable=W0718
|
93
|
+
self.logger.error(
|
94
|
+
"Error committing generation info for component %s: %s",
|
95
|
+
component.__class__.__name__,
|
96
|
+
e,
|
73
97
|
)
|
74
|
-
|
75
|
-
|
76
|
-
except Exception as e: # pylint: disable=W0718
|
77
|
-
self.logger.error(
|
78
|
-
"Error processing component %s: %s",
|
79
|
-
component.__class__.__name__,
|
80
|
-
e,
|
81
|
-
)
|
82
|
-
raise e
|
83
|
-
self.components.append(component)
|
84
|
-
|
85
|
-
pbar.update(1)
|
98
|
+
raise e
|
99
|
+
self.components.append(component)
|
86
100
|
|
87
101
|
def previews(self) -> list[str]:
|
88
102
|
"""Get list of preview images.
|
@@ -0,0 +1,72 @@
|
|
1
|
+
"""This module contains functions and clas for generating path steps."""
|
2
|
+
|
3
|
+
from typing import NamedTuple
|
4
|
+
|
5
|
+
from geopy.distance import distance # type: ignore
|
6
|
+
|
7
|
+
DEFAULT_DISTANCE = 2048
|
8
|
+
|
9
|
+
|
10
|
+
class PathStep(NamedTuple):
|
11
|
+
"""Represents parameters of one step in the path.
|
12
|
+
|
13
|
+
Attributes:
|
14
|
+
code {str} -- Tile code (N, NE, E, SE, S, SW, W, NW).
|
15
|
+
angle {int} -- Angle in degrees (for example 0 for North, 90 for East).
|
16
|
+
distance {int} -- Distance in meters from previous step.
|
17
|
+
size {tuple[int, int]} -- Size of the tile in pixels (width, height).
|
18
|
+
"""
|
19
|
+
|
20
|
+
code: str
|
21
|
+
angle: int
|
22
|
+
distance: int
|
23
|
+
size: tuple[int, int]
|
24
|
+
|
25
|
+
def get_destination(self, origin: tuple[float, float]) -> tuple[float, float]:
|
26
|
+
"""Calculate destination coordinates based on origin and step parameters.
|
27
|
+
|
28
|
+
Arguments:
|
29
|
+
origin {tuple[float, float]} -- Origin coordinates (latitude, longitude)
|
30
|
+
|
31
|
+
Returns:
|
32
|
+
tuple[float, float] -- Destination coordinates (latitude, longitude)
|
33
|
+
"""
|
34
|
+
destination = distance(meters=self.distance).destination(origin, self.angle)
|
35
|
+
return destination.latitude, destination.longitude
|
36
|
+
|
37
|
+
|
38
|
+
def get_steps(map_height: int, map_width: int) -> list[PathStep]:
|
39
|
+
"""Return a list of PathStep objects for each tile, which represent a step in the path.
|
40
|
+
Moving from the center of the map to North, then clockwise.
|
41
|
+
|
42
|
+
Arguments:
|
43
|
+
map_height {int} -- Height of the map in pixels
|
44
|
+
map_width {int} -- Width of the map in pixels
|
45
|
+
|
46
|
+
Returns:
|
47
|
+
list[PathStep] -- List of PathStep objects
|
48
|
+
"""
|
49
|
+
# Move clockwise from N and calculate coordinates and sizes for each tile.
|
50
|
+
half_width = int(map_width / 2)
|
51
|
+
half_height = int(map_height / 2)
|
52
|
+
|
53
|
+
half_default_distance = int(DEFAULT_DISTANCE / 2)
|
54
|
+
|
55
|
+
return [
|
56
|
+
PathStep("N", 0, half_height + half_default_distance, (map_width, DEFAULT_DISTANCE)),
|
57
|
+
PathStep(
|
58
|
+
"NE", 90, half_width + half_default_distance, (DEFAULT_DISTANCE, DEFAULT_DISTANCE)
|
59
|
+
),
|
60
|
+
PathStep("E", 180, half_height + half_default_distance, (DEFAULT_DISTANCE, map_height)),
|
61
|
+
PathStep(
|
62
|
+
"SE", 180, half_height + half_default_distance, (DEFAULT_DISTANCE, DEFAULT_DISTANCE)
|
63
|
+
),
|
64
|
+
PathStep("S", 270, half_width + half_default_distance, (map_width, DEFAULT_DISTANCE)),
|
65
|
+
PathStep(
|
66
|
+
"SW", 270, half_width + half_default_distance, (DEFAULT_DISTANCE, DEFAULT_DISTANCE)
|
67
|
+
),
|
68
|
+
PathStep("W", 0, half_height + half_default_distance, (DEFAULT_DISTANCE, map_height)),
|
69
|
+
PathStep(
|
70
|
+
"NW", 0, half_height + half_default_distance, (DEFAULT_DISTANCE, DEFAULT_DISTANCE)
|
71
|
+
),
|
72
|
+
]
|
maps4fs/generator/texture.py
CHANGED
@@ -5,7 +5,7 @@ from __future__ import annotations
|
|
5
5
|
import json
|
6
6
|
import os
|
7
7
|
import warnings
|
8
|
-
from typing import Callable, Generator, Optional
|
8
|
+
from typing import Any, Callable, Generator, Optional
|
9
9
|
|
10
10
|
import cv2
|
11
11
|
import numpy as np
|
@@ -149,7 +149,6 @@ class Texture(Component):
|
|
149
149
|
self._prepare_weights()
|
150
150
|
self._read_parameters()
|
151
151
|
self.draw()
|
152
|
-
self.info_sequence()
|
153
152
|
|
154
153
|
# pylint: disable=W0201
|
155
154
|
def _read_parameters(self) -> None:
|
@@ -176,23 +175,8 @@ class Texture(Component):
|
|
176
175
|
self.width_coef = self.width / self.map_width
|
177
176
|
self.logger.debug("Map coefficients (HxW): %s x %s.", self.height_coef, self.width_coef)
|
178
177
|
|
179
|
-
def info_sequence(self) ->
|
180
|
-
"""
|
181
|
-
|
182
|
-
Info sequence contains following attributes:
|
183
|
-
- coordinates
|
184
|
-
- bbox
|
185
|
-
- map_height
|
186
|
-
- map_width
|
187
|
-
- minimum_x
|
188
|
-
- minimum_y
|
189
|
-
- maximum_x
|
190
|
-
- maximum_y
|
191
|
-
- height
|
192
|
-
- width
|
193
|
-
- height_coef
|
194
|
-
- width_coef
|
195
|
-
"""
|
178
|
+
def info_sequence(self) -> dict[str, Any]:
|
179
|
+
"""Returns the JSON representation of the generation info for textures."""
|
196
180
|
useful_attributes = [
|
197
181
|
"coordinates",
|
198
182
|
"bbox",
|
@@ -207,11 +191,7 @@ class Texture(Component):
|
|
207
191
|
"height_coef",
|
208
192
|
"width_coef",
|
209
193
|
]
|
210
|
-
|
211
|
-
|
212
|
-
with open(self.info_save_path, "w") as f: # pylint: disable=W1514
|
213
|
-
json.dump(info_sequence, f, indent=4)
|
214
|
-
self.logger.info("Generation info saved to %s.", self.info_save_path)
|
194
|
+
return {attr: getattr(self, attr, None) for attr in useful_attributes}
|
215
195
|
|
216
196
|
def _prepare_weights(self):
|
217
197
|
self.logger.debug("Starting preparing weights from %s layers.", len(self.layers))
|
@@ -505,7 +485,7 @@ class Texture(Component):
|
|
505
485
|
merged.shape,
|
506
486
|
merged.dtype,
|
507
487
|
)
|
508
|
-
preview_path = os.path.join(self.
|
488
|
+
preview_path = os.path.join(self.previews_directory, "textures_osm.png")
|
509
489
|
cv2.imwrite(preview_path, merged) # pylint: disable=no-member
|
510
490
|
self.logger.info("Preview saved to %s.", preview_path)
|
511
491
|
return preview_path
|
@@ -0,0 +1,55 @@
|
|
1
|
+
"""This module contains the Tile component, which is used to generate a tile of DEM data around
|
2
|
+
the map."""
|
3
|
+
|
4
|
+
import os
|
5
|
+
|
6
|
+
from maps4fs.generator.dem import DEM
|
7
|
+
|
8
|
+
|
9
|
+
class Tile(DEM):
|
10
|
+
"""Component for creating a tile of DEM data around the map.
|
11
|
+
|
12
|
+
Arguments:
|
13
|
+
coordinates (tuple[float, float]): The latitude and longitude of the center of the map.
|
14
|
+
map_height (int): The height of the map in pixels.
|
15
|
+
map_width (int): The width of the map in pixels.
|
16
|
+
map_directory (str): The directory where the map files are stored.
|
17
|
+
logger (Any, optional): The logger to use. Must have at least three basic methods: debug,
|
18
|
+
info, warning. If not provided, default logging will be used.
|
19
|
+
|
20
|
+
Keyword Arguments:
|
21
|
+
tile_code (str): The code of the tile (N, NE, E, SE, S, SW, W, NW).
|
22
|
+
|
23
|
+
Public Methods:
|
24
|
+
get_output_resolution: Return the resolution of the output image.
|
25
|
+
process: Launch the component processing.
|
26
|
+
make_copy: Override the method to prevent copying the tile.
|
27
|
+
"""
|
28
|
+
|
29
|
+
def preprocess(self) -> None:
|
30
|
+
"""Prepares the component for processing. Reads the tile code from the kwargs and sets the
|
31
|
+
DEM path for the tile."""
|
32
|
+
super().preprocess()
|
33
|
+
self.code = self.kwargs.get("tile_code")
|
34
|
+
if not self.code:
|
35
|
+
raise ValueError("Tile code was not provided")
|
36
|
+
|
37
|
+
self.logger.debug(f"Generating tile {self.code}")
|
38
|
+
|
39
|
+
tiles_directory = os.path.join(self.map_directory, "objects", "tiles")
|
40
|
+
os.makedirs(tiles_directory, exist_ok=True)
|
41
|
+
|
42
|
+
self._dem_path = os.path.join(tiles_directory, f"{self.code}.png")
|
43
|
+
self.logger.debug(f"DEM path for tile {self.code} is {self._dem_path}")
|
44
|
+
|
45
|
+
def get_output_resolution(self) -> tuple[int, int]:
|
46
|
+
"""Return the resolution of the output image.
|
47
|
+
|
48
|
+
Returns:
|
49
|
+
tuple[int, int]: The width and height of the output image.
|
50
|
+
"""
|
51
|
+
return self.map_width, self.map_height
|
52
|
+
|
53
|
+
def make_copy(self, *args, **kwargs) -> None:
|
54
|
+
"""Override the method to prevent copying the tile."""
|
55
|
+
pass # pylint: disable=unnecessary-pass
|