maps4fs 1.5.0__py3-none-any.whl → 1.6.91__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 +5 -2
- maps4fs/generator/background.py +161 -113
- maps4fs/generator/component.py +34 -1
- maps4fs/generator/dem.py +33 -154
- maps4fs/generator/dtm/__init__.py +0 -0
- maps4fs/generator/dtm/dtm.py +321 -0
- maps4fs/generator/dtm/srtm.py +226 -0
- maps4fs/generator/dtm/usgs.py +351 -0
- maps4fs/generator/game.py +2 -1
- maps4fs/generator/grle.py +94 -28
- maps4fs/generator/i3d.py +17 -21
- maps4fs/generator/map.py +38 -135
- maps4fs/generator/satellite.py +92 -0
- maps4fs/generator/settings.py +187 -0
- maps4fs/generator/texture.py +65 -12
- {maps4fs-1.5.0.dist-info → maps4fs-1.6.91.dist-info}/METADATA +55 -11
- maps4fs-1.6.91.dist-info/RECORD +27 -0
- {maps4fs-1.5.0.dist-info → maps4fs-1.6.91.dist-info}/WHEEL +1 -1
- maps4fs-1.5.0.dist-info/RECORD +0 -21
- {maps4fs-1.5.0.dist-info → maps4fs-1.6.91.dist-info}/LICENSE.md +0 -0
- {maps4fs-1.5.0.dist-info → maps4fs-1.6.91.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,187 @@
|
|
1
|
+
"""This module contains settings models for all components."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
from typing import Any
|
6
|
+
|
7
|
+
from pydantic import BaseModel, ConfigDict
|
8
|
+
|
9
|
+
|
10
|
+
class SharedSettings(BaseModel):
|
11
|
+
"""Represents the shared settings for all components."""
|
12
|
+
|
13
|
+
mesh_z_scaling_factor: float | None = None
|
14
|
+
height_scale_multiplier: float | None = None
|
15
|
+
height_scale_value: float | None = None
|
16
|
+
change_height_scale: bool = False
|
17
|
+
|
18
|
+
model_config = ConfigDict(
|
19
|
+
frozen=False,
|
20
|
+
)
|
21
|
+
|
22
|
+
|
23
|
+
class SettingsModel(BaseModel):
|
24
|
+
"""Base class for settings models. It provides methods to convert settings to and from JSON."""
|
25
|
+
|
26
|
+
model_config = ConfigDict(
|
27
|
+
frozen=False,
|
28
|
+
)
|
29
|
+
|
30
|
+
@classmethod
|
31
|
+
def all_settings_to_json(cls) -> dict[str, dict[str, Any]]:
|
32
|
+
"""Get all settings of the current class and its subclasses as a dictionary.
|
33
|
+
|
34
|
+
Returns:
|
35
|
+
dict[str, dict[str, Any]]: Dictionary with settings of the current class and its
|
36
|
+
subclasses.
|
37
|
+
"""
|
38
|
+
all_settings = {}
|
39
|
+
for subclass in cls.__subclasses__():
|
40
|
+
all_settings[subclass.__name__] = subclass().model_dump()
|
41
|
+
|
42
|
+
return all_settings
|
43
|
+
|
44
|
+
@classmethod
|
45
|
+
def all_settings_from_json(
|
46
|
+
cls, data: dict, flattening: bool = True
|
47
|
+
) -> dict[str, SettingsModel]:
|
48
|
+
"""Create settings instances from JSON data.
|
49
|
+
|
50
|
+
Arguments:
|
51
|
+
data (dict): JSON data.
|
52
|
+
flattening (bool): if set to True will flattet iterables to use the first element
|
53
|
+
of it.
|
54
|
+
|
55
|
+
Returns:
|
56
|
+
dict[str, Type[SettingsModel]]: Dictionary with settings instances.
|
57
|
+
"""
|
58
|
+
settings = {}
|
59
|
+
for subclass in cls.__subclasses__():
|
60
|
+
subclass_data = data[subclass.__name__]
|
61
|
+
if flattening:
|
62
|
+
for key, value in subclass_data.items():
|
63
|
+
if isinstance(value, (list, tuple)):
|
64
|
+
subclass_data[key] = value[0]
|
65
|
+
|
66
|
+
settings[subclass.__name__] = subclass(**subclass_data)
|
67
|
+
|
68
|
+
return settings
|
69
|
+
|
70
|
+
@classmethod
|
71
|
+
def all_settings(cls) -> list[SettingsModel]:
|
72
|
+
"""Get all settings of the current class and its subclasses.
|
73
|
+
|
74
|
+
Returns:
|
75
|
+
list[SettingsModel]: List with settings of the current class and its subclasses.
|
76
|
+
"""
|
77
|
+
settings = []
|
78
|
+
for subclass in cls.__subclasses__():
|
79
|
+
settings.append(subclass())
|
80
|
+
|
81
|
+
return settings
|
82
|
+
|
83
|
+
|
84
|
+
class DEMSettings(SettingsModel):
|
85
|
+
"""Represents the advanced settings for DEM component.
|
86
|
+
|
87
|
+
Attributes:
|
88
|
+
multiplier (int): multiplier for the heightmap, every pixel will be multiplied by this
|
89
|
+
value.
|
90
|
+
blur_radius (int): radius of the blur filter.
|
91
|
+
plateau (int): plateau height, will be added to each pixel.
|
92
|
+
water_depth (int): water depth, will be subtracted from each pixel where the water
|
93
|
+
is present.
|
94
|
+
"""
|
95
|
+
|
96
|
+
multiplier: int = 1
|
97
|
+
blur_radius: int = 35
|
98
|
+
plateau: int = 0
|
99
|
+
water_depth: int = 0
|
100
|
+
|
101
|
+
|
102
|
+
class BackgroundSettings(SettingsModel):
|
103
|
+
"""Represents the advanced settings for background component.
|
104
|
+
|
105
|
+
Attributes:
|
106
|
+
generate_background (bool): generate obj files for the background terrain.
|
107
|
+
generate_water (bool): generate obj files for the water.
|
108
|
+
resize_factor (int): resize factor for the background terrain and water.
|
109
|
+
It will be used as 1 / resize_factor of the original size.
|
110
|
+
"""
|
111
|
+
|
112
|
+
generate_background: bool = False
|
113
|
+
generate_water: bool = False
|
114
|
+
resize_factor: int = 8
|
115
|
+
remove_center: bool = False
|
116
|
+
apply_decimation: bool = False
|
117
|
+
decimation_percent: int = 25
|
118
|
+
decimation_agression: int = 3
|
119
|
+
|
120
|
+
|
121
|
+
class GRLESettings(SettingsModel):
|
122
|
+
"""Represents the advanced settings for GRLE component.
|
123
|
+
|
124
|
+
Attributes:
|
125
|
+
farmland_margin (int): margin around the farmland.
|
126
|
+
random_plants (bool): generate random plants on the map or use the default one.
|
127
|
+
add_farmyards (bool): If True, regions of frarmyards will be added to the map
|
128
|
+
without corresponding fields.
|
129
|
+
"""
|
130
|
+
|
131
|
+
farmland_margin: int = 0
|
132
|
+
random_plants: bool = True
|
133
|
+
add_farmyards: bool = False
|
134
|
+
base_grass: tuple | str = ("smallDenseMix", "meadow")
|
135
|
+
plants_island_minimum_size: int = 10
|
136
|
+
plants_island_maximum_size: int = 200
|
137
|
+
plants_island_vertex_count: int = 30
|
138
|
+
plants_island_rounding_radius: int = 15
|
139
|
+
plants_island_percent: int = 100
|
140
|
+
|
141
|
+
|
142
|
+
class I3DSettings(SettingsModel):
|
143
|
+
"""Represents the advanced settings for I3D component.
|
144
|
+
|
145
|
+
Attributes:
|
146
|
+
forest_density (int): density of the forest (distance between trees).
|
147
|
+
"""
|
148
|
+
|
149
|
+
forest_density: int = 10
|
150
|
+
|
151
|
+
|
152
|
+
class TextureSettings(SettingsModel):
|
153
|
+
"""Represents the advanced settings for texture component.
|
154
|
+
|
155
|
+
Attributes:
|
156
|
+
dissolve (bool): dissolve the texture into several images.
|
157
|
+
fields_padding (int): padding around the fields.
|
158
|
+
skip_drains (bool): skip drains generation.
|
159
|
+
"""
|
160
|
+
|
161
|
+
dissolve: bool = False
|
162
|
+
fields_padding: int = 0
|
163
|
+
skip_drains: bool = False
|
164
|
+
|
165
|
+
|
166
|
+
class SplineSettings(SettingsModel):
|
167
|
+
"""Represents the advanced settings for spline component.
|
168
|
+
|
169
|
+
Attributes:
|
170
|
+
spline_density (int): the number of extra points that will be added between each two
|
171
|
+
existing points.
|
172
|
+
"""
|
173
|
+
|
174
|
+
spline_density: int = 2
|
175
|
+
|
176
|
+
|
177
|
+
class SatelliteSettings(SettingsModel):
|
178
|
+
"""Represents the advanced settings for satellite component.
|
179
|
+
|
180
|
+
Attributes:
|
181
|
+
download_images (bool): download satellite images.
|
182
|
+
margin (int): margin around the map.
|
183
|
+
"""
|
184
|
+
|
185
|
+
download_images: bool = False
|
186
|
+
satellite_margin: int = 100
|
187
|
+
zoom_level: int = 14
|
maps4fs/generator/texture.py
CHANGED
@@ -5,6 +5,8 @@ from __future__ import annotations
|
|
5
5
|
import json
|
6
6
|
import os
|
7
7
|
import re
|
8
|
+
import shutil
|
9
|
+
import warnings
|
8
10
|
from collections import defaultdict
|
9
11
|
from typing import Any, Callable, Generator, Optional
|
10
12
|
|
@@ -69,6 +71,7 @@ class Texture(Component):
|
|
69
71
|
usage: str | None = None,
|
70
72
|
background: bool = False,
|
71
73
|
invisible: bool = False,
|
74
|
+
procedural: list[str] | None = None,
|
72
75
|
):
|
73
76
|
self.name = name
|
74
77
|
self.count = count
|
@@ -81,6 +84,7 @@ class Texture(Component):
|
|
81
84
|
self.usage = usage
|
82
85
|
self.background = background
|
83
86
|
self.invisible = invisible
|
87
|
+
self.procedural = procedural
|
84
88
|
|
85
89
|
def to_json(self) -> dict[str, str | list[str] | bool]: # type: ignore
|
86
90
|
"""Returns dictionary with layer data.
|
@@ -99,6 +103,7 @@ class Texture(Component):
|
|
99
103
|
"usage": self.usage,
|
100
104
|
"background": self.background,
|
101
105
|
"invisible": self.invisible,
|
106
|
+
"procedural": self.procedural,
|
102
107
|
}
|
103
108
|
|
104
109
|
data = {k: v for k, v in data.items() if v is not None}
|
@@ -187,7 +192,7 @@ class Texture(Component):
|
|
187
192
|
custom_schema = self.kwargs.get("texture_custom_schema")
|
188
193
|
if custom_schema:
|
189
194
|
layers_schema = custom_schema # type: ignore
|
190
|
-
self.logger.
|
195
|
+
self.logger.debug("Custom schema loaded with %s layers.", len(layers_schema))
|
191
196
|
else:
|
192
197
|
if not os.path.isfile(self.game.texture_schema):
|
193
198
|
raise FileNotFoundError(
|
@@ -202,18 +207,20 @@ class Texture(Component):
|
|
202
207
|
|
203
208
|
try:
|
204
209
|
self.layers = [self.Layer.from_json(layer) for layer in layers_schema] # type: ignore
|
205
|
-
self.logger.
|
210
|
+
self.logger.debug("Loaded %s layers.", len(self.layers))
|
206
211
|
except Exception as e: # pylint: disable=W0703
|
207
212
|
raise ValueError(f"Error loading texture layers: {e}") from e
|
208
213
|
|
209
214
|
base_layer = self.get_base_layer()
|
210
215
|
if base_layer:
|
211
216
|
self.logger.debug("Base layer found: %s.", base_layer.name)
|
212
|
-
else:
|
213
|
-
self.logger.warning("No base layer found.")
|
214
217
|
|
215
218
|
self._weights_dir = self.game.weights_dir_path(self.map_directory)
|
216
219
|
self.logger.debug("Weights directory: %s.", self._weights_dir)
|
220
|
+
self.procedural_dir = os.path.join(self._weights_dir, "masks")
|
221
|
+
os.makedirs(self.procedural_dir, exist_ok=True)
|
222
|
+
self.logger.debug("Procedural directory: %s.", self.procedural_dir)
|
223
|
+
|
217
224
|
self.info_save_path = os.path.join(self.map_directory, "generation_info.json")
|
218
225
|
self.logger.debug("Generation info save path: %s.", self.info_save_path)
|
219
226
|
|
@@ -253,11 +260,56 @@ class Texture(Component):
|
|
253
260
|
return layer
|
254
261
|
return None
|
255
262
|
|
256
|
-
def process(self):
|
263
|
+
def process(self) -> None:
|
264
|
+
"""Processes the data to generate textures."""
|
257
265
|
self._prepare_weights()
|
258
266
|
self._read_parameters()
|
259
267
|
self.draw()
|
260
268
|
self.rotate_textures()
|
269
|
+
self.copy_procedural()
|
270
|
+
|
271
|
+
def copy_procedural(self) -> None:
|
272
|
+
"""Copies some of the textures to use them as mask for procedural generation.
|
273
|
+
Creates an empty blockmask if it does not exist."""
|
274
|
+
blockmask_path = os.path.join(self.procedural_dir, "BLOCKMASK.png")
|
275
|
+
if not os.path.isfile(blockmask_path):
|
276
|
+
self.logger.debug("BLOCKMASK.png not found, creating an empty file.")
|
277
|
+
img = np.zeros((self.map_size, self.map_size), dtype=np.uint8)
|
278
|
+
cv2.imwrite(blockmask_path, img) # pylint: disable=no-member
|
279
|
+
|
280
|
+
pg_layers_by_type = defaultdict(list)
|
281
|
+
for layer in self.layers:
|
282
|
+
if layer.procedural:
|
283
|
+
# Get path to the original file.
|
284
|
+
texture_path = layer.get_preview_or_path(self._weights_dir)
|
285
|
+
for procedural_layer_name in layer.procedural:
|
286
|
+
pg_layers_by_type[procedural_layer_name].append(texture_path)
|
287
|
+
|
288
|
+
if not pg_layers_by_type:
|
289
|
+
self.logger.debug("No procedural layers found.")
|
290
|
+
return
|
291
|
+
|
292
|
+
for procedural_layer_name, texture_paths in pg_layers_by_type.items():
|
293
|
+
procedural_save_path = os.path.join(self.procedural_dir, f"{procedural_layer_name}.png")
|
294
|
+
if len(texture_paths) > 1:
|
295
|
+
# If there are more than one texture, merge them.
|
296
|
+
merged_texture = np.zeros((self.map_size, self.map_size), dtype=np.uint8)
|
297
|
+
for texture_path in texture_paths:
|
298
|
+
# pylint: disable=E1101
|
299
|
+
texture = cv2.imread(texture_path, cv2.IMREAD_UNCHANGED)
|
300
|
+
merged_texture[texture == 255] = 255
|
301
|
+
cv2.imwrite(procedural_save_path, merged_texture) # pylint: disable=no-member
|
302
|
+
self.logger.debug(
|
303
|
+
"Procedural file %s merged from %s textures.",
|
304
|
+
procedural_save_path,
|
305
|
+
len(texture_paths),
|
306
|
+
)
|
307
|
+
elif len(texture_paths) == 1:
|
308
|
+
# Otherwise, copy the texture.
|
309
|
+
shutil.copyfile(texture_paths[0], procedural_save_path)
|
310
|
+
self.logger.debug(
|
311
|
+
"Procedural file %s copied from %s.", procedural_save_path, texture_paths[0]
|
312
|
+
)
|
261
313
|
|
262
314
|
def rotate_textures(self) -> None:
|
263
315
|
"""Rotates textures of the layers which have tags."""
|
@@ -276,8 +328,6 @@ class Texture(Component):
|
|
276
328
|
output_height=self.map_size,
|
277
329
|
output_width=self.map_size,
|
278
330
|
)
|
279
|
-
else:
|
280
|
-
self.logger.warning("Layer path %s not found.", layer_path)
|
281
331
|
else:
|
282
332
|
self.logger.debug(
|
283
333
|
"Skipping rotation of layer %s because it has no tags.", layer.name
|
@@ -305,8 +355,7 @@ class Texture(Component):
|
|
305
355
|
useful_attributes = [
|
306
356
|
"coordinates",
|
307
357
|
"bbox",
|
308
|
-
"
|
309
|
-
"map_width",
|
358
|
+
"map_size",
|
310
359
|
"rotation",
|
311
360
|
"minimum_x",
|
312
361
|
"minimum_y",
|
@@ -510,7 +559,7 @@ class Texture(Component):
|
|
510
559
|
cv2.imwrite(sublayer_path, sublayer)
|
511
560
|
self.logger.debug("Sublayer %s saved.", sublayer_path)
|
512
561
|
|
513
|
-
self.logger.
|
562
|
+
self.logger.debug("Dissolved layer %s.", layer.name)
|
514
563
|
|
515
564
|
def draw_base_layer(self, cumulative_image: np.ndarray) -> None:
|
516
565
|
"""Draws base layer and saves it into the png file.
|
@@ -596,7 +645,7 @@ class Texture(Component):
|
|
596
645
|
geometry_type = geometry.geom_type
|
597
646
|
converter = self._converters(geometry_type)
|
598
647
|
if not converter:
|
599
|
-
self.logger.
|
648
|
+
self.logger.debug("Geometry type %s not supported.", geometry_type)
|
600
649
|
return None
|
601
650
|
return converter(geometry, width)
|
602
651
|
|
@@ -667,7 +716,9 @@ class Texture(Component):
|
|
667
716
|
is_fieds = info_layer == "fields"
|
668
717
|
try:
|
669
718
|
if self.map.custom_osm is not None:
|
670
|
-
|
719
|
+
with warnings.catch_warnings():
|
720
|
+
warnings.simplefilter("ignore", FutureWarning)
|
721
|
+
objects = ox.features_from_xml(self.map.custom_osm, tags=tags)
|
671
722
|
else:
|
672
723
|
objects = ox.features_from_bbox(bbox=self.new_bbox, tags=tags)
|
673
724
|
except Exception as e: # pylint: disable=W0718
|
@@ -726,6 +777,8 @@ class Texture(Component):
|
|
726
777
|
|
727
778
|
if not isinstance(padded_polygon, shapely.geometry.polygon.Polygon):
|
728
779
|
self.logger.warning("The padding value is too high, field will not padded.")
|
780
|
+
elif not list(padded_polygon.exterior.coords):
|
781
|
+
self.logger.warning("The padding value is too high, field will not padded.")
|
729
782
|
else:
|
730
783
|
polygon = padded_polygon
|
731
784
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: maps4fs
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.6.91
|
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
|
@@ -48,6 +48,7 @@ Requires-Dist: pydantic
|
|
48
48
|
<a href="#Expert-settings">Expert settings</a> •
|
49
49
|
<a href="#Resources">Resources</a> •
|
50
50
|
<a href="#Bugs-and-feature-requests">Bugs and feature requests</a><br>
|
51
|
+
<a href="#DTM-Providers">DTM Providers</a> •
|
51
52
|
<a href="#Special-thanks">Special thanks</a>
|
52
53
|
</p>
|
53
54
|
|
@@ -69,12 +70,15 @@ Requires-Dist: pydantic
|
|
69
70
|
|
70
71
|
🗺️ Supports 2x2, 4x4, 8x8, 16x16 and any custom size maps<br>
|
71
72
|
🔄 Support map rotation 🆕<br>
|
73
|
+
🌐 Supports custom [DTM Providers](#DTM-Providers) 🆕<br>
|
72
74
|
🌾 Automatically generates fields 🆕<br>
|
73
75
|
🌽 Automatically generates farmlands 🆕<br>
|
74
76
|
🌿 Automatically generates decorative foliage 🆕<br>
|
75
77
|
🌲 Automatically generates forests 🆕<br>
|
76
78
|
🌊 Automatically generates water planes 🆕<br>
|
77
79
|
📈 Automatically generates splines 🆕<br>
|
80
|
+
🛰️ Automatically downloads high resolution satellite images 🆕<br>
|
81
|
+
🏔️ Allows to use multiple DTM providers for elevation models 🆕<br>
|
78
82
|
🌍 Based on real-world data from OpenStreetMap<br>
|
79
83
|
🗺️ Supports [custom OSM maps](/docs/custom_osm.md)<br>
|
80
84
|
🏞️ Generates height map using SRTM dataset<br>
|
@@ -127,6 +131,7 @@ docker run -d -p 8501:8501 --name maps4fs iwatkot/maps4fs
|
|
127
131
|
```
|
128
132
|
And open [http://localhost:8501](http://localhost:8501) in your browser.<br>
|
129
133
|
If you don't know how to use Docker, navigate to the [Docker version](#option-2-docker-version), it's really simple.<br>
|
134
|
+
Check out the [Docker FAQ](docs/FAQ_docker.md) if you have any questions.<br>
|
130
135
|
|
131
136
|
### 🤯 For developers
|
132
137
|
**Option 3:** Python package. Install the package using the following command:
|
@@ -181,6 +186,7 @@ Using it is easy and doesn't require any guides. Enjoy!
|
|
181
186
|
🗺️ Supported map sizes: 2x2, 4x4, 8x8, 16x16 km and any custom size.
|
182
187
|
⚙️ Advanced settings: enabled.
|
183
188
|
🖼️ Texture dissolving: enabled.
|
189
|
+
Check out the [Docker FAQ](docs/FAQ_docker.md) if you have any questions.<br>
|
184
190
|
You can launch the project with minimalistic UI in your browser using Docker. Follow these steps:
|
185
191
|
|
186
192
|
1. Install [Docker](https://docs.docker.com/get-docker/) for your OS.
|
@@ -249,6 +255,10 @@ The tool now has a Modder Toolbox, which is a set of tools to help you with vari
|
|
249
255
|
|
250
256
|
### Tool Categories
|
251
257
|
Tools are divided into categories, which are listed below.
|
258
|
+
|
259
|
+
#### For custom schemas
|
260
|
+
- **Tree Schema Editor** - allows you to view all the supported trees models and select the ones you need on your map. After it, 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 selected trees.
|
261
|
+
|
252
262
|
#### For Textures and DEM
|
253
263
|
- **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.
|
254
264
|
|
@@ -417,6 +427,7 @@ Let's have a closer look at the fields:
|
|
417
427
|
- `background` - set it to True for the textures, which should have impact on the Background Terrain, by default it's used to subtract the water depth from the DEM and background terrain.
|
418
428
|
- `info_layer` - if the layer is saving some data in JSON format, this section will describe it's name in the JSON file. Used to find the needed JSON data, for example for fields it will be `fields` and as a value - list of polygon coordinates.
|
419
429
|
- `invisible` - set it to True for the textures, which should not be drawn in the files, but only to save the data in the JSON file (related to the previous field).
|
430
|
+
- `procedural` - is a list of corresponding files, that will be used for a procedural generation. For example: `"procedural": ["PG_meadow", "PG_acres"]` - means that the texture will be used for two procedural generation files: `masks/PG_meadow.png` and `masks/PG_acres.png`. Note, that the one procuderal name can be applied to multiple textures, in this case they will be merged into one mask.
|
420
431
|
|
421
432
|
## Background terrain
|
422
433
|
The tool now supports the generation of the background terrain. If you don't know what it is, here's a brief explanation. The background terrain is the world around the map. It's important to create it because if you don't, the map will look like it's floating in the void. The background terrain is a simple plane that can (and should) be textured to look fine.<br>
|
@@ -463,19 +474,12 @@ List of the important DDS files:
|
|
463
474
|
- `mapsUS/overview.dds` - 4096x4096 pixels, the overview image of the map (in-game map)
|
464
475
|
|
465
476
|
## Advanced settings
|
466
|
-
The tool supports the custom size of the map. To use this feature select `Custom` in the `Map size` dropdown and enter the desired size. The tool will generate a map with the size you entered.<br>
|
467
|
-
|
468
|
-
⛔️ Do not use this feature, if you don't know what you're doing. In most cases, the Giants Editor will just crash on opening the file, because you need to enter specific values for the map size.<br><br>
|
469
477
|
|
470
|
-
|
471
|
-
|
472
|
-
You can also apply some advanced settings to the map generation process. Note that they're ADVANCED, so you don't need to use them if you're not sure what they do.<br>
|
478
|
+
You can also apply some advanced settings to the map generation process.<br>
|
473
479
|
|
474
480
|
### DEM Advanced settings
|
475
481
|
|
476
|
-
-
|
477
|
-
|
478
|
-
- Multiplier: the height of the map is multiplied by this value. So the DEM map is just a 16-bit grayscale image, which means that the maximum available value there is 65535, while the actual difference between the deepest and the highest point on Earth is about 20 km. Just note that this setting mostly does not matter, because you can always adjust it in the Giants Editor, learn more about the DEM file and the heightScale parameter in [docs](docs/dem.md). By default, it's set to 1.
|
482
|
+
- Multiplier: the height of the map is multiplied by this value. So the DEM map is just a 16-bit grayscale image, which means that the maximum available value there is 65535, while the actual difference between the deepest and the highest point on Earth is about 20 km. Just note that this setting mostly does not matter, because you can always adjust it in the Giants Editor, learn more about the DEM file and the heightScale parameter in [docs](docs/dem.md). To match the in-game heights with SRTM Data provider, the recommended value is 255 (if easy mode is disabled), but depending on the place, you will need to play with both multiplier and the height scale in Giants Editor to find the best values.
|
479
483
|
|
480
484
|
- Blur radius: the radius of the Gaussian blur filter applied to the DEM map. By default, it's set to 21. This filter just makes the DEM map smoother, so the height transitions will be more natural. You can set it to 1 to disable the filter, but it will result in a Minecraft-like map.
|
481
485
|
|
@@ -491,6 +495,15 @@ You can also apply some advanced settings to the map generation process. Note th
|
|
491
495
|
|
492
496
|
- Resize factor - the factor by which the background terrain will be resized. It will be used as 1 / resize_factor while generating the models. Which means that the larger the value the more the terrain will be resized. The lowest value is 1, in this case background terrain will not be resized. Note, than low values will lead to long processing and enormous size of the obj files.
|
493
497
|
|
498
|
+
- Remove center - if enabled, the playable region (map terrain) will be removed from the background terrain. Note, that it will require low resize factors, to avoid gaps between the map and the background terrain.
|
499
|
+
|
500
|
+
- Apply decimation - if enabled, the mesh will be simplified to reduce the number of faces.
|
501
|
+
|
502
|
+
- Decimation percent - the target percentage of decimation. The higher the value, the more simplified the mesh will be. Note, that high values will break the 3D model entirely.
|
503
|
+
|
504
|
+
- Decimation agression - the aggression of the decimation. The higher the value, the more aggressive the
|
505
|
+
decimation will be, which means the higher it will affect the geometry. It's not recommended to make it higher than the default value, otherwise the background terrain will not match the map terrain.
|
506
|
+
|
494
507
|
### GRLE Advanced settings
|
495
508
|
|
496
509
|
- Farmlands margin - this value (in meters) will be applied to each farmland, making it bigger. You can use the value to adjust how much the farmland should be bigger than the actual field. By default, it's set to 3.
|
@@ -499,6 +512,18 @@ You can also apply some advanced settings to the map generation process. Note th
|
|
499
512
|
|
500
513
|
- Add Farmyards - if enabled, the tool will create farmlands from the regions that are marked as farmyards in the OSM data. Those farmlands will not have fields and also will not be drawn on textures. By default, it's turned off.
|
501
514
|
|
515
|
+
- Base grass - you can select which plant will be used as a base grass on the map.
|
516
|
+
|
517
|
+
- Plants island minimum size - when random plants are enabled, the generator will add islands of differents plants to the map and choose the random size of those island between the minimum and maximum values. This one is the minimum size of the island in meters.
|
518
|
+
|
519
|
+
- Plants island maximum size - it's the same as above, but for the maximum size of the island in meters.
|
520
|
+
|
521
|
+
- Plants island vertex count - the number of vertices in the island. The higher the value, the more detailed the island will be. Note, that high values will turn the smoothed island into geometric madness.
|
522
|
+
|
523
|
+
- Plants insland rounding radius - used to round the vertices of the island. The higher the value, the more rounded the island will be.
|
524
|
+
|
525
|
+
- Plants island percent - defines the relation between the map size and the number of islands of plants. For example, if set to 100% for map size of 2048 will be added 2048 islands of plants.
|
526
|
+
|
502
527
|
### I3D Advanced settings
|
503
528
|
|
504
529
|
- Forest density - the density of the forest in meters. The lower the value, the lower the distance between the trees, which makes the forest denser. Note, that low values will lead to enormous number of trees, which may cause the Giants Editor to crash or lead to performance issues. By default, it's set to 10.
|
@@ -511,10 +536,16 @@ You can also apply some advanced settings to the map generation process. Note th
|
|
511
536
|
|
512
537
|
- Skip drains - if enabled, the tool will not generate the drains and ditches on the map. By default, it's set to False. Use this if you don't need the drains on the map.
|
513
538
|
|
514
|
-
|
539
|
+
### Splines Advanced settings
|
515
540
|
|
516
541
|
- Splines density - number of points, which will be added (interpolate) between each pair of existing points. The higher the value, the denser the spline will be. It can smooth the splines, but high values can in opposite make the splines look unnatural.
|
517
542
|
|
543
|
+
### Satellite Advanced settings
|
544
|
+
|
545
|
+
- Download images - if enabled, the tool will download the satellite images for the background terrain and the overview image. If you already have the images, you can turn it off.
|
546
|
+
- Satellite margin - the margin around the map in meters. It's useful when you want to have some space around the map on the satellite images. By default, it's set to 100.
|
547
|
+
- Zoom level - the zoom level of the satellite images. The higher the value, the more detailed the images will be. By default, it's set to 14 and this option is disabled on a public version of the app.
|
548
|
+
|
518
549
|
## Expert Settings
|
519
550
|
The tool also supports the expert settings. Do not use them until you read the documentation and understand what they do. Here's the list of the expert settings:
|
520
551
|
|
@@ -526,6 +557,8 @@ The tool also supports the expert settings. Do not use them until you read the d
|
|
526
557
|
|
527
558
|
- Show schemas - you'll be able to edit or define your own texture or tree schemas. It's useful if you want to add some custom textures or trees to the map. Refer to the [Texture schema](#texture-schema) section to learn more about the schema structure. Any incorrect value here will lead to the completely broken map.
|
528
559
|
|
560
|
+
- Upload custom background image - if you have an image, which represents the map and background terrain you can use it for generation. Note, that the image should meet the following requirements: 1:1 aspect ratio, size = map size + 2048 * 2, it should be uint16 (unsigned 16-bit integer) grayscale (single channel) image. The image should be in the PNG format. If any of the requirements are not met, the tool raises an error. If you're using rotation, the image should already be rotated.
|
561
|
+
|
529
562
|
## Resources
|
530
563
|
In this section, you'll find a list of the resources that you need to create a map for the Farming Simulator.<br>
|
531
564
|
To create a basic map, you only need the Giants Editor. But if you want to create a background terrain - the world around the map, so it won't look like it's floating in the void - you also need Blender and the Blender Exporter Plugins. To create realistic textures for the background terrain, the QGIS is required to obtain high-resolution satellite images.<br>
|
@@ -541,6 +574,15 @@ To create a basic map, you only need the Giants Editor. But if you want to creat
|
|
541
574
|
➡️ Please, before creating an issue or asking some questions, check the [FAQ](docs/FAQ.md) section.<br>
|
542
575
|
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) or on Discord: `iwatkot`.
|
543
576
|
|
577
|
+
## DTM Providers
|
578
|
+
|
579
|
+
The generator supports adding the own DTM providers, please refer to the [DTM Providers](docs/dtm_providers.md) section to learn how to add the custom DTM provider.
|
580
|
+
|
581
|
+
### Supported DTM providers
|
582
|
+
|
583
|
+
- [SRTM 30m](https://dwtkns.com/srtm30m/) - the 30 meters resolution DEM data from the SRTM mission for the whole world.
|
584
|
+
- [USGS 1m](https://portal.opentopography.org/raster?opentopoID=OTNED.012021.4269.3) - the 1-meter resolution DEM data from the USGS for the USA. Developed by [ZenJakey](https://github.com/ZenJakey).
|
585
|
+
|
544
586
|
## Special thanks
|
545
587
|
|
546
588
|
Of course, first of all, thanks to the direct [contributors](https://github.com/iwatkot/maps4fs/graphs/contributors) of the project.
|
@@ -555,3 +597,5 @@ But also, I want to thank the people who helped me with the project in some way,
|
|
555
597
|
- [Tox3](https://github.com/Tox3) - for the manual tests of the app.
|
556
598
|
- [Lucandia](https://github.com/Lucandia) - for the awesome StreamLit [widget to preview STL files](https://github.com/Lucandia/streamlit_stl).
|
557
599
|
- [H4rdB4se](https://github.com/H4rdB4se) - for investigating the issue with custom OSM files and finding a proper way to work with the files in JOSM.
|
600
|
+
- [kbrandwijk](https://github.com/kbrandwijk) - for providing [awesome tool](https://github.com/Paint-a-Farm/satmap_downloader) to download the satellite images from the Google Maps and giving a permission to modify it and create a Python Package.
|
601
|
+
- [Maaslandmods](https://github.com/Maaslandmods) - for the awesome idea to edit the tree schema in UI, images and code snippets on how to do it.
|
@@ -0,0 +1,27 @@
|
|
1
|
+
maps4fs/__init__.py,sha256=LrWSsyWaU28Dzcs7sRycywO_LvM-j34UvtafyBhvdx4,490
|
2
|
+
maps4fs/logger.py,sha256=B-NEYpMjPAAqlV4VpfTi6nbBFnEABVtQOaYe6nMpidg,1489
|
3
|
+
maps4fs/generator/__init__.py,sha256=zZMLEkGzb4z0xql650gOtGSvcgX58DnJ2yN3vC2daRk,43
|
4
|
+
maps4fs/generator/background.py,sha256=tV4UXvtkNN-OSvv6ujp4jFWRU1xGBgEvSakVGZ1H4nc,24877
|
5
|
+
maps4fs/generator/component.py,sha256=vn_ThQw3OTcloqYuJWC7vghAvIAnwJsybEm7qMwvsZk,21356
|
6
|
+
maps4fs/generator/config.py,sha256=0QmK052B8bxyHVhg3jzCORLfOBMMmqVfhhbqXKf6OMk,4383
|
7
|
+
maps4fs/generator/dem.py,sha256=20gx0dzX0LyO6ipvDitst-BwGfcKogFqgQf9Q2qMH5U,10933
|
8
|
+
maps4fs/generator/game.py,sha256=Nf5r2ubV4YVAVHGzJyhbF2GnOC0qV3HlHYIZBCWciHs,7992
|
9
|
+
maps4fs/generator/grle.py,sha256=hcbVBJ4j_Zr2QvEVo2cYNh2jARVXp_X3onifBtp9Zxs,20922
|
10
|
+
maps4fs/generator/i3d.py,sha256=pUyHKWKcw43xVCf3Y8iabtbQba05LYxMHi8vziGksIA,24843
|
11
|
+
maps4fs/generator/map.py,sha256=a50KQEr1XZKjS_WKXywGwh4OC3gyjY6M8FTc0eNcxpg,10183
|
12
|
+
maps4fs/generator/qgis.py,sha256=Es8hLuqN_KH8lDfnJE6He2rWYbAKJ3RGPn-o87S6CPI,6116
|
13
|
+
maps4fs/generator/satellite.py,sha256=_7RcuNmR1mjxEJWMDsjnzKUIqWxnGUn50XtjB7HmSPg,3661
|
14
|
+
maps4fs/generator/settings.py,sha256=3ASf3hW1nkGt8_3IOvKIKNUd6XAHYTAA8FquuhpSUlU,5668
|
15
|
+
maps4fs/generator/texture.py,sha256=gIXCHU1vT3evbkaXAV9gLUrgI1wH3xJLgWAtZgFruj0,34013
|
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
|
20
|
+
maps4fs/toolbox/__init__.py,sha256=zZMLEkGzb4z0xql650gOtGSvcgX58DnJ2yN3vC2daRk,43
|
21
|
+
maps4fs/toolbox/background.py,sha256=9BXWNqs_n3HgqDiPztWylgYk_QM4YgBpe6_ZNQAWtSc,2154
|
22
|
+
maps4fs/toolbox/dem.py,sha256=z9IPFNmYbjiigb3t02ZenI3Mo8odd19c5MZbjDEovTo,3525
|
23
|
+
maps4fs-1.6.91.dist-info/LICENSE.md,sha256=pTKD_oUexcn-yccFCTrMeLkZy0ifLRa-VNcDLqLZaIw,10749
|
24
|
+
maps4fs-1.6.91.dist-info/METADATA,sha256=1yIT5j9FOyB83FGk2lNExtLmEA3w-V1yeKiobQEbn40,39161
|
25
|
+
maps4fs-1.6.91.dist-info/WHEEL,sha256=A3WOREP4zgxI0fKrHUG8DC8013e3dK3n7a6HDbcEIwE,91
|
26
|
+
maps4fs-1.6.91.dist-info/top_level.txt,sha256=Ue9DSRlejRQRCaJueB0uLcKrWwsEq9zezfv5dI5mV1M,8
|
27
|
+
maps4fs-1.6.91.dist-info/RECORD,,
|
maps4fs-1.5.0.dist-info/RECORD
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
maps4fs/__init__.py,sha256=LMzzORK3Q3OjXmmRJ03CpS2SMP6zTwKNnUUei3P7s40,300
|
2
|
-
maps4fs/logger.py,sha256=B-NEYpMjPAAqlV4VpfTi6nbBFnEABVtQOaYe6nMpidg,1489
|
3
|
-
maps4fs/generator/__init__.py,sha256=zZMLEkGzb4z0xql650gOtGSvcgX58DnJ2yN3vC2daRk,43
|
4
|
-
maps4fs/generator/background.py,sha256=ySABP9HLji8R0aXi1BwjUQtP2uDqZPkrlmugowa9Gkk,22836
|
5
|
-
maps4fs/generator/component.py,sha256=58UQgdR-7KlWHTfwLesNNK76BTRsiVngRa6B64OKjhc,20065
|
6
|
-
maps4fs/generator/config.py,sha256=0QmK052B8bxyHVhg3jzCORLfOBMMmqVfhhbqXKf6OMk,4383
|
7
|
-
maps4fs/generator/dem.py,sha256=MZf3ZjawJ977TxqB1q9nNpvPZUNwfmm2EaJDtVU-eCU,15939
|
8
|
-
maps4fs/generator/game.py,sha256=jjo7CTwHHSkRpeD_QgRXkhR_NxI09C4kMxz-nYOTM4A,7931
|
9
|
-
maps4fs/generator/grle.py,sha256=u8ZwSs313PIOkH_0B_O2tVTaZ-eYNkc30eKGtBxWzTM,17846
|
10
|
-
maps4fs/generator/i3d.py,sha256=qeZYqfuhbhRPlSAuQHXaq6RmIO7314oMN68Ivebp1YQ,24786
|
11
|
-
maps4fs/generator/map.py,sha256=jIdekpiymhHqKx4FaAwjtq3hMnRdKYo6TvJLX1fSD0k,12814
|
12
|
-
maps4fs/generator/qgis.py,sha256=Es8hLuqN_KH8lDfnJE6He2rWYbAKJ3RGPn-o87S6CPI,6116
|
13
|
-
maps4fs/generator/texture.py,sha256=sErusfv1AqQfP-veMrZ921Tz8DnGEhfB4ucggMmKrD4,31231
|
14
|
-
maps4fs/toolbox/__init__.py,sha256=zZMLEkGzb4z0xql650gOtGSvcgX58DnJ2yN3vC2daRk,43
|
15
|
-
maps4fs/toolbox/background.py,sha256=9BXWNqs_n3HgqDiPztWylgYk_QM4YgBpe6_ZNQAWtSc,2154
|
16
|
-
maps4fs/toolbox/dem.py,sha256=z9IPFNmYbjiigb3t02ZenI3Mo8odd19c5MZbjDEovTo,3525
|
17
|
-
maps4fs-1.5.0.dist-info/LICENSE.md,sha256=pTKD_oUexcn-yccFCTrMeLkZy0ifLRa-VNcDLqLZaIw,10749
|
18
|
-
maps4fs-1.5.0.dist-info/METADATA,sha256=JZXcCZU91J0GD2q1YKooz_52UeA8DeCgbuv2zRrnTsQ,35026
|
19
|
-
maps4fs-1.5.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
20
|
-
maps4fs-1.5.0.dist-info/top_level.txt,sha256=Ue9DSRlejRQRCaJueB0uLcKrWwsEq9zezfv5dI5mV1M,8
|
21
|
-
maps4fs-1.5.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|