maps4fs 0.6.9__py3-none-any.whl → 0.7.1__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.
@@ -53,3 +53,11 @@ class Component:
53
53
  NotImplementedError: If the method is not implemented in the child class.
54
54
  """
55
55
  raise NotImplementedError
56
+
57
+ def previews(self) -> list[str]:
58
+ """Returns a list of paths to the preview images. Must be implemented in the child class.
59
+
60
+ Raises:
61
+ NotImplementedError: If the method is not implemented in the child class.
62
+ """
63
+ raise NotImplementedError
@@ -42,3 +42,12 @@ class Config(Component):
42
42
  self.logger.debug("Map size set to %sx%s in Map XML file.", width, height)
43
43
  tree.write(self._map_xml_path)
44
44
  self.logger.debug("Map XML file saved to: %s.", self._map_xml_path)
45
+
46
+ def previews(self) -> list[str]:
47
+ """Returns a list of paths to the preview images (empty list).
48
+ The component does not generate any preview images so it returns an empty list.
49
+
50
+ Returns:
51
+ list[str]: An empty list.
52
+ """
53
+ return []
maps4fs/generator/dem.py CHANGED
@@ -29,9 +29,6 @@ class DEM(Component):
29
29
  """
30
30
 
31
31
  def preprocess(self) -> None:
32
- self._blur_seed: int = self.kwargs.get("blur_seed") or 5
33
- self._max_height: int = self.kwargs.get("max_height") or 200
34
-
35
32
  self._dem_path = self.game.dem_file_path(self.map_directory)
36
33
  self.temp_dir = "temp"
37
34
  self.hgt_dir = os.path.join(self.temp_dir, "hgt")
@@ -87,19 +84,17 @@ class DEM(Component):
87
84
  f"Min: {data.min()}, max: {data.max()}."
88
85
  )
89
86
 
90
- normalized_data = self._normalize_dem(data)
91
-
92
87
  resampled_data = cv2.resize(
93
- normalized_data, dem_output_resolution, interpolation=cv2.INTER_LINEAR
94
- )
88
+ data, dem_output_resolution, interpolation=cv2.INTER_LINEAR
89
+ ).astype("uint16")
90
+
95
91
  self.logger.debug(
96
92
  f"DEM data was resampled. Shape: {resampled_data.shape}, "
97
93
  f"dtype: {resampled_data.dtype}. "
98
94
  f"Min: {resampled_data.min()}, max: {resampled_data.max()}."
99
95
  )
100
96
 
101
- blurred_data = cv2.GaussianBlur(resampled_data, (self._blur_seed, self._blur_seed), 0)
102
- cv2.imwrite(self._dem_path, blurred_data)
97
+ cv2.imwrite(self._dem_path, resampled_data)
103
98
  self.logger.debug("DEM data was saved to %s.", self._dem_path)
104
99
 
105
100
  def _tile_info(self, lat: float, lon: float) -> tuple[str, str]:
@@ -182,26 +177,42 @@ class DEM(Component):
182
177
  cv2.imwrite(self._dem_path, dem_data) # pylint: disable=no-member
183
178
  self.logger.warning("DEM data filled with zeros and saved to %s.", self._dem_path)
184
179
 
185
- def _normalize_dem(self, data: np.ndarray) -> np.ndarray:
186
- """Normalize DEM data to 16-bit unsigned integer using max height from settings.
180
+ def grayscale_preview(self) -> str:
181
+ """Converts DEM image to grayscale RGB image and saves it to the map directory.
182
+ Returns path to the preview image.
187
183
 
188
- Args:
189
- data (np.ndarray): DEM data from SRTM file after cropping.
184
+ Returns:
185
+ str: Path to the preview image.
186
+ """
187
+ rgb_dem_path = self._dem_path.replace(".png", "_grayscale.png")
188
+ dem_data = cv2.imread(self._dem_path, cv2.IMREAD_GRAYSCALE)
189
+ dem_data_rgb = cv2.cvtColor(dem_data, cv2.COLOR_GRAY2RGB)
190
+ cv2.imwrite(rgb_dem_path, dem_data_rgb)
191
+ return rgb_dem_path
192
+
193
+ def colored_preview(self) -> str:
194
+ """Converts DEM image to colored RGB image and saves it to the map directory.
195
+ Returns path to the preview image.
190
196
 
