maps4fs 0.6.7__py3-none-any.whl → 0.7.0__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
@@ -205,3 +205,43 @@ class DEM(Component):
205
205
  f"DEM data was normalized to {normalized_data.min()} - {normalized_data.max()}."
206
206
  )
207
207
  return normalized_data
208
+
209
+ def grayscale_preview(self) -> str:
210
+ """Converts DEM image to grayscale RGB image and saves it to the map directory.
211
+ Returns path to the preview image.
212
+
213
+ Returns:
214
+ str: Path to the preview image.
215
+ """
216
+ rgb_dem_path = self._dem_path.replace(".png", "_grayscale.png")
217
+ dem_data = cv2.imread(self._dem_path, cv2.IMREAD_GRAYSCALE)
218
+ dem_data_rgb = cv2.cvtColor(dem_data, cv2.COLOR_GRAY2RGB)
219
+ cv2.imwrite(rgb_dem_path, dem_data_rgb)
220
+ return rgb_dem_path
221
+
222
+ def colored_preview(self) -> str:
223
+ """Converts DEM image to colored RGB image and saves it to the map directory.
224
+ Returns path to the preview image.
225
+
226
+ Returns:
227
+ list[str]: List with a single path to the DEM file
228
+ """
229
+
230
+ colored_dem_path = self._dem_path.replace(".png", "_colored.png")
231
+ dem_data = cv2.imread(self._dem_path, cv2.IMREAD_GRAYSCALE)
232
+
233
+ # Normalize the DEM data to the range [0, 255]
234
+ # dem_data_normalized = cv2.normalize(dem_data, None, 0, 255, cv2.NORM_MINMAX)
235
+
236
+ dem_data_colored = cv2.applyColorMap(dem_data, cv2.COLORMAP_JET)
237
+
238
+ cv2.imwrite(colored_dem_path, dem_data_colored)
239
+ return colored_dem_path
240
+
241
+ def previews(self) -> list[str]:
242
+ """Get list of preview images.
243
+
244
+ Returns:
245
+ list[str]: List of preview images.
246
+ """
247
+ 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
 
@@ -35,6 +36,7 @@ class Map:
35
36
  logger: Any = None,
36
37
  ):
37
38
  self.game = game
39
+ self.components: list[Component] = []
38
40
  self.coordinates = coordinates
39
41
  self.distance = distance
40
42
  self.map_directory = map_directory
@@ -84,7 +86,8 @@ class Map:
84
86
  e,
85
87
  )
86
88
  raise e
87
- setattr(self, game_component.__name__.lower(), component)
89
+ # setattr(self, game_component.__name__.lower(), component)
90
+ self.components.append(component)
88
91
 
89
92
  pbar.update(1)
90
93
 
@@ -94,7 +97,13 @@ class Map:
94
97
  Returns:
95
98
  list[str]: List of preview images.
96
99
  """
97
- return self.texture.previews() # type: ignore # pylint: disable=no-member
100
+ # texture_previews = self.texture.previews() # type: ignore # pylint: disable=no-member
101
+ # dem_previews = self.dem.previews() # type: ignore # pylint: disable=no-member
102
+ # return texture_previews + dem_previews
103
+ previews = []
104
+ for component in self.components:
105
+ previews.extend(component.previews())
106
+ return previews
98
107
 
99
108
  def pack(self, archive_name: str) -> str:
100
109
  """Pack map directory to zip archive.
@@ -16,134 +16,6 @@ from shapely.geometry.base import BaseGeometry # type: ignore
16
16
 
17
17
  from maps4fs.generator.component import Component
18
18
 
