maps4fs 0.9.98__tar.gz → 1.0.3__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-0.9.98 → maps4fs-1.0.3}/PKG-INFO +38 -9
- {maps4fs-0.9.98 → maps4fs-1.0.3}/README.md +36 -7
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs/generator/background.py +16 -115
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs/generator/component.py +12 -2
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs/generator/config.py +1 -1
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs/generator/dem.py +13 -12
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs/generator/game.py +2 -1
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs/generator/grle.py +1 -1
- maps4fs-1.0.3/maps4fs/generator/i3d.py +358 -0
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs/generator/map.py +3 -3
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs/generator/texture.py +39 -10
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs/generator/tile.py +3 -3
- maps4fs-1.0.3/maps4fs/toolbox/background.py +63 -0
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs.egg-info/PKG-INFO +38 -9
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs.egg-info/SOURCES.txt +1 -0
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs.egg-info/requires.txt +1 -1
- {maps4fs-0.9.98 → maps4fs-1.0.3}/pyproject.toml +2 -2
- maps4fs-0.9.98/maps4fs/generator/i3d.py +0 -89
- {maps4fs-0.9.98 → maps4fs-1.0.3}/LICENSE.md +0 -0
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs/__init__.py +0 -0
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs/generator/__init__.py +0 -0
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs/generator/path_steps.py +0 -0
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs/generator/qgis.py +0 -0
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs/logger.py +0 -0
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs/toolbox/__init__.py +0 -0
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs/toolbox/dem.py +0 -0
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs.egg-info/dependency_links.txt +0 -0
- {maps4fs-0.9.98 → maps4fs-1.0.3}/maps4fs.egg-info/top_level.txt +0 -0
- {maps4fs-0.9.98 → maps4fs-1.0.3}/setup.cfg +0 -0
- {maps4fs-0.9.98 → maps4fs-1.0.3}/tests/test_generator.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: maps4fs
|
3
|
-
Version: 0.
|
3
|
+
Version: 1.0.3
|
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
|
@@ -14,7 +14,7 @@ Classifier: Operating System :: OS Independent
|
|
14
14
|
Description-Content-Type: text/markdown
|
15
15
|
License-File: LICENSE.md
|
16
16
|
Requires-Dist: opencv-python
|
17
|
-
Requires-Dist: osmnx
|
17
|
+
Requires-Dist: osmnx>=2.0.0
|
18
18
|
Requires-Dist: rasterio
|
19
19
|
Requires-Dist: folium
|
20
20
|
Requires-Dist: geopy
|
@@ -31,8 +31,10 @@ Requires-Dist: pympler
|
|
31
31
|
<p align="center">
|
32
32
|
<a href="#Quick-Start">Quick Start</a> •
|
33
33
|
<a href="#Overview">Overview</a> •
|
34
|
-
<a href="#
|
34
|
+
<a href="#Step-by-step">Create a map in 10 steps</a> •
|
35
|
+
<a href="#How-To-Run">How-To-Run</a><br>
|
35
36
|
<a href="docs/FAQ.md">FAQ</a> •
|
37
|
+
<a href="docs/map_structure.md">Map Structure</a> •
|
36
38
|
<a href="#Modder-Toolbox">Modder Toolbox</a><br>
|
37
39
|
<a href="#Supported-objects">Supported objects</a> •
|
38
40
|
<a href="#Generation-info">Generation info</a> •
|
@@ -68,6 +70,7 @@ Requires-Dist: pympler
|
|
68
70
|
🔷 Generates *.obj files for background terrain based on the real-world height map<br>
|
69
71
|
📄 Generates scripts to download high-resolution satellite images from [QGIS](https://qgis.org/download/) in one click<br>
|
70
72
|
🧰 Modder Toolbox to help you with various of tasks 🆕<br>
|
73
|
+
🌾 Automatically generates fields 🆕<br>
|
71
74
|
|
72
75
|
<p align="center">
|
73
76
|
<img src="https://github.com/user-attachments/assets/cf8f5752-9c69-4018-bead-290f59ba6976"><br>
|
@@ -76,6 +79,8 @@ Requires-Dist: pympler
|
|
76
79
|
🛰️ Realistic background terrain objects with satellite images.<br><br>
|
77
80
|
<img src="https://github.com/user-attachments/assets/80e5923c-22c7-4dc0-8906-680902511f3a"><br>
|
78
81
|
🗒️ True-to-life blueprints for fast and precise modding.<br><br>
|
82
|
+
<img width="480" src="https://github.com/user-attachments/assets/1a8802d2-6a3b-4bfa-af2b-7c09478e199b"><br>
|
83
|
+
🌾 Field generation with one click.<br><br>
|
79
84
|
<img src="https://github.com/user-attachments/assets/cce45575-c917-4a1b-bdc0-6368e32ccdff"><br>
|
80
85
|
📏 Almost any possible map sizes.
|
81
86
|
</p>
|
@@ -84,6 +89,13 @@ Requires-Dist: pympler
|
|
84
89
|
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>
|
85
90
|
### 🚜 For most users
|
86
91
|
**Option 1:** open the [maps4fs](https://maps4fs.streamlit.app) on StreamLit and generate a map template in a few clicks.<br>
|
92
|
+
<i>Note, that StreamLit community hosting has some limitations, such as: <br>
|
93
|
+
1. Maximum map size is 4096x4096 meters. <br>
|
94
|
+
2. Advanced settings are disabled. <br>
|
95
|
+
3. Texure dissolving is disabled (they will look worse). </i><br>
|
96
|
+
|
97
|
+
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>
|
98
|
+
So, jump to [Docker version](#option-2-docker-version) to launch the tool with one command and get the full experience.<br>
|
87
99
|
|
88
100
|

|
89
101
|
|
@@ -126,6 +138,9 @@ Parameters:
|
|
126
138
|
- coordinates: 45.15, 19.71
|
127
139
|
- size: 16 x 16 km
|
128
140
|
|
141
|
+
## Step by step
|
142
|
+
Don't know where to start? Don't worry, just follow this [step-by-step guide](docs/step_by_step.md) to create your first map in 10 simple steps.<br>
|
143
|
+
|
129
144
|
## How-To-Run
|
130
145
|
|
131
146
|
You'll find detailed instructions on how to run the project below. But if you prefer video tutorials, here's one for you:
|
@@ -133,14 +148,22 @@ You'll find detailed instructions on how to run the project below. But if you pr
|
|
133
148
|
<i>Video tutorial: How to generate a Farming Simulator 22 map from real-world data.</i>
|
134
149
|
|
135
150
|
### Option 1: StreamLit
|
136
|
-
🟢 Recommended for all users
|
151
|
+
🟢 Recommended for all users.
|
152
|
+
🛠️ Don't need to install anything.
|
153
|
+
🗺️ Supported map sizes: 2x2, 4x4 km.
|
154
|
+
⚙️ Advanced settings: disabled.
|
155
|
+
🖼️ Texture dissolving: disabled.
|
137
156
|
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.
|
138
157
|
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>
|
139
158
|
|
140
159
|
Using it is easy and doesn't require any guides. Enjoy!
|
141
160
|
|
142
161
|
### Option 2: Docker version
|
143
|
-
🟠 Recommended for users who want
|
162
|
+
🟠 Recommended for users who want bigger maps, fast generation, nice looking textures and advanced settings.
|
163
|
+
🛠️ Launch with one single command.
|
164
|
+
🗺️ Supported map sizes: 2x2, 4x4, 8x8, 16x16 km and any custom size.
|
165
|
+
⚙️ Advanced settings: enabled.
|
166
|
+
🖼️ Texture dissolving: enabled.
|
144
167
|
You can launch the project with minimalistic UI in your browser using Docker. Follow these steps:
|
145
168
|
|
146
169
|
1. Install [Docker](https://docs.docker.com/get-docker/) for your OS.
|
@@ -153,7 +176,10 @@ docker run -d -p 8501:8501 iwatkot/maps4fs
|
|
153
176
|
5. When the map is generated click on the `Download` button to get the map.
|
154
177
|
|
155
178
|
### Option 3: Python package
|
156
|
-
🔴 Recommended for developers
|
179
|
+
🔴 Recommended for developers.
|
180
|
+
🗺️ Supported map sizes: 2x2, 4x4, 8x8, 16x16 km and any custom size.
|
181
|
+
⚙️ Advanced settings: enabled.
|
182
|
+
🖼️ Texture dissolving: enabled.
|
157
183
|
You can use the Python package to generate maps. Follow these steps:
|
158
184
|
|
159
185
|
1. Install the package from PyPI:
|
@@ -202,12 +228,15 @@ The map will be saved in the `map_directory` directory.
|
|
202
228
|
## Modder Toolbox
|
203
229
|
The tool now has a Modder Toolbox, which is a set of tools to help you with various tasks. You can open the toolbox by switching to the `🧰 Modder Toolbox` tab in the StreamLit app.<br>
|
204
230
|
|
205
|
-

|
206
232
|
|
207
233
|
### Tool categories
|
208
234
|
Tools are divided into categories, which are listed below.
|
209
235
|
#### Textures and DEM
|
210
|
-
- **GeoTIFF windowing** - allows you to upload your GeoTIFF file and select the region of interest to extract it from the image.
|
236
|
+
- **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 the height map using it.
|
237
|
+
|
238
|
+
#### Background terrain
|
239
|
+
- **Convert image to obj model** - allows you to convert the image to the obj model. You can use this tool to create the background terrain for your map. It can be extremely useful if you have access to the sources of high-resolution DEM data and want to create the background terrain using it.
|
211
240
|
|
212
241
|
## Supported objects
|
213
242
|
The project is based on the [OpenStreetMap](https://www.openstreetmap.org/) data. So, refer to [this page](https://wiki.openstreetmap.org/wiki/Map_Features) to understand the list below.
|
@@ -376,7 +405,7 @@ Let's have a closer look at the fields:
|
|
376
405
|
|
377
406
|
## Background terrain
|
378
407
|
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 which can (and should) be texture to look fine.<br>
|
379
|
-
So, the tool generates the background terrain in the form of the 8 tiles, which surround the map. The tiles are named as the cardinal points, e.g. "N", "NE", "E" and so on. All those tiles will be saved in the `
|
408
|
+
So, the tool generates the background terrain in the form of the 8 tiles, which surround the map. The tiles are named as the cardinal points, e.g. "N", "NE", "E" and so on. All those tiles will be saved in the `background` directory with corresponding names: `N.obj`, `NE.obj`, `E.obj` and so on.<br>
|
380
409
|
If you don't want to work with separate tiles, the tool also generates the `FULL.obj` file, which includes everything around the map and the map itself. It may be a convinient approach to work with one file, one texture and then just cut the map from it.<br>
|
381
410
|
|
382
411
|

|
@@ -6,8 +6,10 @@
|
|
6
6
|
<p align="center">
|
7
7
|
<a href="#Quick-Start">Quick Start</a> •
|
8
8
|
<a href="#Overview">Overview</a> •
|
9
|
-
<a href="#
|
9
|
+
<a href="#Step-by-step">Create a map in 10 steps</a> •
|
10
|
+
<a href="#How-To-Run">How-To-Run</a><br>
|
10
11
|
<a href="docs/FAQ.md">FAQ</a> •
|
12
|
+
<a href="docs/map_structure.md">Map Structure</a> •
|
11
13
|
<a href="#Modder-Toolbox">Modder Toolbox</a><br>
|
12
14
|
<a href="#Supported-objects">Supported objects</a> •
|
13
15
|
<a href="#Generation-info">Generation info</a> •
|
@@ -43,6 +45,7 @@
|
|
43
45
|
🔷 Generates *.obj files for background terrain based on the real-world height map<br>
|
44
46
|
📄 Generates scripts to download high-resolution satellite images from [QGIS](https://qgis.org/download/) in one click<br>
|
45
47
|
🧰 Modder Toolbox to help you with various of tasks 🆕<br>
|
48
|
+
🌾 Automatically generates fields 🆕<br>
|
46
49
|
|
47
50
|
<p align="center">
|
48
51
|
<img src="https://github.com/user-attachments/assets/cf8f5752-9c69-4018-bead-290f59ba6976"><br>
|
@@ -51,6 +54,8 @@
|
|
51
54
|
🛰️ Realistic background terrain objects with satellite images.<br><br>
|
52
55
|
<img src="https://github.com/user-attachments/assets/80e5923c-22c7-4dc0-8906-680902511f3a"><br>
|
53
56
|
🗒️ True-to-life blueprints for fast and precise modding.<br><br>
|
57
|
+
<img width="480" src="https://github.com/user-attachments/assets/1a8802d2-6a3b-4bfa-af2b-7c09478e199b"><br>
|
58
|
+
🌾 Field generation with one click.<br><br>
|
54
59
|
<img src="https://github.com/user-attachments/assets/cce45575-c917-4a1b-bdc0-6368e32ccdff"><br>
|
55
60
|
📏 Almost any possible map sizes.
|
56
61
|
</p>
|
@@ -59,6 +64,13 @@
|
|
59
64
|
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>
|
60
65
|
### 🚜 For most users
|
61
66
|
**Option 1:** open the [maps4fs](https://maps4fs.streamlit.app) on StreamLit and generate a map template in a few clicks.<br>
|
67
|
+
<i>Note, that StreamLit community hosting has some limitations, such as: <br>
|
68
|
+
1. Maximum map size is 4096x4096 meters. <br>
|
69
|
+
2. Advanced settings are disabled. <br>
|
70
|
+
3. Texure dissolving is disabled (they will look worse). </i><br>
|
71
|
+
|
72
|
+
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>
|
73
|
+
So, jump to [Docker version](#option-2-docker-version) to launch the tool with one command and get the full experience.<br>
|
62
74
|
|
63
75
|

|
64
76
|
|
@@ -101,6 +113,9 @@ Parameters:
|
|
101
113
|
- coordinates: 45.15, 19.71
|
102
114
|
- size: 16 x 16 km
|
103
115
|
|
116
|
+
## Step by step
|
117
|
+
Don't know where to start? Don't worry, just follow this [step-by-step guide](docs/step_by_step.md) to create your first map in 10 simple steps.<br>
|
118
|
+
|
104
119
|
## How-To-Run
|
105
120
|
|
106
121
|
You'll find detailed instructions on how to run the project below. But if you prefer video tutorials, here's one for you:
|
@@ -108,14 +123,22 @@ You'll find detailed instructions on how to run the project below. But if you pr
|
|
108
123
|
<i>Video tutorial: How to generate a Farming Simulator 22 map from real-world data.</i>
|
109
124
|
|
110
125
|
### Option 1: StreamLit
|
111
|
-
🟢 Recommended for all users
|
126
|
+
🟢 Recommended for all users.
|
127
|
+
🛠️ Don't need to install anything.
|
128
|
+
🗺️ Supported map sizes: 2x2, 4x4 km.
|
129
|
+
⚙️ Advanced settings: disabled.
|
130
|
+
🖼️ Texture dissolving: disabled.
|
112
131
|
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.
|
113
132
|
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>
|
114
133
|
|
115
134
|
Using it is easy and doesn't require any guides. Enjoy!
|
116
135
|
|
117
136
|
### Option 2: Docker version
|
118
|
-
🟠 Recommended for users who want
|
137
|
+
🟠 Recommended for users who want bigger maps, fast generation, nice looking textures and advanced settings.
|
138
|
+
🛠️ Launch with one single command.
|
139
|
+
🗺️ Supported map sizes: 2x2, 4x4, 8x8, 16x16 km and any custom size.
|
140
|
+
⚙️ Advanced settings: enabled.
|
141
|
+
🖼️ Texture dissolving: enabled.
|
119
142
|
You can launch the project with minimalistic UI in your browser using Docker. Follow these steps:
|
120
143
|
|
121
144
|
1. Install [Docker](https://docs.docker.com/get-docker/) for your OS.
|
@@ -128,7 +151,10 @@ docker run -d -p 8501:8501 iwatkot/maps4fs
|
|
128
151
|
5. When the map is generated click on the `Download` button to get the map.
|
129
152
|
|
130
153
|
### Option 3: Python package
|
131
|
-
🔴 Recommended for developers
|
154
|
+
🔴 Recommended for developers.
|
155
|
+
🗺️ Supported map sizes: 2x2, 4x4, 8x8, 16x16 km and any custom size.
|
156
|
+
⚙️ Advanced settings: enabled.
|
157
|
+
🖼️ Texture dissolving: enabled.
|
132
158
|
You can use the Python package to generate maps. Follow these steps:
|
133
159
|
|
134
160
|
1. Install the package from PyPI:
|
@@ -177,12 +203,15 @@ The map will be saved in the `map_directory` directory.
|
|
177
203
|
## Modder Toolbox
|
178
204
|
The tool now has a Modder Toolbox, which is a set of tools to help you with various tasks. You can open the toolbox by switching to the `🧰 Modder Toolbox` tab in the StreamLit app.<br>
|
179
205
|
|
180
|
-

|
181
207
|
|
182
208
|
### Tool categories
|
183
209
|
Tools are divided into categories, which are listed below.
|
184
210
|
#### Textures and DEM
|
185
|
-
- **GeoTIFF windowing** - allows you to upload your GeoTIFF file and select the region of interest to extract it from the image.
|
211
|
+
- **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 the height map using it.
|
212
|
+
|
213
|
+
#### Background terrain
|
214
|
+
- **Convert image to obj model** - allows you to convert the image to the obj model. You can use this tool to create the background terrain for your map. It can be extremely useful if you have access to the sources of high-resolution DEM data and want to create the background terrain using it.
|
186
215
|
|
187
216
|
## Supported objects
|
188
217
|
The project is based on the [OpenStreetMap](https://www.openstreetmap.org/) data. So, refer to [this page](https://wiki.openstreetmap.org/wiki/Map_Features) to understand the list below.
|
@@ -351,7 +380,7 @@ Let's have a closer look at the fields:
|
|
351
380
|
|
352
381
|
## Background terrain
|
353
382
|
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 which can (and should) be texture to look fine.<br>
|
354
|
-
So, the tool generates the background terrain in the form of the 8 tiles, which surround the map. The tiles are named as the cardinal points, e.g. "N", "NE", "E" and so on. All those tiles will be saved in the `
|
383
|
+
So, the tool generates the background terrain in the form of the 8 tiles, which surround the map. The tiles are named as the cardinal points, e.g. "N", "NE", "E" and so on. All those tiles will be saved in the `background` directory with corresponding names: `N.obj`, `NE.obj`, `E.obj` and so on.<br>
|
355
384
|
If you don't want to work with separate tiles, the tool also generates the `FULL.obj` file, which includes everything around the map and the map itself. It may be a convinient approach to work with one file, one texture and then just cut the map from it.<br>
|
356
385
|
|
357
386
|

|
@@ -15,7 +15,7 @@ from maps4fs.generator.dem import (
|
|
15
15
|
DEFAULT_MULTIPLIER,
|
16
16
|
DEFAULT_PLATEAU,
|
17
17
|
)
|
18
|
-
from maps4fs.generator.path_steps import
|
18
|
+
from maps4fs.generator.path_steps import PATH_FULL_NAME, get_steps
|
19
19
|
from maps4fs.generator.tile import Tile
|
20
20
|
|
21
21
|
RESIZE_FACTOR = 1 / 4
|
@@ -143,7 +143,7 @@ class Background(Component):
|
|
143
143
|
self.logger.warning("DEM file not found, generation will be stopped: %s", dem_path)
|
144
144
|
return
|
145
145
|
|
146
|
-
self.logger.
|
146
|
+
self.logger.debug("DEM file for tile %s found: %s", tile.code, dem_path)
|
147
147
|
|
148
148
|
base_directory = os.path.dirname(dem_path)
|
149
149
|
save_path = os.path.join(base_directory, f"{tile.code}.obj")
|
@@ -164,7 +164,6 @@ class Background(Component):
|
|
164
164
|
if tile_code == PATH_FULL_NAME:
|
165
165
|
resize_factor = FULL_RESIZE_FACTOR
|
166
166
|
simplify_factor = FULL_SIMPLIFY_FACTOR
|
167
|
-
self.logger.info("Generating a full map obj file")
|
168
167
|
else:
|
169
168
|
resize_factor = RESIZE_FACTOR
|
170
169
|
simplify_factor = SIMPLIFY_FACTOR
|
@@ -242,119 +241,21 @@ class Background(Component):
|
|
242
241
|
|
243
242
|
self.stl_preview_path = preview_path # pylint: disable=attribute-defined-outside-init
|
244
243
|
|
244
|
+
# pylint: disable=no-member
|
245
245
|
def previews(self) -> list[str]:
|
246
|
-
"""
|
247
|
-
NOTE: The map itself is not included in the preview, so it will be empty.
|
246
|
+
"""Returns the path to the image of full tile and the path to the STL preview file.
|
248
247
|
|
249
248
|
Returns:
|
250
|
-
list[str] -- A list of paths to the
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
image = np.zeros((image_height, image_width), np.uint16) # pylint: disable=no-member
|
259
|
-
self.logger.debug("Empty image created: %s", image.shape)
|
260
|
-
|
261
|
-
for tile in self.tiles:
|
262
|
-
# pylint: disable=no-member
|
263
|
-
if tile.code == PATH_FULL_NAME:
|
264
|
-
continue
|
265
|
-
tile_image = cv2.imread(tile.dem_path, cv2.IMREAD_UNCHANGED)
|
266
|
-
|
267
|
-
self.logger.debug(
|
268
|
-
"Tile %s image shape: %s, dtype: %s, max: %s, min: %s",
|
269
|
-
tile.code,
|
270
|
-
tile_image.shape,
|
271
|
-
tile_image.dtype,
|
272
|
-
tile_image.max(),
|
273
|
-
tile_image.min(),
|
274
|
-
)
|
275
|
-
|
276
|
-
tile_height, tile_width = tile_image.shape
|
277
|
-
self.logger.debug("Tile %s size: %s x %s", tile.code, tile_width, tile_height)
|
278
|
-
|
279
|
-
# Calculate the position based on the tile code
|
280
|
-
if tile.code == "N":
|
281
|
-
x = DEFAULT_DISTANCE
|
282
|
-
y = 0
|
283
|
-
elif tile.code == "NE":
|
284
|
-
x = self.map_width + DEFAULT_DISTANCE
|
285
|
-
y = 0
|
286
|
-
elif tile.code == "E":
|
287
|
-
x = self.map_width + DEFAULT_DISTANCE
|
288
|
-
y = DEFAULT_DISTANCE
|
289
|
-
elif tile.code == "SE":
|
290
|
-
x = self.map_width + DEFAULT_DISTANCE
|
291
|
-
y = self.map_height + DEFAULT_DISTANCE
|
292
|
-
elif tile.code == "S":
|
293
|
-
x = DEFAULT_DISTANCE
|
294
|
-
y = self.map_height + DEFAULT_DISTANCE
|
295
|
-
elif tile.code == "SW":
|
296
|
-
x = 0
|
297
|
-
y = self.map_height + DEFAULT_DISTANCE
|
298
|
-
elif tile.code == "W":
|
299
|
-
x = 0
|
300
|
-
y = DEFAULT_DISTANCE
|
301
|
-
elif tile.code == "NW":
|
302
|
-
x = 0
|
303
|
-
y = 0
|
304
|
-
|
305
|
-
# pylint: disable=possibly-used-before-assignment
|
306
|
-
x2 = x + tile_width
|
307
|
-
y2 = y + tile_height
|
308
|
-
|
309
|
-
self.logger.debug(
|
310
|
-
"Tile %s position. X from %s to %s, Y from %s to %s", tile.code, x, x2, y, y2
|
249
|
+
list[str] -- A list of paths to the previews.
|
250
|
+
"""
|
251
|
+
full_tile = next((tile for tile in self.tiles if tile.code == PATH_FULL_NAME), None)
|
252
|
+
if full_tile:
|
253
|
+
preview_path = os.path.join(self.previews_directory, "background_dem.png")
|
254
|
+
full_tile_image = cv2.imread(full_tile.dem_path, cv2.IMREAD_UNCHANGED)
|
255
|
+
full_tile_image = cv2.normalize( # type: ignore
|
256
|
+
full_tile_image, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U
|
311
257
|
)
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
# Save image to the map directory.
|
317
|
-
preview_path = os.path.join(self.previews_directory, "background_dem.png")
|
318
|
-
|
319
|
-
# pylint: disable=no-member
|
320
|
-
image = cv2.normalize(image, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U) # type: ignore
|
321
|
-
image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR) # type: ignore
|
322
|
-
cv2.imwrite(preview_path, image)
|
323
|
-
|
324
|
-
return [preview_path, self.stl_preview_path]
|
325
|
-
|
326
|
-
|
327
|
-
# Creates tiles around the map.
|
328
|
-
# The one on corners 2048x2048, on sides and in the middle map_size x 2048.
|
329
|
-
# So 2048 is a distance FROM the edge of the map, but the other size depends on the map size.
|
330
|
-
# But for corner tiles it's always 2048.
|
331
|
-
|
332
|
-
# In the beginning we have coordinates of the central point of the map and it's size.
|
333
|
-
# We need to calculate the coordinates of central points all 8 tiles around the map.
|
334
|
-
|
335
|
-
# Latitude is a vertical line, Longitude is a horizontal line.
|
336
|
-
|
337
|
-
# 2048
|
338
|
-
# | |
|
339
|
-
# ____________________|_________|___
|
340
|
-
# | | | |
|
341
|
-
# | NW | N | NE | 2048
|
342
|
-
# |_________|_________|_________|___
|
343
|
-
# | | | |
|
344
|
-
# | W | C | E |
|
345
|
-
# |_________|_________|_________|
|
346
|
-
# | | | |
|
347
|
-
# | SW | S | SE |
|
348
|
-
# |_________|_________|_________|
|
349
|
-
#
|
350
|
-
# N = C map_height / 2 + 1024; N_width = map_width; N_height = 2048
|
351
|
-
# NW = N - map_width / 2 - 1024; NW_width = 2048; NW_height = 2048
|
352
|
-
# and so on...
|
353
|
-
|
354
|
-
# lat, lon = 45.28565000315636, 20.237121355049904
|
355
|
-
# dst = 1024
|
356
|
-
|
357
|
-
# # N
|
358
|
-
# destination = distance(meters=dst).destination((lat, lon), 0)
|
359
|
-
# lat, lon = destination.latitude, destination.longitude
|
360
|
-
# print(lat, lon)
|
258
|
+
full_tile_image = cv2.cvtColor(full_tile_image, cv2.COLOR_GRAY2BGR)
|
259
|
+
cv2.imwrite(preview_path, full_tile_image)
|
260
|
+
return [preview_path, self.stl_preview_path]
|
261
|
+
return [self.stl_preview_path]
|
@@ -50,6 +50,7 @@ class Component:
|
|
50
50
|
|
51
51
|
os.makedirs(self.previews_directory, exist_ok=True)
|
52
52
|
os.makedirs(self.scripts_directory, exist_ok=True)
|
53
|
+
os.makedirs(self.info_layers_directory, exist_ok=True)
|
53
54
|
|
54
55
|
self.save_bbox()
|
55
56
|
self.preprocess()
|
@@ -87,6 +88,15 @@ class Component:
|
|
87
88
|
"""
|
88
89
|
return os.path.join(self.map_directory, "previews")
|
89
90
|
|
91
|
+
@property
|
92
|
+
def info_layers_directory(self) -> str:
|
93
|
+
"""The directory where the info layers are stored.
|
94
|
+
|
95
|
+
Returns:
|
96
|
+
str: The directory where the info layers are stored.
|
97
|
+
"""
|
98
|
+
return os.path.join(self.map_directory, "info_layers")
|
99
|
+
|
90
100
|
@property
|
91
101
|
def scripts_directory(self) -> str:
|
92
102
|
"""The directory where the scripts are stored.
|
@@ -174,10 +184,10 @@ class Component:
|
|
174
184
|
height_distance = height_distance or int(self.map_height / 2)
|
175
185
|
width_distance = width_distance or int(self.map_width / 2)
|
176
186
|
|
177
|
-
|
187
|
+
west, south, _, _ = ox.utils_geo.bbox_from_point( # type: ignore
|
178
188
|
coordinates, dist=height_distance, project_utm=project_utm
|
179
189
|
)
|
180
|
-
_, _, east,
|
190
|
+
_, _, east, north = ox.utils_geo.bbox_from_point( # type: ignore
|
181
191
|
coordinates, dist=width_distance, project_utm=project_utm
|
182
192
|
)
|
183
193
|
bbox = north, south, east, west
|
@@ -36,7 +36,7 @@ class Config(Component):
|
|
36
36
|
self.logger.warning("Map XML file not found: %s.", self._map_xml_path)
|
37
37
|
return
|
38
38
|
tree = ET.parse(self._map_xml_path)
|
39
|
-
self.logger.
|
39
|
+
self.logger.info("Map XML file loaded from: %s.", self._map_xml_path)
|
40
40
|
root = tree.getroot()
|
41
41
|
for map_elem in root.iter("map"):
|
42
42
|
map_elem.set("width", str(self.map_width))
|
@@ -103,7 +103,7 @@ class DEM(Component):
|
|
103
103
|
north, south, east, west = self.bbox
|
104
104
|
|
105
105
|
dem_output_resolution = self.get_output_resolution()
|
106
|
-
self.logger.
|
106
|
+
self.logger.info("DEM output resolution: %s.", dem_output_resolution)
|
107
107
|
|
108
108
|
tile_path = self._srtm_tile()
|
109
109
|
if not tile_path:
|
@@ -223,7 +223,7 @@ class DEM(Component):
|
|
223
223
|
)
|
224
224
|
|
225
225
|
cv2.imwrite(self._dem_path, resampled_data)
|
226
|
-
self.logger.
|
226
|
+
self.logger.info("DEM data was saved to %s.", self._dem_path)
|
227
227
|
|
228
228
|
if self.game.additional_dem_name is not None:
|
229
229
|
self.make_copy(self.game.additional_dem_name)
|
@@ -239,7 +239,7 @@ class DEM(Component):
|
|
239
239
|
additional_dem_path = os.path.join(dem_directory, dem_name)
|
240
240
|
|
241
241
|
shutil.copyfile(self._dem_path, additional_dem_path)
|
242
|
-
self.logger.
|
242
|
+
self.logger.info("Additional DEM data was copied to %s.", additional_dem_path)
|
243
243
|
|
244
244
|
def _tile_info(self, lat: float, lon: float) -> tuple[str, str]:
|
245
245
|
"""Returns latitude band and tile name for SRTM tile from coordinates.
|
@@ -260,7 +260,7 @@ class DEM(Component):
|
|
260
260
|
else:
|
261
261
|
tile_name = f"{latitude_band}E{abs(tile_longitude):03d}"
|
262
262
|
|
263
|
-
self.logger.
|
263
|
+
self.logger.info(
|
264
264
|
"Detected tile name: %s for coordinates: lat %s, lon %s.", tile_name, lat, lon
|
265
265
|
)
|
266
266
|
return latitude_band, tile_name
|
@@ -319,7 +319,7 @@ class DEM(Component):
|
|
319
319
|
def _save_empty_dem(self, dem_output_resolution: tuple[int, int]) -> None:
|
320
320
|
"""Saves empty DEM file filled with zeros."""
|
321
321
|
dem_data = np.zeros(dem_output_resolution, dtype="uint16")
|
322
|
-
cv2.imwrite(self._dem_path, dem_data)
|
322
|
+
cv2.imwrite(self._dem_path, dem_data)
|
323
323
|
self.logger.warning("DEM data filled with zeros and saved to %s.", self._dem_path)
|
324
324
|
|
325
325
|
def grayscale_preview(self) -> str:
|
@@ -329,7 +329,6 @@ class DEM(Component):
|
|
329
329
|
Returns:
|
330
330
|
str: Path to the preview image.
|
331
331
|
"""
|
332
|
-
# rgb_dem_path = self._dem_path.replace(".png", "_grayscale.png")
|
333
332
|
grayscale_dem_path = os.path.join(self.previews_directory, "dem_grayscale.png")
|
334
333
|
|
335
334
|
self.logger.debug("Creating grayscale preview of DEM data in %s.", grayscale_dem_path)
|
@@ -346,8 +345,6 @@ class DEM(Component):
|
|
346
345
|
Returns:
|
347
346
|
list[str]: List with a single path to the DEM file
|
348
347
|
"""
|
349
|
-
|
350
|
-
# colored_dem_path = self._dem_path.replace(".png", "_colored.png")
|
351
348
|
colored_dem_path = os.path.join(self.previews_directory, "dem_colored.png")
|
352
349
|
|
353
350
|
self.logger.debug("Creating colored preview of DEM data in %s.", colored_dem_path)
|
@@ -424,14 +421,18 @@ class DEM(Component):
|
|
424
421
|
|
425
422
|
scaling_factor = self._get_scaling_factor(max_dev)
|
426
423
|
adjusted_max_height = int(65535 * scaling_factor)
|
427
|
-
self.logger.
|
428
|
-
|
429
|
-
|
424
|
+
self.logger.info(
|
425
|
+
"Maximum deviation: %s. Scaling factor: %s. Adjusted max height: %s.",
|
426
|
+
max_dev,
|
427
|
+
scaling_factor,
|
428
|
+
adjusted_max_height,
|
430
429
|
)
|
431
430
|
normalized_data = (
|
432
431
|
(data - data.min()) / (data.max() - data.min()) * adjusted_max_height
|
433
432
|
).astype("uint16")
|
434
433
|
self.logger.debug(
|
435
|
-
|
434
|
+
"DEM data was normalized to %s - %s.",
|
435
|
+
normalized_data.min(),
|
436
|
+
normalized_data.max(),
|
436
437
|
)
|
437
438
|
return normalized_data
|
@@ -38,7 +38,8 @@ class Game:
|
|
38
38
|
_texture_schema: str | None = None
|
39
39
|
_grle_schema: str | None = None
|
40
40
|
|
41
|
-
|
41
|
+
# Order matters! Some components depend on others.
|
42
|
+
components = [Texture, I3d, DEM, Config, GRLE, Background]
|
42
43
|
|
43
44
|
def __init__(self, map_template_path: str | None = None):
|
44
45
|
if map_template_path:
|
@@ -61,7 +61,7 @@ class GRLE(Component):
|
|
61
61
|
info_layer_data = np.zeros((height, width), dtype=data_type)
|
62
62
|
print(info_layer_data.shape)
|
63
63
|
cv2.imwrite(file_path, info_layer_data) # pylint: disable=no-member
|
64
|
-
self.logger.
|
64
|
+
self.logger.debug("InfoLayer PNG file %s created.", file_path)
|
65
65
|
else:
|
66
66
|
self.logger.warning("Invalid InfoLayer schema: %s.", info_layer)
|
67
67
|
|