191
197
  Returns:
192
- np.ndarray: Normalized DEM data.
198
+ list[str]: List with a single path to the DEM file
193
199
  """
194
- max_dev = data.max() - data.min()
195
- scaling_factor = max_dev / self._max_height if max_dev < self._max_height else 1
196
- adjusted_max_height = int(65535 * scaling_factor)
197
- self.logger.debug(
198
- f"Maximum deviation: {max_dev}. Scaling factor: {scaling_factor}. "
199
- f"Adjusted max height: {adjusted_max_height}."
200
- )
201
- normalized_data = (
202
- (data - data.min()) / (data.max() - data.min()) * adjusted_max_height
203
- ).astype("uint16")
204
- self.logger.debug(
205
- f"DEM data was normalized to {normalized_data.min()} - {normalized_data.max()}."
206
- )
207
- return normalized_data
200
+
201
+ colored_dem_path = self._dem_path.replace(".png", "_colored.png")
202
+ dem_data = cv2.imread(self._dem_path, cv2.IMREAD_GRAYSCALE)
203
+
204
+ # Normalize the DEM data to the range [0, 255]
205
+ # dem_data_normalized = cv2.normalize(dem_data, None, 0, 255, cv2.NORM_MINMAX)
206
+
207
+ dem_data_colored = cv2.applyColorMap(dem_data, cv2.COLORMAP_JET)
208
+
209
+ cv2.imwrite(colored_dem_path, dem_data_colored)
210
+ return colored_dem_path
211
+
212
+ def previews(self) -> list[str]:
213
+ """Get list of preview images.
214
+
215
+ Returns:
216
+ list[str]: List of preview images.
217
+ """
218
+ return [self.grayscale_preview(), self.colored_preview()]
maps4fs/generator/map.py CHANGED
@@ -6,11 +6,12 @@ from typing import Any
6
6
 
7
7
  from tqdm import tqdm
8
8
 
9
+ from maps4fs.generator.component import Component
9
10
  from maps4fs.generator.game import Game
10
11
  from maps4fs.logger import Logger
11
12
 
12
13
 
13
- # pylint: disable=R0913
14
+ # pylint: disable=R0913, R0902
14
15
  class Map:
15
16
  """Class used to generate map using all components.
16
17
 
@@ -19,8 +20,6 @@ class Map:
19
20
  coordinates (tuple[float, float]): Coordinates of the center of the map.
20
21
  distance (int): Distance from the center of the map.
21
22
  map_directory (str): Path to the directory where map files will be stored.
22
- blur_seed (int): Seed used for blur effect.
23
- max_height (int): Maximum height of the map.
24
23
  logger (Any): Logger instance
25
24
  """
26
25
 
@@ -30,11 +29,10 @@ class Map:
30
29
  coordinates: tuple[float, float],
31
30
  distance: int,
32
31
  map_directory: str,
33
- blur_seed: int,
34
- max_height: int,
35
32
  logger: Any = None,
36
33
  ):
37
34
  self.game = game
35
+ self.components: list[Component] = []
38
36
  self.coordinates = coordinates
39
37
  self.distance = distance
40
38
  self.map_directory = map_directory
@@ -53,15 +51,6 @@ class Map:
53
51
  except Exception as e:
54
52
  raise RuntimeError(f"Can not unpack map template due to error: {e}") from e
55
53
 
56
- # Blur seed should be positive and odd.
57
- if blur_seed <= 0:
58
- raise ValueError("Blur seed should be positive.")
59
- if blur_seed % 2 == 0:
60
- blur_seed += 1
61
-
62
- self.blur_seed = blur_seed
63
- self.max_height = max_height
64
-
65
54
  def generate(self) -> None:
66
55
  """Launch map generation using all components."""
67
56
  with tqdm(total=len(self.game.components), desc="Generating map...") as pbar:
@@ -72,8 +61,6 @@ class Map:
72
61
  self.distance,
73
62
  self.map_directory,
74
63
  self.logger,
75
- blur_seed=self.blur_seed,
76
- max_height=self.max_height,
77
64
  )
78
65
  try:
79
66
  component.process()
@@ -84,7 +71,8 @@ class Map:
84
71
  e,
85
72
  )
86
73
  raise e
87
- setattr(self, game_component.__name__.lower(), component)
74
+ # setattr(self, game_component.__name__.lower(), component)
75
+ self.components.append(component)
88
76
 
89
77
  pbar.update(1)
90
78
 
@@ -94,7 +82,13 @@ class Map:
94
82
  Returns:
95
83
  list[str]: List of preview images.
96
84
  """
