maps4fs 1.2.4__tar.gz → 1.4.1__tar.gz
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-1.2.4 → maps4fs-1.4.1}/PKG-INFO +36 -17
- {maps4fs-1.2.4 → maps4fs-1.4.1}/README.md +34 -16
- maps4fs-1.4.1/maps4fs/__init__.py +13 -0
- {maps4fs-1.2.4 → maps4fs-1.4.1}/maps4fs/generator/background.py +27 -29
- {maps4fs-1.2.4 → maps4fs-1.4.1}/maps4fs/generator/component.py +80 -24
- {maps4fs-1.2.4 → maps4fs-1.4.1}/maps4fs/generator/config.py +1 -1
- {maps4fs-1.2.4 → maps4fs-1.4.1}/maps4fs/generator/dem.py +11 -13
- {maps4fs-1.2.4 → maps4fs-1.4.1}/maps4fs/generator/game.py +1 -1
- {maps4fs-1.2.4 → maps4fs-1.4.1}/maps4fs/generator/grle.py +13 -14
- {maps4fs-1.2.4 → maps4fs-1.4.1}/maps4fs/generator/i3d.py +169 -35
- maps4fs-1.4.1/maps4fs/generator/map.py +337 -0
- {maps4fs-1.2.4 → maps4fs-1.4.1}/maps4fs/generator/texture.py +94 -32
- {maps4fs-1.2.4 → maps4fs-1.4.1}/maps4fs.egg-info/PKG-INFO +36 -17
- {maps4fs-1.2.4 → maps4fs-1.4.1}/maps4fs.egg-info/requires.txt +1 -0
- {maps4fs-1.2.4 → maps4fs-1.4.1}/pyproject.toml +2 -1
- {maps4fs-1.2.4 → maps4fs-1.4.1}/tests/test_generator.py +54 -57
- maps4fs-1.2.4/maps4fs/__init__.py +0 -4
- maps4fs-1.2.4/maps4fs/generator/map.py +0 -160
- {maps4fs-1.2.4 → maps4fs-1.4.1}/LICENSE.md +0 -0
- {maps4fs-1.2.4 → maps4fs-1.4.1}/maps4fs/generator/__init__.py +0 -0
- {maps4fs-1.2.4 → maps4fs-1.4.1}/maps4fs/generator/qgis.py +0 -0
- {maps4fs-1.2.4 → maps4fs-1.4.1}/maps4fs/logger.py +0 -0
- {maps4fs-1.2.4 → maps4fs-1.4.1}/maps4fs/toolbox/__init__.py +0 -0
- {maps4fs-1.2.4 → maps4fs-1.4.1}/maps4fs/toolbox/background.py +0 -0
- {maps4fs-1.2.4 → maps4fs-1.4.1}/maps4fs/toolbox/dem.py +0 -0
- {maps4fs-1.2.4 → maps4fs-1.4.1}/maps4fs.egg-info/SOURCES.txt +0 -0
- {maps4fs-1.2.4 → maps4fs-1.4.1}/maps4fs.egg-info/dependency_links.txt +0 -0
- {maps4fs-1.2.4 → maps4fs-1.4.1}/maps4fs.egg-info/top_level.txt +0 -0
- {maps4fs-1.2.4 → maps4fs-1.4.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: maps4fs
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.4.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
|
@@ -22,6 +22,7 @@ Requires-Dist: trimesh
|
|
22
22
|
Requires-Dist: imageio
|
23
23
|
Requires-Dist: tifffile
|
24
24
|
Requires-Dist: pympler
|
25
|
+
Requires-Dist: pydantic
|
25
26
|
|
26
27
|
<div align="center" markdown>
|
27
28
|
<a href="https://discord.gg/Sj5QKKyE42">
|
@@ -60,7 +61,8 @@ Requires-Dist: pympler
|
|
60
61
|
[](https://mypy-lang.org/)
|
61
62
|
[](https://github.com/iwatkot/maps4fs/actions)
|
62
63
|
[](https://codeclimate.com/github/iwatkot/maps4fs/test_coverage)
|
63
|
-
[](https://github.com/iwatkot/maps4fs/stargazers)
|
64
|
+
[](https://github.com/iwatkot/maps4fs/stargazers)<br>
|
65
|
+
[](https://github.com/iwatkot/maps4fs)
|
64
66
|
|
65
67
|
</div>
|
66
68
|
|
@@ -71,7 +73,9 @@ Requires-Dist: pympler
|
|
71
73
|
🌿 Automatically generates decorative foliage 🆕<br>
|
72
74
|
🌲 Automatically generates forests 🆕<br>
|
73
75
|
🌊 Automatically generates water planes 🆕<br>
|
76
|
+
📈 Automatically generates splines 🆕<br>
|
74
77
|
🌍 Based on real-world data from OpenStreetMap<br>
|
78
|
+
🗺️ Supports [custom OSM maps](/docs/custom_osm.md)<br>
|
75
79
|
🏞️ Generates height map using SRTM dataset<br>
|
76
80
|
📦 Provides a ready-to-use map template for the Giants Editor<br>
|
77
81
|
🚜 Supports Farming Simulator 22 and 25<br>
|
@@ -79,7 +83,6 @@ Requires-Dist: pympler
|
|
79
83
|
📄 Generates scripts to download high-resolution satellite images from [QGIS](https://qgis.org/download/) in one click<br>
|
80
84
|
📕 Detailed [documentation](/docs) and tutorials <br>
|
81
85
|
🧰 Modder Toolbox to help you with various tasks <br>
|
82
|
-
|
83
86
|
<p align="center">
|
84
87
|
<img src="https://github.com/user-attachments/assets/cf8f5752-9c69-4018-bead-290f59ba6976"><br>
|
85
88
|
🌎 Detailed terrain based on real-world data.<br><br>
|
@@ -93,6 +96,8 @@ Requires-Dist: pympler
|
|
93
96
|
🌲 Automatically generates forests.<br><br>
|
94
97
|
<img src="https://github.com/user-attachments/assets/cce7d4e0-cba2-4dd2-b22d-03137fb2e860"><br>
|
95
98
|
🌊 Automatically generates water planes.<br><br>
|
99
|
+
<img src="https://github.com/user-attachments/assets/0b05b511-a595-48e7-a353-8298081314a4"><br>
|
100
|
+
📈 Automatically generates splines.<br><br>
|
96
101
|
<img src="https://github.com/user-attachments/assets/80e5923c-22c7-4dc0-8906-680902511f3a"><br>
|
97
102
|
🗒️ True-to-life blueprints for fast and precise modding.<br><br>
|
98
103
|
<img width="480" src="https://github.com/user-attachments/assets/1a8802d2-6a3b-4bfa-af2b-7c09478e199b"><br>
|
@@ -110,14 +115,7 @@ Requires-Dist: pympler
|
|
110
115
|
## Quick Start
|
111
116
|
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>
|
112
117
|
### 🚜 For most users
|
113
|
-
**Option 1:** Open the [maps4fs](https://maps4fs.
|
114
|
-
<i>Note, that StreamLit community hosting has some limitations, such as: <br>
|
115
|
-
1. Maximum map size is 4096x4096 meters. <br>
|
116
|
-
2. Advanced settings are disabled. <br>
|
117
|
-
3. Texture dissolving is disabled (they will look worse). </i><br>
|
118
|
-
|
119
|
-
If you run the application locally, you won't have any of these limitations and will be able to generate maps of any size with any settings you want and nice looking textures.<br>
|
120
|
-
So, jump to [Docker version](#option-2-docker-version) to launch the tool with one command and get the full experience.<br>
|
118
|
+
**Option 1:** Open the [maps4fs](https://maps4fs.xyz) and generate a map template in a few clicks.<br>
|
121
119
|
|
122
120
|

|
123
121
|
|
@@ -165,13 +163,13 @@ Don't know where to start? Don't worry, just follow this [step-by-step guide](do
|
|
165
163
|
|
166
164
|
## How-To-Run
|
167
165
|
|
168
|
-
### Option 1:
|
169
|
-
🟢 Recommended for all users.
|
166
|
+
### Option 1: Public version
|
167
|
+
🟢 Recommended for all users.
|
170
168
|
🛠️ Don't need to install anything.
|
171
|
-
🗺️ Supported map sizes: 2x2, 4x4 km.
|
172
|
-
⚙️ Advanced settings:
|
173
|
-
🖼️ Texture dissolving:
|
174
|
-
Using the [
|
169
|
+
🗺️ Supported map sizes: 2x2, 4x4, 8x8 km.
|
170
|
+
⚙️ Advanced settings: enabled.
|
171
|
+
🖼️ Texture dissolving: enabled.
|
172
|
+
Using the public version on [maps4fs.xyz](https://maps4fs.xyz) is the easiest way to generate a map template. Just open the link and follow the instructions.
|
175
173
|
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>
|
176
174
|
|
177
175
|
Using it is easy and doesn't require any guides. Enjoy!
|
@@ -488,6 +486,10 @@ You can also apply some advanced settings to the map generation process. Note th
|
|
488
486
|
|
489
487
|
- Fields padding - this value (in meters) will be applied to each field, making it smaller. It's useful when the fields are too close to each other and you want to make them smaller. By default, it's set to 0.
|
490
488
|
|
489
|
+
- Texture dissolving - if enabled, the values from one layer will be splitted between different layers of texture, making it look more natural. By default, it's set to True. Can be turned of for faster processing.
|
490
|
+
|
491
|
+
- 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.
|
492
|
+
|
491
493
|
### Farmlands Advanced settings
|
492
494
|
|
493
495
|
- 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.
|
@@ -498,6 +500,18 @@ You can also apply some advanced settings to the map generation process. Note th
|
|
498
500
|
|
499
501
|
- Random plants - when adding decorative foliage, enabling this option will add different species of plants to the map. If unchecked only basic grass (smallDenseMix) will be added. Defaults to True.
|
500
502
|
|
503
|
+
### Background terrain Advanced settings
|
504
|
+
|
505
|
+
- Generate background - if enabled, the obj files for the background terrain will be generated. You can turn it off if you already have those files or don't need them. By default, it's set to True.
|
506
|
+
|
507
|
+
- Generate water - if enabled, the water planes obj files will be generated. You can turn it off if you already have those files or don't need them. By default, it's set to True.
|
508
|
+
|
509
|
+
- 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.
|
510
|
+
|
511
|
+
## Splines Advanced settings
|
512
|
+
|
513
|
+
- 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.
|
514
|
+
|
501
515
|
## Resources
|
502
516
|
In this section, you'll find a list of the resources that you need to create a map for the Farming Simulator.<br>
|
503
517
|
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>
|
@@ -522,3 +536,8 @@ But also, I want to thank the people who helped me with the project in some way,
|
|
522
536
|
- [Ka5tis](https://github.com/Ka5tis) - for investigating the issue with a "spiky terrain" and finding a solution - changing the `DisplacementLayer` size to a higher value.
|
523
537
|
- [Kalderone](https://www.youtube.com/@Kalderone_FS22) - for useful feedback, suggestions, expert advice on the map-making process and highlihting some important settings in the Giants Editor.
|
524
538
|
- [OneSunnySunday](https://www.artstation.com/onesunnysunday) - for expert advice on Blender, help in processing background terrain, and compiling detailed tutorials on how to prepare the OBJ files for use in Giants Editor.
|
539
|
+
- [BFernaesds](https://github.com/BFernaesds) - for the manual tests of the app.
|
540
|
+
- [gamerdesigns](https://github.com/gamerdesigns) - for the manual tests of the app.
|
541
|
+
- [Tox3](https://github.com/Tox3) - for the manual tests of the app.
|
542
|
+
- [Lucandia](https://github.com/Lucandia) - for the awesome StreamLit [widget to preview STL files](https://github.com/Lucandia/streamlit_stl).
|
543
|
+
- [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.
|
@@ -35,7 +35,8 @@
|
|
35
35
|
[](https://mypy-lang.org/)
|
36
36
|
[](https://github.com/iwatkot/maps4fs/actions)
|
37
37
|
[](https://codeclimate.com/github/iwatkot/maps4fs/test_coverage)
|
38
|
-
[](https://github.com/iwatkot/maps4fs/stargazers)
|
38
|
+
[](https://github.com/iwatkot/maps4fs/stargazers)<br>
|
39
|
+
[](https://github.com/iwatkot/maps4fs)
|
39
40
|
|
40
41
|
</div>
|
41
42
|
|
@@ -46,7 +47,9 @@
|
|
46
47
|
🌿 Automatically generates decorative foliage 🆕<br>
|
47
48
|
🌲 Automatically generates forests 🆕<br>
|
48
49
|
🌊 Automatically generates water planes 🆕<br>
|
50
|
+
📈 Automatically generates splines 🆕<br>
|
49
51
|
🌍 Based on real-world data from OpenStreetMap<br>
|
52
|
+
🗺️ Supports [custom OSM maps](/docs/custom_osm.md)<br>
|
50
53
|
🏞️ Generates height map using SRTM dataset<br>
|
51
54
|
📦 Provides a ready-to-use map template for the Giants Editor<br>
|
52
55
|
🚜 Supports Farming Simulator 22 and 25<br>
|
@@ -54,7 +57,6 @@
|
|
54
57
|
📄 Generates scripts to download high-resolution satellite images from [QGIS](https://qgis.org/download/) in one click<br>
|
55
58
|
📕 Detailed [documentation](/docs) and tutorials <br>
|
56
59
|
🧰 Modder Toolbox to help you with various tasks <br>
|
57
|
-
|
58
60
|
<p align="center">
|
59
61
|
<img src="https://github.com/user-attachments/assets/cf8f5752-9c69-4018-bead-290f59ba6976"><br>
|
60
62
|
🌎 Detailed terrain based on real-world data.<br><br>
|
@@ -68,6 +70,8 @@
|
|
68
70
|
🌲 Automatically generates forests.<br><br>
|
69
71
|
<img src="https://github.com/user-attachments/assets/cce7d4e0-cba2-4dd2-b22d-03137fb2e860"><br>
|
70
72
|
🌊 Automatically generates water planes.<br><br>
|
73
|
+
<img src="https://github.com/user-attachments/assets/0b05b511-a595-48e7-a353-8298081314a4"><br>
|
74
|
+
📈 Automatically generates splines.<br><br>
|
71
75
|
<img src="https://github.com/user-attachments/assets/80e5923c-22c7-4dc0-8906-680902511f3a"><br>
|
72
76
|
🗒️ True-to-life blueprints for fast and precise modding.<br><br>
|
73
77
|
<img width="480" src="https://github.com/user-attachments/assets/1a8802d2-6a3b-4bfa-af2b-7c09478e199b"><br>
|
@@ -85,14 +89,7 @@
|
|
85
89
|
## Quick Start
|
86
90
|
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>
|
87
91
|
### 🚜 For most users
|
88
|
-
**Option 1:** Open the [maps4fs](https://maps4fs.
|
89
|
-
<i>Note, that StreamLit community hosting has some limitations, such as: <br>
|
90
|
-
1. Maximum map size is 4096x4096 meters. <br>
|
91
|
-
2. Advanced settings are disabled. <br>
|
92
|
-
3. Texture dissolving is disabled (they will look worse). </i><br>
|
93
|
-
|
94
|
-
If you run the application locally, you won't have any of these limitations and will be able to generate maps of any size with any settings you want and nice looking textures.<br>
|
95
|
-
So, jump to [Docker version](#option-2-docker-version) to launch the tool with one command and get the full experience.<br>
|
92
|
+
**Option 1:** Open the [maps4fs](https://maps4fs.xyz) and generate a map template in a few clicks.<br>
|
96
93
|
|
97
94
|

|
98
95
|
|
@@ -140,13 +137,13 @@ Don't know where to start? Don't worry, just follow this [step-by-step guide](do
|
|
140
137
|
|
141
138
|
## How-To-Run
|
142
139
|
|
143
|
-
### Option 1:
|
144
|
-
🟢 Recommended for all users.
|
140
|
+
### Option 1: Public version
|
141
|
+
🟢 Recommended for all users.
|
145
142
|
🛠️ Don't need to install anything.
|
146
|
-
🗺️ Supported map sizes: 2x2, 4x4 km.
|
147
|
-
⚙️ Advanced settings:
|
148
|
-
🖼️ Texture dissolving:
|
149
|
-
Using the [
|
143
|
+
🗺️ Supported map sizes: 2x2, 4x4, 8x8 km.
|
144
|
+
⚙️ Advanced settings: enabled.
|
145
|
+
🖼️ Texture dissolving: enabled.
|
146
|
+
Using the public version on [maps4fs.xyz](https://maps4fs.xyz) is the easiest way to generate a map template. Just open the link and follow the instructions.
|
150
147
|
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>
|
151
148
|
|
152
149
|
Using it is easy and doesn't require any guides. Enjoy!
|
@@ -463,6 +460,10 @@ You can also apply some advanced settings to the map generation process. Note th
|
|
463
460
|
|
464
461
|
- Fields padding - this value (in meters) will be applied to each field, making it smaller. It's useful when the fields are too close to each other and you want to make them smaller. By default, it's set to 0.
|
465
462
|
|
463
|
+
- Texture dissolving - if enabled, the values from one layer will be splitted between different layers of texture, making it look more natural. By default, it's set to True. Can be turned of for faster processing.
|
464
|
+
|
465
|
+
- 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.
|
466
|
+
|
466
467
|
### Farmlands Advanced settings
|
467
468
|
|
468
469
|
- 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.
|
@@ -473,6 +474,18 @@ You can also apply some advanced settings to the map generation process. Note th
|
|
473
474
|
|
474
475
|
- Random plants - when adding decorative foliage, enabling this option will add different species of plants to the map. If unchecked only basic grass (smallDenseMix) will be added. Defaults to True.
|
475
476
|
|
477
|
+
### Background terrain Advanced settings
|
478
|
+
|
479
|
+
- Generate background - if enabled, the obj files for the background terrain will be generated. You can turn it off if you already have those files or don't need them. By default, it's set to True.
|
480
|
+
|
481
|
+
- Generate water - if enabled, the water planes obj files will be generated. You can turn it off if you already have those files or don't need them. By default, it's set to True.
|
482
|
+
|
483
|
+
- 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.
|
484
|
+
|
485
|
+
## Splines Advanced settings
|
486
|
+
|
487
|
+
- 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.
|
488
|
+
|
476
489
|
## Resources
|
477
490
|
In this section, you'll find a list of the resources that you need to create a map for the Farming Simulator.<br>
|
478
491
|
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>
|
@@ -497,3 +510,8 @@ But also, I want to thank the people who helped me with the project in some way,
|
|
497
510
|
- [Ka5tis](https://github.com/Ka5tis) - for investigating the issue with a "spiky terrain" and finding a solution - changing the `DisplacementLayer` size to a higher value.
|
498
511
|
- [Kalderone](https://www.youtube.com/@Kalderone_FS22) - for useful feedback, suggestions, expert advice on the map-making process and highlihting some important settings in the Giants Editor.
|
499
512
|
- [OneSunnySunday](https://www.artstation.com/onesunnysunday) - for expert advice on Blender, help in processing background terrain, and compiling detailed tutorials on how to prepare the OBJ files for use in Giants Editor.
|
513
|
+
- [BFernaesds](https://github.com/BFernaesds) - for the manual tests of the app.
|
514
|
+
- [gamerdesigns](https://github.com/gamerdesigns) - for the manual tests of the app.
|
515
|
+
- [Tox3](https://github.com/Tox3) - for the manual tests of the app.
|
516
|
+
- [Lucandia](https://github.com/Lucandia) - for the awesome StreamLit [widget to preview STL files](https://github.com/Lucandia/streamlit_stl).
|
517
|
+
- [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.
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# pylint: disable=missing-module-docstring
|
2
|
+
from maps4fs.generator.game import Game
|
3
|
+
from maps4fs.generator.map import (
|
4
|
+
BackgroundSettings,
|
5
|
+
DEMSettings,
|
6
|
+
GRLESettings,
|
7
|
+
I3DSettings,
|
8
|
+
Map,
|
9
|
+
SettingsModel,
|
10
|
+
SplineSettings,
|
11
|
+
TextureSettings,
|
12
|
+
)
|
13
|
+
from maps4fs.logger import Logger
|
@@ -13,16 +13,10 @@ import numpy as np
|
|
13
13
|
import trimesh # type: ignore
|
14
14
|
|
15
15
|
from maps4fs.generator.component import Component
|
16
|
-
from maps4fs.generator.dem import
|
17
|
-
DEFAULT_BLUR_RADIUS,
|
18
|
-
DEFAULT_MULTIPLIER,
|
19
|
-
DEFAULT_PLATEAU,
|
20
|
-
DEM,
|
21
|
-
)
|
16
|
+
from maps4fs.generator.dem import DEM
|
22
17
|
from maps4fs.generator.texture import Texture
|
23
18
|
|
24
19
|
DEFAULT_DISTANCE = 2048
|
25
|
-
RESIZE_FACTOR = 1 / 8
|
26
20
|
FULL_NAME = "FULL"
|
27
21
|
FULL_PREVIEW_NAME = "PREVIEW"
|
28
22
|
ELEMENTS = [FULL_NAME, FULL_PREVIEW_NAME]
|
@@ -46,8 +40,6 @@ class Background(Component):
|
|
46
40
|
# pylint: disable=R0801
|
47
41
|
def preprocess(self) -> None:
|
48
42
|
"""Registers the DEMs for the background terrain."""
|
49
|
-
self.light_version = self.kwargs.get("light_version", False)
|
50
|
-
self.water_depth = self.kwargs.get("water_depth", 0)
|
51
43
|
self.stl_preview_path: str | None = None
|
52
44
|
self.water_resources_path: str | None = None
|
53
45
|
|
@@ -65,11 +57,12 @@ class Background(Component):
|
|
65
57
|
os.makedirs(self.background_directory, exist_ok=True)
|
66
58
|
os.makedirs(self.water_directory, exist_ok=True)
|
67
59
|
|
68
|
-
autoprocesses = [self.
|
60
|
+
autoprocesses = [self.map.dem_settings.auto_process, False]
|
69
61
|
self.output_paths = [
|
70
62
|
os.path.join(self.background_directory, f"{name}.png") for name in ELEMENTS
|
71
63
|
]
|
72
64
|
self.not_substracted_path = os.path.join(self.background_directory, "not_substracted.png")
|
65
|
+
self.not_resized_path = os.path.join(self.background_directory, "not_resized.png")
|
73
66
|
|
74
67
|
dems = []
|
75
68
|
|
@@ -83,13 +76,12 @@ class Background(Component):
|
|
83
76
|
self.rotation,
|
84
77
|
self.map_directory,
|
85
78
|
self.logger,
|
86
|
-
auto_process=autoprocess,
|
87
|
-
blur_radius=self.kwargs.get("blur_radius", DEFAULT_BLUR_RADIUS),
|
88
|
-
multiplier=self.kwargs.get("multiplier", DEFAULT_MULTIPLIER),
|
89
|
-
plateau=self.kwargs.get("plateau", DEFAULT_PLATEAU),
|
90
79
|
)
|
91
80
|
dem.preprocess()
|
92
81
|
dem.is_preview = self.is_preview(name) # type: ignore
|
82
|
+
if dem.is_preview: # type: ignore
|
83
|
+
dem.multiplier = 1
|
84
|
+
dem.auto_process = autoprocess
|
93
85
|
dem.set_output_resolution((self.rotated_size, self.rotated_size))
|
94
86
|
dem.set_dem_path(output_path)
|
95
87
|
dems.append(dem)
|
@@ -117,8 +109,9 @@ class Background(Component):
|
|
117
109
|
dem.process()
|
118
110
|
if not dem.is_preview: # type: ignore
|
119
111
|
shutil.copyfile(dem.dem_path, self.not_substracted_path)
|
112
|
+
self.cutout(dem.dem_path, save_path=self.not_resized_path)
|
120
113
|
|
121
|
-
if self.water_depth:
|
114
|
+
if self.map.dem_settings.water_depth:
|
122
115
|
self.subtraction()
|
123
116
|
|
124
117
|
for dem in self.dems:
|
@@ -127,11 +120,10 @@ class Background(Component):
|
|
127
120
|
if self.game.additional_dem_name is not None:
|
128
121
|
self.make_copy(cutted_dem_path, self.game.additional_dem_name)
|
129
122
|
|
130
|
-
if
|
123
|
+
if self.map.background_settings.generate_background:
|
131
124
|
self.generate_obj_files()
|
125
|
+
if self.map.background_settings.generate_water:
|
132
126
|
self.generate_water_resources_obj()
|
133
|
-
else:
|
134
|
-
self.logger.info("Light version is enabled, obj files will not be generated.")
|
135
127
|
|
136
128
|
def make_copy(self, dem_path: str, dem_name: str) -> None:
|
137
129
|
"""Copies DEM data to additional DEM file.
|
@@ -145,7 +137,7 @@ class Background(Component):
|
|
145
137
|
additional_dem_path = os.path.join(dem_directory, dem_name)
|
146
138
|
|
147
139
|
shutil.copyfile(dem_path, additional_dem_path)
|
148
|
-
self.logger.
|
140
|
+
self.logger.debug("Additional DEM data was copied to %s.", additional_dem_path)
|
149
141
|
|
150
142
|
def info_sequence(self) -> dict[str, str | float | int]:
|
151
143
|
"""Returns a dictionary with information about the background terrain.
|
@@ -207,11 +199,12 @@ class Background(Component):
|
|
207
199
|
self.plane_from_np(dem_data, save_path, is_preview=dem.is_preview) # type: ignore
|
208
200
|
|
209
201
|
# pylint: disable=too-many-locals
|
210
|
-
def cutout(self, dem_path: str) -> str:
|
202
|
+
def cutout(self, dem_path: str, save_path: str | None = None) -> str:
|
211
203
|
"""Cuts out the center of the DEM (the actual map) and saves it as a separate file.
|
212
204
|
|
213
205
|
Arguments:
|
214
206
|
dem_path (str): The path to the DEM file.
|
207
|
+
save_path (str, optional): The path where the cutout DEM file will be saved.
|
215
208
|
|
216
209
|
Returns:
|
217
210
|
str -- The path to the cutout DEM file.
|
@@ -226,6 +219,11 @@ class Background(Component):
|
|
226
219
|
y2 = center[1] + half_size
|
227
220
|
dem_data = dem_data[x1:x2, y1:y2]
|
228
221
|
|
222
|
+
if save_path:
|
223
|
+
cv2.imwrite(save_path, dem_data) # pylint: disable=no-member
|
224
|
+
self.logger.debug("Not resized DEM saved: %s", save_path)
|
225
|
+
return save_path
|
226
|
+
|
229
227
|
output_size = self.map_size + 1
|
230
228
|
|
231
229
|
main_dem_path = self.game.dem_file_path(self.map_directory)
|
@@ -261,11 +259,12 @@ class Background(Component):
|
|
261
259
|
is_preview (bool, optional) -- If True, the preview mesh will be generated.
|
262
260
|
include_zeros (bool, optional) -- If True, the mesh will include the zero height values.
|
263
261
|
"""
|
262
|
+
resize_factor = 1 / self.map.background_settings.resize_factor
|
264
263
|
dem_data = cv2.resize( # pylint: disable=no-member
|
265
|
-
dem_data, (0, 0), fx=
|
264
|
+
dem_data, (0, 0), fx=resize_factor, fy=resize_factor
|
266
265
|
)
|
267
266
|
self.logger.debug(
|
268
|
-
"DEM data resized to shape: %s with factor: %s", dem_data.shape,
|
267
|
+
"DEM data resized to shape: %s with factor: %s", dem_data.shape, resize_factor
|
269
268
|
)
|
270
269
|
|
271
270
|
# Invert the height values.
|
@@ -325,13 +324,13 @@ class Background(Component):
|
|
325
324
|
self.mesh_to_stl(mesh)
|
326
325
|
else:
|
327
326
|
if not include_zeros:
|
328
|
-
multiplier = self.
|
327
|
+
multiplier = self.map.dem_settings.multiplier
|
329
328
|
if multiplier != 1:
|
330
329
|
z_scaling_factor = 1 / multiplier
|
331
330
|
else:
|
332
331
|
z_scaling_factor = 1 / 2**5
|
333
332
|
self.logger.debug("Z scaling factor: %s", z_scaling_factor)
|
334
|
-
mesh.apply_scale([1 /
|
333
|
+
mesh.apply_scale([1 / resize_factor, 1 / resize_factor, z_scaling_factor])
|
335
334
|
|
336
335
|
mesh.export(save_path)
|
337
336
|
self.logger.debug("Obj file saved: %s", save_path)
|
@@ -347,7 +346,7 @@ class Background(Component):
|
|
347
346
|
preview_path = os.path.join(self.previews_directory, "background_dem.stl")
|
348
347
|
mesh.export(preview_path)
|
349
348
|
|
350
|
-
self.logger.
|
349
|
+
self.logger.debug("STL file saved: %s", preview_path)
|
351
350
|
|
352
351
|
self.stl_preview_path = preview_path # pylint: disable=attribute-defined-outside-init
|
353
352
|
|
@@ -485,8 +484,7 @@ class Background(Component):
|
|
485
484
|
rotation=self.rotation,
|
486
485
|
map_directory=self.map_directory,
|
487
486
|
logger=self.logger,
|
488
|
-
|
489
|
-
custom_schema=background_layers,
|
487
|
+
texture_custom_schema=background_layers, # type: ignore
|
490
488
|
)
|
491
489
|
|
492
490
|
self.background_texture.preprocess()
|
@@ -509,7 +507,7 @@ class Background(Component):
|
|
509
507
|
|
510
508
|
background_save_path = os.path.join(self.water_directory, "water_resources.png")
|
511
509
|
cv2.imwrite(background_save_path, background_image)
|
512
|
-
self.logger.
|
510
|
+
self.logger.debug("Background texture saved: %s", background_save_path)
|
513
511
|
self.water_resources_path = background_save_path # pylint: disable=W0201
|
514
512
|
|
515
513
|
def subtraction(self) -> None:
|
@@ -534,7 +532,7 @@ class Background(Component):
|
|
534
532
|
|
535
533
|
# Create a mask where water_resources_image is 255 (or not 0)
|
536
534
|
# Subtract water_depth from dem_image where mask is True
|
537
|
-
dem_image[mask] = dem_image[mask] - self.water_depth
|
535
|
+
dem_image[mask] = dem_image[mask] - self.map.dem_settings.water_depth
|
538
536
|
|
539
537
|
# Save the modified dem_image back to the output path
|
540
538
|
cv2.imwrite(output_path, dem_image)
|
@@ -7,11 +7,11 @@ import os
|
|
7
7
|
from copy import deepcopy
|
8
8
|
from typing import TYPE_CHECKING, Any
|
9
9
|
|
10
|
-
import cv2
|
10
|
+
import cv2 # type: ignore
|
11
11
|
import osmnx as ox # type: ignore
|
12
12
|
from pyproj import Transformer
|
13
13
|
from shapely.affinity import rotate, translate # type: ignore
|
14
|
-
from shapely.geometry import Polygon, box # type: ignore
|
14
|
+
from shapely.geometry import LineString, Polygon, box # type: ignore
|
15
15
|
|
16
16
|
from maps4fs.generator.qgis import save_scripts
|
17
17
|
|
@@ -20,7 +20,7 @@ if TYPE_CHECKING:
|
|
20
20
|
from maps4fs.generator.map import Map
|
21
21
|
|
22
22
|
|
23
|
-
# pylint: disable=R0801, R0903, R0902, R0904
|
23
|
+
# pylint: disable=R0801, R0903, R0902, R0904, R0913, R0917
|
24
24
|
class Component:
|
25
25
|
"""Base class for all map generation components.
|
26
26
|
|
@@ -46,7 +46,7 @@ class Component:
|
|
46
46
|
rotation: int,
|
47
47
|
map_directory: str,
|
48
48
|
logger: Any = None,
|
49
|
-
**kwargs
|
49
|
+
**kwargs: dict[str, Any],
|
50
50
|
):
|
51
51
|
self.game = game
|
52
52
|
self.map = map
|
@@ -58,6 +58,13 @@ class Component:
|
|
58
58
|
self.logger = logger
|
59
59
|
self.kwargs = kwargs
|
60
60
|
|
61
|
+
self.logger.info(
|
62
|
+
"Component %s initialized. Map size: %s, map rotated size: %s", # type: ignore
|
63
|
+
self.__class__.__name__,
|
64
|
+
self.map_size,
|
65
|
+
self.map_rotated_size,
|
66
|
+
)
|
67
|
+
|
61
68
|
os.makedirs(self.previews_directory, exist_ok=True)
|
62
69
|
os.makedirs(self.scripts_directory, exist_ok=True)
|
63
70
|
os.makedirs(self.info_layers_directory, exist_ok=True)
|
@@ -331,62 +338,79 @@ class Component:
|
|
331
338
|
return cs_x, cs_y
|
332
339
|
|
333
340
|
# pylint: disable=R0914
|
334
|
-
def
|
335
|
-
self,
|
341
|
+
def fit_object_into_bounds(
|
342
|
+
self,
|
343
|
+
polygon_points: list[tuple[int, int]] | None = None,
|
344
|
+
linestring_points: list[tuple[int, int]] | None = None,
|
345
|
+
margin: int = 0,
|
346
|
+
angle: int = 0,
|
336
347
|
) -> list[tuple[int, int]]:
|
337
348
|
"""Fits a polygon into the bounds of the map.
|
338
349
|
|
339
350
|
Arguments:
|
340
351
|
polygon_points (list[tuple[int, int]]): The points of the polygon.
|
352
|
+
linestring_points (list[tuple[int, int]]): The points of the linestring.
|
341
353
|
margin (int, optional): The margin to add to the polygon. Defaults to 0.
|
342
354
|
angle (int, optional): The angle to rotate the polygon by. Defaults to 0.
|
343
355
|
|
344
356
|
Returns:
|
345
357
|
list[tuple[int, int]]: The points of the polygon fitted into the map bounds.
|
346
358
|
"""
|
359
|
+
if polygon_points is None and linestring_points is None:
|
360
|
+
raise ValueError("Either polygon or linestring points must be provided.")
|
361
|
+
|
347
362
|
min_x = min_y = 0
|
348
363
|
max_x = max_y = self.map_size
|
349
364
|
|
350
|
-
|
365
|
+
object_type = Polygon if polygon_points else LineString
|
366
|
+
|
367
|
+
# polygon = Polygon(polygon_points)
|
368
|
+
osm_object = object_type(polygon_points or linestring_points)
|
351
369
|
|
352
370
|
if angle:
|
353
371
|
center_x = center_y = self.map_rotated_size // 2
|
354
372
|
self.logger.debug(
|
355
|
-
"Rotating the
|
373
|
+
"Rotating the osm_object by %s degrees with center at %sx%s",
|
356
374
|
angle,
|
357
375
|
center_x,
|
358
376
|
center_y,
|
359
377
|
)
|
360
|
-
|
378
|
+
osm_object = rotate(osm_object, -angle, origin=(center_x, center_y))
|
361
379
|
offset = (self.map_size / 2) - (self.map_rotated_size / 2)
|
362
|
-
self.logger.debug("Translating the
|
363
|
-
|
364
|
-
self.logger.debug("Rotated and translated
|
380
|
+
self.logger.debug("Translating the osm_object by %s", offset)
|
381
|
+
osm_object = translate(osm_object, xoff=offset, yoff=offset)
|
382
|
+
self.logger.debug("Rotated and translated the osm_object.")
|
365
383
|
|
366
|
-
if margin:
|
367
|
-
|
368
|
-
if
|
369
|
-
raise ValueError("The
|
384
|
+
if margin and object_type is Polygon:
|
385
|
+
osm_object = osm_object.buffer(margin, join_style="mitre")
|
386
|
+
if osm_object.is_empty:
|
387
|
+
raise ValueError("The osm_object is empty after adding the margin.")
|
370
388
|
|
371
389
|
# Create a bounding box for the map bounds
|
372
390
|
bounds = box(min_x, min_y, max_x, max_y)
|
373
391
|
|
374
|
-
# Intersect the
|
392
|
+
# Intersect the osm_object with the bounds to fit it within the map
|
375
393
|
try:
|
376
|
-
|
377
|
-
self.logger.debug("Fitted the
|
394
|
+
fitted_osm_object = osm_object.intersection(bounds)
|
395
|
+
self.logger.debug("Fitted the osm_object into the bounds: %s", bounds)
|
378
396
|
except Exception as e:
|
379
397
|
raise ValueError( # pylint: disable=W0707
|
380
|
-
f"Could not fit the
|
398
|
+
f"Could not fit the osm_object into the bounds: {e}"
|
381
399
|
)
|
382
400
|
|
383
|
-
if not isinstance(
|
384
|
-
raise ValueError("The fitted
|
401
|
+
if not isinstance(fitted_osm_object, object_type):
|
402
|
+
raise ValueError("The fitted osm_object is not valid (probably splitted into parts).")
|
385
403
|
|
386
404
|
# Return the fitted polygon points
|
387
|
-
|
405
|
+
if object_type is Polygon:
|
406
|
+
as_list = list(fitted_osm_object.exterior.coords)
|
407
|
+
elif object_type is LineString:
|
408
|
+
as_list = list(fitted_osm_object.coords)
|
409
|
+
else:
|
410
|
+
raise ValueError("The object type is not supported.")
|
411
|
+
|
388
412
|
if not as_list:
|
389
|
-
raise ValueError("The fitted
|
413
|
+
raise ValueError("The fitted osm_object has no points.")
|
390
414
|
return as_list
|
391
415
|
|
392
416
|
def get_infolayer_path(self, layer_name: str) -> str | None:
|
@@ -469,3 +493,35 @@ class Component:
|
|
469
493
|
self.logger.debug("Shape of the cropped image: %s", cropped.shape)
|
470
494
|
|
471
495
|
cv2.imwrite(output_path, cropped)
|
496
|
+
|
497
|
+
@staticmethod
|
498
|
+
def interpolate_points(
|
499
|
+
polyline: list[tuple[int, int]], num_points: int = 4
|
500
|
+
) -> list[tuple[int, int]]:
|
501
|
+
"""Receives a list of tuples, which represents a polyline. Add additional points
|
502
|
+
between the existing points to make the polyline smoother.
|
503
|
+
|
504
|
+
Arguments:
|
505
|
+
polyline (list[tuple[int, int]]): The list of points to interpolate.
|
506
|
+
num_points (int): The number of additional points to add between each pair of points.
|
507
|
+
|
508
|
+
Returns:
|
509
|
+
list[tuple[int, int]]: The list of points with additional points.
|
510
|
+
"""
|
511
|
+
if not polyline or num_points < 1:
|
512
|
+
return polyline
|
513
|
+
|
514
|
+
interpolated_polyline = []
|
515
|
+
for i in range(len(polyline) - 1):
|
516
|
+
p1 = polyline[i]
|
517
|
+
p2 = polyline[i + 1]
|
518
|
+
interpolated_polyline.append(p1)
|
519
|
+
for j in range(1, num_points + 1):
|
520
|
+
new_point = (
|
521
|
+
p1[0] + (p2[0] - p1[0]) * j / (num_points + 1),
|
522
|
+
p1[1] + (p2[1] - p1[1]) * j / (num_points + 1),
|
523
|
+
)
|
524
|
+
interpolated_polyline.append((int(new_point[0]), int(new_point[1])))
|
525
|
+
interpolated_polyline.append(polyline[-1])
|
526
|
+
|
527
|
+
return interpolated_polyline
|
@@ -38,7 +38,7 @@ class Config(Component):
|
|
38
38
|
self.logger.warning("Map XML file not found: %s.", self._map_xml_path)
|
39
39
|
return
|
40
40
|
tree = ET.parse(self._map_xml_path)
|
41
|
-
self.logger.
|
41
|
+
self.logger.debug("Map XML file loaded from: %s.", self._map_xml_path)
|
42
42
|
root = tree.getroot()
|
43
43
|
for map_elem in root.iter("map"):
|
44
44
|
map_elem.set("width", str(self.map_size))
|