19
- # region constants
20
- # texture = {
21
- # "name": "concrete",
22
- # "count": 4,
23
- # "tags": {"building": True},
24
- # "width": 8,
25
- # "color": (130, 130, 130),
26
- # }
27
-
28
- # textures = [
29
- # {
30
- # "name": "animalMud",
31
- # "count": 4,
32
- # },
33
- # {
34
- # "name": "asphalt",
35
- # "count": 4,
36
- # "tags": {"highway": ["motorway", "trunk", "primary"]},
37
- # "width": 8,
38
- # "color": (70, 70, 70),
39
- # },
40
- # {
41
- # "name": "cobbleStone",
42
- # "count": 4,
43
- # },
44
- # {
45
- # "name": "concrete",
46
- # "count": 4,
47
- # "tags": {"building": True},
48
- # "width": 8,
49
- # "color": (130, 130, 130),
50
- # },
51
- # {
52
- # "name": "concreteRubble",
53
- # "count": 4,
54
- # },
55
- # {
56
- # "name": "concreteTiles",
57
- # "count": 4,
58
- # },
59
- # {
60
- # "name": "dirt",
61
- # "count": 4,
62
- # },
63
- # {
64
- # "name": "dirtDark",
65
- # "count": 2,
66
- # "tags": {"highway": ["unclassified", "residential", "track"]},
67
- # "width": 2,
68
- # "color": (33, 67, 101),
69
- # },
70
- # {
71
- # "name": "forestGround",
72
- # "count": 4,
73
- # "tags": {"landuse": "farmland"},
74
- # "color": (47, 107, 85),
75
- # },
76
- # {
77
- # "name": "forestGroundLeaves",
78
- # "count": 4,
79
- # },
80
- # {
81
- # "name": "grass",
82
- # "count": 4,
83
- # "tags": {"natural": "grassland"},
84
- # "color": (34, 255, 34),
85
- # },
86
- # {
87
- # "name": "grassDirt",
88
- # "count": 4,
89
- # "tags": {"natural": ["wood", "tree_row"]},
90
- # "width": 2,
91
- # "color": (0, 252, 124),
92
- # },
93
- # {
94
- # "name": "gravel",
95
- # "count": 4,
96
- # "tags": {"highway": ["secondary", "tertiary", "road"]},
97
- # "width": 4,
98
- # "color": (140, 180, 210),
99
- # },
100
- # {
101
- # "name": "groundBricks",
102
- # "count": 4,
103
- # },
104
- # {
105
- # "name": "mountainRock",
106
- # "count": 4,
107
- # },
108
- # {
109
- # "name": "mountainRockDark",
110
- # "count": 4,
111
- # },
112
- # {
113
- # "name": "riverMud",
114
- # "count": 4,
115
- # },
116
- # {
117
- # "name": "waterPuddle",
118
- # "count": 0,
119
- # "tags": {"natural": "water", "waterway": True},
120
- # "width": 10,
121
- # "color": (255, 20, 20),
122
- # },
123
- # ]
124
-
125
- # TEXTURES = {
126
- # ? "animalMud": 4,
127
- # ? "asphalt": 4,
128
- # ? "cobbleStone": 4,
129
- # ? "concrete": 4,
130
- # "concreteRubble": 4,
131
- # "concreteTiles": 4,
132
- # "dirt": 4,
133
- # "dirtDark": 2,
134
- # "forestGround": 4,
135
- # "forestGroundLeaves": 4,
136
- # "grass": 4,
137
- # "grassDirt": 4,
138
- # "gravel": 4,
139
- # "groundBricks": 4,
140
- # "mountainRock": 4,
141
- # "mountainRockDark": 4,
142
- # "riverMud": 4,
143
- # "waterPuddle": 0,
144
- # }
145
- # endregion
146
-
147
19
 
148
20
  # pylint: disable=R0902
149
21
  class Texture(Component):
@@ -365,6 +237,9 @@ class Texture(Component):
365
237
  def draw(self) -> None:
366
238
  """Iterates over layers and fills them with polygons from OSM data."""
367
239
  for layer in self.layers:
240
+ if not layer.tags:
241
+ self.logger.debug("Layer %s has no tags, there's nothing to draw.", layer.name)
242
+ continue
368
243
  layer_path = layer.path(self._weights_dir)