97
- return self.texture.previews() # type: ignore # pylint: disable=no-member
85
+ # texture_previews = self.texture.previews() # type: ignore # pylint: disable=no-member
86
+ # dem_previews = self.dem.previews() # type: ignore # pylint: disable=no-member
87
+ # return texture_previews + dem_previews
88
+ previews = []
89
+ for component in self.components:
90
+ previews.extend(component.previews())
91
+ return previews
98
92
 
99
93
  def pack(self, archive_name: str) -> str:
100
94
  """Pack map directory to zip archive.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: maps4fs
3
- Version: 0.6.9
3
+ Version: 0.7.1
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
@@ -16,7 +16,6 @@ License-File: LICENSE.md
16
16
  Requires-Dist: opencv-python
17
17
  Requires-Dist: osmnx<2.0.0
18
18
  Requires-Dist: rasterio
19
- Requires-Dist: python-dotenv
20
19
  Requires-Dist: tqdm
21
20
 
22
21
  <div align="center" markdown>
@@ -80,6 +79,20 @@ So, if you're new to map making, here's a quick overview of the process:
80
79
  3. Open the map template in the Giants Editor.
81
80
  4. Now you can start creating your map (adding roads, fields, buildings, etc.).
82
81
 
82
+ ### Previews
83
+
84
+ The generator also creates a multiple previews of the map. Here's the list of them:
85
+ 1. General preview - merging all the layers into one image with different colors.
86
+ 2. Grayscale DEM preview - a grayscale image of the height map (as it is).
87
+ 3. Colored DEM preview - a colored image of the height map (from blue to red). The blue color represents the lowest point, and the red color represents the highest point.
88
+
89
+ ![16 km map](https://github.com/user-attachments/assets/82543bcc-1289-479e-bd13-85a8890f0485)<br>
90
+ *Preview of a 16 km map with a 500-meter mountain in the middle of it.*<br>
91
+
92
+ Parameters:
93
+ - coordinates: 45.15, 19.71
94
+ - size: 16 x 16 km
95
+
83
96
  ## How-To-Run
84
97
 
85
98
  You'll find detailed instructions on how to run the project below. But if you prefer video tutorials, here's one for you:
@@ -145,8 +158,6 @@ map = mfs.Map(
145
158
  (52.5200, 13.4050), # Latitude and longitude of the map center.
146
159
  distance=1024, # The DISTANCE from the center to the edge of the map in meters. The map will be 2048x2048 meters.
147
160
  map_directory="path/to/your/map/directory", # The directory where the map will be saved.
148
- blur_seed=5, # The seed for the blur algorithm. The default value is 5, which means 5 meters.
149
- max_height=400 # The maximum height of the map.
150
161
  )
151
162
  ```
152
163
 
@@ -157,11 +168,6 @@ map.generate()
157
168
 
158
169
  The map will be saved in the `map_directory` directory.
159
170
 
160
- ## Settings
161
- Advanced settings are available in the tool's UI under the **Advanced Settings** tab. Here's the list of them:
162
- - `max_height` - the maximum height of the map. The default value is 400. Select smaller values for plain-like maps and bigger values for mountainous maps. You may need to experiment with this value to get the desired result.
163
- - `blur_seed` - the seed for the blur algorithm. The default value is 5, which means 5 meters. The bigger the value, the smoother the map will be. The smaller the value, the more detailed the map will be. Keep in mind that for some regions, where terrain is bumpy, disabling the blur algorithm may lead to a very rough map. So, I recommend leaving this value as it is.
164
-
165
171
  ## Features
166
172
  - Allows to enter a location by lat and lon (e.g. from Google Maps).
167
173
  - Allows to select a size of the map (2x2, 4x4, 8x8 km, 16x16 km).
@@ -0,0 +1,14 @@
1
+ maps4fs/__init__.py,sha256=da4jmND2Ths9AffnkAKgzLHNkvKFOc_l21gJisPXqWY,155
2
+ maps4fs/logger.py,sha256=CneeHxQywjNUJXqQrUUSeiDxu95FfrfyK_Si1v0gMZ8,1477
3
+ maps4fs/generator/__init__.py,sha256=zZMLEkGzb4z0xql650gOtGSvcgX58DnJ2yN3vC2daRk,43
4
+ maps4fs/generator/component.py,sha256=Xq5yVFMqG1d1iHTtn2mn5RN-UntsutXIvV5eQYBuFLw,2046
5
+ maps4fs/generator/config.py,sha256=wlGacB69fdcvggfEDvCpx5gzPRKq_4Sh6xuX-z-kwwE,2043
6
+ maps4fs/generator/dem.py,sha256=SdYSz_rS10oIL6t3OGuFhH1A6RhL8BF_sXUdxxWpL4Q,8754
7
+ maps4fs/generator/game.py,sha256=IyXjNEC5epJmDdqjsrl4wKL85T1F23km73pUkBiuDWU,4468
8
+ maps4fs/generator/map.py,sha256=nGU6i45lON1oxYEGRRRzRbFhWE_8bJtgZzIwubY89MQ,3640
9
+ maps4fs/generator/texture.py,sha256=f5dPD5q17CTg8aY6G3i33vFk9ckbpndVb1W3hbT1wL4,15318
10
+ maps4fs-0.7.1.dist-info/LICENSE.md,sha256=-JY0v7p3dwXze61EbYiK7YEJ2aKrjaFZ8y2xYEOrmRY,1068
11
+ maps4fs-0.7.1.dist-info/METADATA,sha256=zsoFq2z1kSshdDqbwzeD7bXWwz1fX4t0C3dbiLBguwA,10418
12
+ maps4fs-0.7.1.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
13
+ maps4fs-0.7.1.dist-info/top_level.txt,sha256=Ue9DSRlejRQRCaJueB0uLcKrWwsEq9zezfv5dI5mV1M,8
14
+ maps4fs-0.7.1.dist-info/RECORD,,
@@ -1,14 +0,0 @@
1
- maps4fs/__init__.py,sha256=da4jmND2Ths9AffnkAKgzLHNkvKFOc_l21gJisPXqWY,155
2
- maps4fs/logger.py,sha256=CneeHxQywjNUJXqQrUUSeiDxu95FfrfyK_Si1v0gMZ8,1477
3
- maps4fs/generator/__init__.py,sha256=zZMLEkGzb4z0xql650gOtGSvcgX58DnJ2yN3vC2daRk,43
4
- maps4fs/generator/component.py,sha256=UmR6Gbs-uDld7897q_9hOOzqBXaIYD8svmw_a3IgC5g,1761
5
- maps4fs/generator/config.py,sha256=3X9E6luYh0dBlYcGvE4Exzp-ShAMCFjGB_8SK3qPBtM,1760
6
- maps4fs/generator/dem.py,sha256=_1d_TPMOGBgl2-R_CRMbKumzxCbQyb-hcpqsElhYbQ4,8546
7
- maps4fs/generator/game.py,sha256=IyXjNEC5epJmDdqjsrl4wKL85T1F23km73pUkBiuDWU,4468
8
- maps4fs/generator/map.py,sha256=Y7ERUB6ivxJilDAjE9UD0-vl0SKtzj6J2f8QPXM6i48,3712
9
- maps4fs/generator/texture.py,sha256=f5dPD5q17CTg8aY6G3i33vFk9ckbpndVb1W3hbT1wL4,15318
10
- maps4fs-0.6.9.dist-info/LICENSE.md,sha256=-JY0v7p3dwXze61EbYiK7YEJ2aKrjaFZ8y2xYEOrmRY,1068
11
- maps4fs-0.6.9.dist-info/METADATA,sha256=xmzb7SNRXB0z6_nSFRhBny1XdV84cPWyjWSWz264COQ,10652
12
- maps4fs-0.6.9.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
13
- maps4fs-0.6.9.dist-info/top_level.txt,sha256=Ue9DSRlejRQRCaJueB0uLcKrWwsEq9zezfv5dI5mV1M,8
14
- maps4fs-0.6.9.dist-info/RECORD,,