369
244
  self.logger.debug("Drawing layer %s.", layer_path)
370
245
 
@@ -372,7 +247,7 @@ class Texture(Component):
372
247
  for polygon in self.polygons(layer.tags, layer.width): # type: ignore
373
248
  cv2.fillPoly(img, [polygon], color=255) # type: ignore
374
249
  cv2.imwrite(layer_path, img)
375
- self.logger.debug("Texture %s saved.", layer.path)
250
+ self.logger.debug("Texture %s saved.", layer_path)
376
251
 
377
252
  def get_relative_x(self, x: float) -> int:
378
253
  """Converts UTM X coordinate to relative X coordinate in map image.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: maps4fs
3
- Version: 0.6.7
3
+ Version: 0.7.0
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
@@ -34,6 +34,7 @@ Requires-Dist: tqdm
34
34
 
35
35
 
36
36
  [![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/iwatkot/maps4fs)](https://github.com/iwatkot/maps4fs/releases)
37
+ [![PyPI - Version](https://img.shields.io/pypi/v/maps4fs)](https://pypi.org/project/maps4fs)
37
38
  [![Docker Pulls](https://img.shields.io/docker/pulls/iwatkot/maps4fs)](https://hub.docker.com/repository/docker/iwatkot/maps4fs/general)
38
39
  [![GitHub issues](https://img.shields.io/github/issues/iwatkot/maps4fs)](https://github.com/iwatkot/maps4fs/issues)
39
40
  [![Maintainability](https://api.codeclimate.com/v1/badges/b922fd0a7188d37e61de/maintainability)](https://codeclimate.com/github/iwatkot/maps4fs/maintainability)<br>
@@ -50,8 +51,11 @@ Requires-Dist: tqdm
50
51
  🔃 Farming Simulator 25 (changes in the library are ready, waiting for the Giants to release the Giants Editor v10)<br>
51
52
 
52
53
  ## Quick Start
53
- For those, who don't want to read anything, here you go:<br>
54
- **Option 1:** open the [maps4fs](https://maps4fs.streamlit.app) on StreamLit a map template in a few clicks.<br>
54
+ There are several ways to use the tool. You obviously need the **first one**, but you can choose any of the others depending on your needs.<br>
55
+ ### 🚜 For most users
56
+ **Option 1:** open the [maps4fs](https://maps4fs.streamlit.app) on StreamLit and generate a map template in a few clicks.<br>
57
+
58
+ ### 😎 For advanced users
55
59
  **Option 2:** run the Docker version in your browser. Launch the following command in your terminal:
56
60
  ```bash
57
61
  docker run -d -p 8501:8501 iwatkot/maps4fs
@@ -59,6 +63,13 @@ docker run -d -p 8501:8501 iwatkot/maps4fs
59
63
  And open [http://localhost:8501](http://localhost:8501) in your browser.<br>
60
64
  If you don't know how to use Docker, navigate to the [Docker version](#option-2-docker-version), it's really simple.<br>
61
65
 
66
+ ### 🤯 For developers
67
+ **Option 3:** Python package. Install the package using the following command:
68
+ ```bash
69
+ pip install maps4fs
70
+ ```
71
+ And refer to the [Python package](#option-3-python-package) section to learn how to use it.<br>
72
+
62
73
  ## Overview
63
74
  The core idea is coming from the awesome [maps4cim](https://github.com/klamann/maps4cim) project.<br>
64
75
 
@@ -69,6 +80,24 @@ So, if you're new to map making, here's a quick overview of the process:
69
80
  3. Open the map template in the Giants Editor.
70
81
  4. Now you can start creating your map (adding roads, fields, buildings, etc.).
71
82
 
83
+ ### Previews
84
+
85
+ The generator also creates a multiple previews of the map. Here's the list of them:
86
+ 1. General preview - merging all the layers into one image with different colors.
87
+ 2. Grayscale DEM preview - a grayscale image of the height map (as it is).
88
+ 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.
89
+
90
+ So the colored DEM preview can be very handy when you're trying to find the best value for the `max_height` parameter. Learn more about it in the [Settings](#settings) section.
91
+
92
+ ![Previews](https://github.com/user-attachments/assets/69609169-834b-4269-ac6a-9a5c56b629dc)<br>
93
+ In the second row of the image you can see the following images:<br>
94
+ 1. DEM preview with `max_height=200`.
95
+ 2. Colored DEM preview with `max_height=200`.
96
+ 3. Colored DEM preview with `max_height=50`.
97
+
98
+ As you can see there's a huge difference between images 2 and 3. The third (with lower `max_height`) will have a higher terrain contrast, and the second one will have lower differences between the terrain heights.<br>
99
+ There's no like "in real world" option, because FS system of coordinates does not work in meters or something like that when talking about DEM. So you need to experiment with the `max_height` parameter to get the desired result. To clarify: in the example above the difference on the platue is about 80 meters, so `max_height=50` made this like super mountainous terrain, and `max_height=200` made it like a plain.
100
+
72
101
  ## How-To-Run
73
102
 
74
103
  You'll find detailed instructions on how to run the project below. But if you prefer video tutorials, here's one for you:
@@ -78,14 +107,14 @@ You'll find detailed instructions on how to run the project below. But if you pr
78
107
  ### Option 1: StreamLit
79
108
  **🗺️ Supported map sizes:** 2x2, 4x4, 8x8, 16x16 km.<br>
80
109
  🟢 Recommended for all users, you don't need to install anything.<br>
81
- Using Telegram bot [@maps4fs](https://t.me/maps4fsbot).<br>
110
+ Using the [StreamLit](https://maps4fs.streamlit.app) version of the tool is the easiest way to generate a map template. Just open the link and follow the instructions.
82
111
  Note: due to CPU and RAM limitations of the hosting, the generation may take some time. If you need faster processing, use the [Docker version](#option-2-docker-version).<br>
83
112
 
84
113
  Using it is easy and doesn't require any guides. Enjoy!
85
114
 
86
115
  ### Option 2: Docker version
87
116
  **🗺️ Supported map sizes:** 2x2, 4x4, 8x8, 16x16 km.<br>
88
- 🟢 Recommended for users who want faster processing, very simple installation.<br>
117
+ 🟠 Recommended for users who want faster processing, very simple installation.<br>
89
118
  You can launch the project with minimalistic UI in your browser using Docker. Follow these steps:
90
119
 
91
120
  1. Install [Docker](https://docs.docker.com/get-docker/) for your OS.
@@ -99,6 +128,53 @@ docker run -d -p 8501:8501 iwatkot/maps4fs
99
128
 
100
129
  ![WebUI](https://github.com/user-attachments/assets/e3b48c9d-7b87-4ce7-8ad7-98332a558a88)
101
130
 
131
+ ### Option 3: Python package
132
+ **🗺️ Supported map sizes:** 2x2, 4x4, 8x8, 16x16 km (and ANY other you may add).<br>
133
+ 🔴 Recommended for developers.<br>
134
+ You can use the Python package to generate maps. Follow these steps:
135
+
136
+ 1. Install the package from PyPI:
137
+ ```bash
138
+ pip install maps4fs
139
+ ```
140
+ 2. Import the Game class and create an instance of it:
141
+ ```python
142
+ import maps4fs as mfs
143
+
144
+ game = mfs.Game.from_code("FS25")
145
+ ```
146
+ 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>
147
+ Structure example:<br>
148
+
149
+ ```text
150
+ 📁 data
151
+ ┣ 📄 fs22-map-template.zip
152
+ ┗ 📄 fs22-texture-schema.json
153
+ ```
154
+
155
+ So it's recommended to download the `data` directory from the repository and place it in the root of your project.<br>
156
+
157
+ 3. Create an instance of the Map class:
158
+ ```python
159
+ import maps4fs as mfs
160
+
161
+ map = mfs.Map(
162
+ game,
163
+ (52.5200, 13.4050), # Latitude and longitude of the map center.
164
+ distance=1024, # The DISTANCE from the center to the edge of the map in meters. The map will be 2048x2048 meters.
165
+ map_directory="path/to/your/map/directory", # The directory where the map will be saved.
166
+ blur_seed=5, # The seed for the blur algorithm. The default value is 5, which means 5 meters.
167
+ max_height=400 # The maximum height of the map.
168
+ )
169
+ ```
170
+
171
+ 4. Generate the map:
172
+ ```python
173
+ map.generate()
174
+ ```
175
+
176
+ The map will be saved in the `map_directory` directory.
177
+
102
178
  ## Settings
103
179
  Advanced settings are available in the tool's UI under the **Advanced Settings** tab. Here's the list of them:
104
180
  - `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.
@@ -143,4 +219,3 @@ You can use this information to adjust some other sources of data to the map, e.
143
219
 
144
220
  ## Bugs and feature requests
145
221
  If you find a bug or have an idea for a new feature, please create an issue [here](https://github.com/iwatkot/maps4fs/issues) or contact me directly on [Telegram](https://t.me/iwatkot).<br>
146
- ℹ️ Please, don't bother me if the Telegram bot is down. As I said before this is related to the hosting limitations, if you want you can always run the tool locally or support the project by donating, so maybe I'll be able to afford better hosting.
@@ -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=xOKHvWIMD-7nIWGQNQi6Tan1Ovb1EPfHHVnUfUIC31k,10004
7
+ maps4fs/generator/game.py,sha256=IyXjNEC5epJmDdqjsrl4wKL85T1F23km73pUkBiuDWU,4468
8
+ maps4fs/generator/map.py,sha256=bqog38u2fltYdC1xgfeC0ehboL7Vp7V6nJq0NQOI9lA,4157
9
+ maps4fs/generator/texture.py,sha256=f5dPD5q17CTg8aY6G3i33vFk9ckbpndVb1W3hbT1wL4,15318
10
+ maps4fs-0.7.0.dist-info/LICENSE.md,sha256=-JY0v7p3dwXze61EbYiK7YEJ2aKrjaFZ8y2xYEOrmRY,1068
11
+ maps4fs-0.7.0.dist-info/METADATA,sha256=559aJEFn3HctVKqakqaBoTVA6xLY8WTNQsKTlFG-icE,12187
12
+ maps4fs-0.7.0.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
13
+ maps4fs-0.7.0.dist-info/top_level.txt,sha256=Ue9DSRlejRQRCaJueB0uLcKrWwsEq9zezfv5dI5mV1M,8
14
+ maps4fs-0.7.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.4.0)
2
+ Generator: setuptools (75.5.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -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=BUDDYIASk7lhYhJpEjZUTccKUI1GIfJIcPRgIgiUHAE,17938
10
- maps4fs-0.6.7.dist-info/LICENSE.md,sha256=-JY0v7p3dwXze61EbYiK7YEJ2aKrjaFZ8y2xYEOrmRY,1068
11
- maps4fs-0.6.7.dist-info/METADATA,sha256=6LkFXz56KTpX5IbDAnDNMv00lhjFKhYb00n0yr8ATSA,8869
12
- maps4fs-0.6.7.dist-info/WHEEL,sha256=a7TGlA-5DaHMRrarXjVbQagU3Man_dCnGIWMJr5kRWo,91
13
- maps4fs-0.6.7.dist-info/top_level.txt,sha256=Ue9DSRlejRQRCaJueB0uLcKrWwsEq9zezfv5dI5mV1M,8
14
- maps4fs-0.6.7.dist-info/RECORD,,