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
maps4fs/__init__.py
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
# pylint: disable=missing-module-docstring
|
2
|
+
from maps4fs.generator.dtm.dtm import DTMProvider
|
3
|
+
from maps4fs.generator.dtm.srtm import SRTM30Provider
|
4
|
+
from maps4fs.generator.dtm.usgs import USGSProvider
|
2
5
|
from maps4fs.generator.game import Game
|
3
|
-
from maps4fs.generator.map import
|
6
|
+
from maps4fs.generator.map import Map
|
7
|
+
from maps4fs.generator.settings import (
|
4
8
|
BackgroundSettings,
|
5
9
|
DEMSettings,
|
6
10
|
GRLESettings,
|
7
11
|
I3DSettings,
|
8
|
-
Map,
|
9
12
|
SettingsModel,
|
10
13
|
SplineSettings,
|
11
14
|
TextureSettings,
|
maps4fs/generator/background.py
CHANGED
@@ -57,36 +57,49 @@ class Background(Component):
|
|
57
57
|
os.makedirs(self.background_directory, exist_ok=True)
|
58
58
|
os.makedirs(self.water_directory, exist_ok=True)
|
59
59
|
|
60
|
-
|
61
|
-
self.
|
62
|
-
|
63
|
-
|
60
|
+
self.output_path = os.path.join(self.background_directory, f"{FULL_NAME}.png")
|
61
|
+
if self.map.custom_background_path:
|
62
|
+
self.check_custom_background(self.map.custom_background_path)
|
63
|
+
shutil.copyfile(self.map.custom_background_path, self.output_path)
|
64
|
+
|
64
65
|
self.not_substracted_path = os.path.join(self.background_directory, "not_substracted.png")
|
65
66
|
self.not_resized_path = os.path.join(self.background_directory, "not_resized.png")
|
66
67
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
68
|
+
self.dem = DEM(
|
69
|
+
self.game,
|
70
|
+
self.map,
|
71
|
+
self.coordinates,
|
72
|
+
self.background_size,
|
73
|
+
self.rotated_size,
|
74
|
+
self.rotation,
|
75
|
+
self.map_directory,
|
76
|
+
self.logger,
|
77
|
+
)
|
78
|
+
self.dem.preprocess()
|
79
|
+
self.dem.set_output_resolution((self.rotated_size, self.rotated_size))
|
80
|
+
self.dem.set_dem_path(self.output_path)
|
81
|
+
|
82
|
+
def check_custom_background(self, image_path: str) -> None:
|
83
|
+
"""Checks if the custom background image meets the requirements.
|
84
|
+
|
85
|
+
Arguments:
|
86
|
+
image_path (str): The path to the custom background image.
|
87
|
+
|
88
|
+
Raises:
|
89
|
+
ValueError: If the custom background image does not meet the requirements.
|
90
|
+
"""
|
91
|
+
image = cv2.imread(image_path, cv2.IMREAD_UNCHANGED) # pylint: disable=no-member
|
92
|
+
if image.shape[0] != image.shape[1]:
|
93
|
+
raise ValueError("The custom background image must be a square.")
|
94
|
+
|
95
|
+
if image.shape[0] != self.map_size + DEFAULT_DISTANCE * 2:
|
96
|
+
raise ValueError("The custom background image must have the size of the map + 4096.")
|
97
|
+
|
98
|
+
if len(image.shape) != 2:
|
99
|
+
raise ValueError("The custom background image must be a grayscale image.")
|
88
100
|
|
89
|
-
|
101
|
+
if image.dtype != np.uint16:
|
102
|
+
raise ValueError("The custom background image must be a 16-bit grayscale image.")
|
90
103
|
|
91
104
|
def is_preview(self, name: str) -> bool:
|
92
105
|
"""Checks if the DEM is a preview.
|
@@ -105,20 +118,18 @@ class Background(Component):
|
|
105
118
|
generated."""
|
106
119
|
self.create_background_textures()
|
107
120
|
|
108
|
-
|
109
|
-
dem.process()
|
110
|
-
|
111
|
-
|
112
|
-
|
121
|
+
if not self.map.custom_background_path:
|
122
|
+
self.dem.process()
|
123
|
+
|
124
|
+
shutil.copyfile(self.dem.dem_path, self.not_substracted_path)
|
125
|
+
self.cutout(self.dem.dem_path, save_path=self.not_resized_path)
|
113
126
|
|
114
127
|
if self.map.dem_settings.water_depth:
|
115
128
|
self.subtraction()
|
116
129
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
if self.game.additional_dem_name is not None:
|
121
|
-
self.make_copy(cutted_dem_path, self.game.additional_dem_name)
|
130
|
+
cutted_dem_path = self.cutout(self.dem.dem_path)
|
131
|
+
if self.game.additional_dem_name is not None:
|
132
|
+
self.make_copy(cutted_dem_path, self.game.additional_dem_name)
|
122
133
|
|
123
134
|
if self.map.background_settings.generate_background:
|
124
135
|
self.generate_obj_files()
|
@@ -149,32 +160,33 @@ class Background(Component):
|
|
149
160
|
"""
|
150
161
|
self.qgis_sequence()
|
151
162
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
epsg3857_string = dem.get_epsg3857_string()
|
156
|
-
epsg3857_string_with_margin = dem.get_epsg3857_string(add_margin=True)
|
163
|
+
north, south, east, west = self.dem.bbox
|
164
|
+
epsg3857_string = self.dem.get_epsg3857_string()
|
165
|
+
epsg3857_string_with_margin = self.dem.get_epsg3857_string(add_margin=True)
|
157
166
|
|
158
167
|
data = {
|
159
|
-
"center_latitude": dem.coordinates[0],
|
160
|
-
"center_longitude": dem.coordinates[1],
|
168
|
+
"center_latitude": self.dem.coordinates[0],
|
169
|
+
"center_longitude": self.dem.coordinates[1],
|
161
170
|
"epsg3857_string": epsg3857_string,
|
162
171
|
"epsg3857_string_with_margin": epsg3857_string_with_margin,
|
163
|
-
"height": dem.map_size,
|
164
|
-
"width": dem.map_size,
|
172
|
+
"height": self.dem.map_size,
|
173
|
+
"width": self.dem.map_size,
|
165
174
|
"north": north,
|
166
175
|
"south": south,
|
167
176
|
"east": east,
|
168
177
|
"west": west,
|
169
178
|
}
|
179
|
+
|
180
|
+
dem_info_sequence = self.dem.info_sequence()
|
181
|
+
data["DEM"] = dem_info_sequence
|
170
182
|
return data # type: ignore
|
171
183
|
|
172
184
|
def qgis_sequence(self) -> None:
|
173
185
|
"""Generates QGIS scripts for creating bounding box layers and rasterizing them."""
|
174
|
-
qgis_layer = (f"Background_{FULL_NAME}", *self.
|
186
|
+
qgis_layer = (f"Background_{FULL_NAME}", *self.dem.get_espg3857_bbox())
|
175
187
|
qgis_layer_with_margin = (
|
176
188
|
f"Background_{FULL_NAME}_margin",
|
177
|
-
*self.
|
189
|
+
*self.dem.get_espg3857_bbox(add_margin=True),
|
178
190
|
)
|
179
191
|
self.create_qgis_scripts([qgis_layer, qgis_layer_with_margin])
|
180
192
|
|
@@ -182,21 +194,26 @@ class Background(Component):
|
|
182
194
|
"""Iterates over all dems and generates 3D obj files based on DEM data.
|
183
195
|
If at least one DEM file is missing, the generation will be stopped at all.
|
184
196
|
"""
|
185
|
-
|
186
|
-
|
187
|
-
self.
|
188
|
-
|
189
|
-
|
190
|
-
return
|
197
|
+
if not os.path.isfile(self.dem.dem_path):
|
198
|
+
self.logger.warning(
|
199
|
+
"DEM file not found, generation will be stopped: %s", self.dem.dem_path
|
200
|
+
)
|
201
|
+
return
|
191
202
|
|
192
|
-
|
203
|
+
self.logger.debug("DEM file for found: %s", self.dem.dem_path)
|
193
204
|
|
194
|
-
|
195
|
-
|
196
|
-
|
205
|
+
filename = os.path.splitext(os.path.basename(self.dem.dem_path))[0]
|
206
|
+
save_path = os.path.join(self.background_directory, f"{filename}.obj")
|
207
|
+
self.logger.debug("Generating obj file in path: %s", save_path)
|
197
208
|
|
198
|
-
|
199
|
-
|
209
|
+
dem_data = cv2.imread(self.dem.dem_path, cv2.IMREAD_UNCHANGED) # pylint: disable=no-member
|
210
|
+
self.plane_from_np(
|
211
|
+
dem_data,
|
212
|
+
save_path,
|
213
|
+
create_preview=True,
|
214
|
+
remove_center=self.map.background_settings.remove_center,
|
215
|
+
include_zeros=False,
|
216
|
+
) # type: ignore
|
200
217
|
|
201
218
|
# pylint: disable=too-many-locals
|
202
219
|
def cutout(self, dem_path: str, save_path: str | None = None) -> str:
|
@@ -239,30 +256,56 @@ class Background(Component):
|
|
239
256
|
)
|
240
257
|
|
241
258
|
cv2.imwrite(main_dem_path, resized_dem_data) # pylint: disable=no-member
|
242
|
-
self.logger.
|
259
|
+
self.logger.debug("DEM cutout saved: %s", main_dem_path)
|
243
260
|
|
244
261
|
return main_dem_path
|
245
262
|
|
246
|
-
|
263
|
+
def remove_center(self, dem_data: np.ndarray, resize_factor: float) -> np.ndarray:
|
264
|
+
"""Removes the center part of the DEM data.
|
265
|
+
|
266
|
+
Arguments:
|
267
|
+
dem_data (np.ndarray) -- The DEM data as a numpy array.
|
268
|
+
resize_factor (float) -- The resize factor of the DEM data.
|
269
|
+
|
270
|
+
Returns:
|
271
|
+
np.ndarray -- The DEM data with the center part removed.
|
272
|
+
"""
|
273
|
+
center = (dem_data.shape[0] // 2, dem_data.shape[1] // 2)
|
274
|
+
half_size = int(self.map_size // 2 * resize_factor)
|
275
|
+
x1 = center[0] - half_size
|
276
|
+
x2 = center[0] + half_size
|
277
|
+
y1 = center[1] - half_size
|
278
|
+
y2 = center[1] + half_size
|
279
|
+
dem_data[x1:x2, y1:y2] = 0
|
280
|
+
return dem_data
|
281
|
+
|
282
|
+
# pylint: disable=R0913, R0917, R0915
|
247
283
|
def plane_from_np(
|
248
284
|
self,
|
249
285
|
dem_data: np.ndarray,
|
250
286
|
save_path: str,
|
251
|
-
is_preview: bool = False,
|
252
287
|
include_zeros: bool = True,
|
288
|
+
create_preview: bool = False,
|
289
|
+
remove_center: bool = False,
|
253
290
|
) -> None:
|
254
291
|
"""Generates a 3D obj file based on DEM data.
|
255
292
|
|
256
293
|
Arguments:
|
257
294
|
dem_data (np.ndarray) -- The DEM data as a numpy array.
|
258
295
|
save_path (str) -- The path where the obj file will be saved.
|
259
|
-
is_preview (bool, optional) -- If True, the preview mesh will be generated.
|
260
296
|
include_zeros (bool, optional) -- If True, the mesh will include the zero height values.
|
297
|
+
create_preview (bool, optional) -- If True, a simplified mesh will be saved as an STL.
|
298
|
+
remove_center (bool, optional) -- If True, the center of the mesh will be removed.
|
299
|
+
This setting is used for a Background Terrain, where the center part where the
|
300
|
+
playable area is will be cut out.
|
261
301
|
"""
|
262
302
|
resize_factor = 1 / self.map.background_settings.resize_factor
|
263
303
|
dem_data = cv2.resize( # pylint: disable=no-member
|
264
304
|
dem_data, (0, 0), fx=resize_factor, fy=resize_factor
|
265
305
|
)
|
306
|
+
if remove_center:
|
307
|
+
dem_data = self.remove_center(dem_data, resize_factor)
|
308
|
+
self.logger.debug("Center removed from DEM data.")
|
266
309
|
self.logger.debug(
|
267
310
|
"DEM data resized to shape: %s with factor: %s", dem_data.shape, resize_factor
|
268
311
|
)
|
@@ -297,7 +340,10 @@ class Background(Component):
|
|
297
340
|
bottom_left = top_left + cols
|
298
341
|
bottom_right = bottom_left + 1
|
299
342
|
|
300
|
-
if
|
343
|
+
if (
|
344
|
+
ground in [z[i, j], z[i, j + 1], z[i + 1, j], z[i + 1, j + 1]]
|
345
|
+
and not include_zeros
|
346
|
+
):
|
301
347
|
skipped += 1
|
302
348
|
continue
|
303
349
|
|
@@ -315,25 +361,37 @@ class Background(Component):
|
|
315
361
|
mesh.apply_transform(rotation_matrix_y)
|
316
362
|
mesh.apply_transform(rotation_matrix_z)
|
317
363
|
|
318
|
-
if
|
364
|
+
# if not include_zeros:
|
365
|
+
z_scaling_factor = self.get_z_scaling_factor()
|
366
|
+
self.logger.debug("Z scaling factor: %s", z_scaling_factor)
|
367
|
+
mesh.apply_scale([1 / resize_factor, 1 / resize_factor, z_scaling_factor])
|
368
|
+
|
369
|
+
old_faces = len(mesh.faces)
|
370
|
+
self.logger.debug("Mesh generated with %s faces.", old_faces)
|
371
|
+
|
372
|
+
if self.map.background_settings.apply_decimation:
|
373
|
+
percent = self.map.background_settings.decimation_percent / 100
|
374
|
+
mesh = mesh.simplify_quadric_decimation(
|
375
|
+
percent=percent, aggression=self.map.background_settings.decimation_agression
|
376
|
+
)
|
377
|
+
|
378
|
+
new_faces = len(mesh.faces)
|
379
|
+
decimation_percent = (old_faces - new_faces) / old_faces * 100
|
380
|
+
|
381
|
+
self.logger.debug(
|
382
|
+
"Mesh simplified to %s faces. Decimation percent: %s", new_faces, decimation_percent
|
383
|
+
)
|
384
|
+
|
385
|
+
mesh.export(save_path)
|
386
|
+
self.logger.debug("Obj file saved: %s", save_path)
|
387
|
+
|
388
|
+
if create_preview:
|
319
389
|
# Simplify the preview mesh to reduce the size of the file.
|
320
|
-
mesh = mesh.simplify_quadric_decimation(face_count=len(mesh.faces) // 2**7)
|
390
|
+
# mesh = mesh.simplify_quadric_decimation(face_count=len(mesh.faces) // 2**7)
|
321
391
|
|
322
392
|
# Apply scale to make the preview mesh smaller in the UI.
|
323
393
|
mesh.apply_scale([0.5, 0.5, 0.5])
|
324
394
|
self.mesh_to_stl(mesh)
|
325
|
-
else:
|
326
|
-
if not include_zeros:
|
327
|
-
multiplier = self.map.dem_settings.multiplier
|
328
|
-
if multiplier != 1:
|
329
|
-
z_scaling_factor = 1 / multiplier
|
330
|
-
else:
|
331
|
-
z_scaling_factor = 1 / 2**5
|
332
|
-
self.logger.debug("Z scaling factor: %s", z_scaling_factor)
|
333
|
-
mesh.apply_scale([1 / resize_factor, 1 / resize_factor, z_scaling_factor])
|
334
|
-
|
335
|
-
mesh.export(save_path)
|
336
|
-
self.logger.debug("Obj file saved: %s", save_path)
|
337
395
|
|
338
396
|
def mesh_to_stl(self, mesh: trimesh.Trimesh) -> None:
|
339
397
|
"""Converts the mesh to an STL file and saves it in the previews directory.
|
@@ -358,25 +416,22 @@ class Background(Component):
|
|
358
416
|
list[str] -- A list of paths to the previews.
|
359
417
|
"""
|
360
418
|
preview_paths = self.dem_previews(self.game.dem_file_path(self.map_directory))
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
cv2.imwrite(background_dem_preview_path, background_dem_preview_image)
|
379
|
-
preview_paths.append(background_dem_preview_path)
|
419
|
+
|
420
|
+
background_dem_preview_path = os.path.join(self.previews_directory, "background_dem.png")
|
421
|
+
background_dem_preview_image = cv2.imread(self.dem.dem_path, cv2.IMREAD_UNCHANGED)
|
422
|
+
|
423
|
+
background_dem_preview_image = cv2.resize(
|
424
|
+
background_dem_preview_image, (0, 0), fx=1 / 4, fy=1 / 4
|
425
|
+
)
|
426
|
+
background_dem_preview_image = cv2.normalize( # type: ignore
|
427
|
+
background_dem_preview_image, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U
|
428
|
+
)
|
429
|
+
background_dem_preview_image = cv2.cvtColor(
|
430
|
+
background_dem_preview_image, cv2.COLOR_GRAY2BGR
|
431
|
+
)
|
432
|
+
|
433
|
+
cv2.imwrite(background_dem_preview_path, background_dem_preview_image)
|
434
|
+
preview_paths.append(background_dem_preview_path)
|
380
435
|
|
381
436
|
if self.stl_preview_path:
|
382
437
|
preview_paths.append(self.stl_preview_path)
|
@@ -525,18 +580,15 @@ class Background(Component):
|
|
525
580
|
bool
|
526
581
|
)
|
527
582
|
|
528
|
-
|
529
|
-
if FULL_PREVIEW_NAME in output_path:
|
530
|
-
continue
|
531
|
-
dem_image = cv2.imread(output_path, cv2.IMREAD_UNCHANGED)
|
583
|
+
dem_image = cv2.imread(self.output_path, cv2.IMREAD_UNCHANGED)
|
532
584
|
|
533
|
-
|
534
|
-
|
535
|
-
|
585
|
+
# Create a mask where water_resources_image is 255 (or not 0)
|
586
|
+
# Subtract water_depth from dem_image where mask is True
|
587
|
+
dem_image[mask] = dem_image[mask] - self.map.dem_settings.water_depth
|
536
588
|
|
537
|
-
|
538
|
-
|
539
|
-
|
589
|
+
# Save the modified dem_image back to the output path
|
590
|
+
cv2.imwrite(self.output_path, dem_image)
|
591
|
+
self.logger.debug("Water depth subtracted from DEM data: %s", self.output_path)
|
540
592
|
|
541
593
|
def generate_water_resources_obj(self) -> None:
|
542
594
|
"""Generates 3D obj files based on water resources data."""
|
@@ -550,9 +602,7 @@ class Background(Component):
|
|
550
602
|
plane_water.astype(np.uint8), np.ones((5, 5), np.uint8), iterations=5
|
551
603
|
).astype(np.uint8)
|
552
604
|
plane_save_path = os.path.join(self.water_directory, "plane_water.obj")
|
553
|
-
self.plane_from_np(
|
554
|
-
dilated_plane_water, plane_save_path, is_preview=False, include_zeros=False
|
555
|
-
)
|
605
|
+
self.plane_from_np(dilated_plane_water, plane_save_path, include_zeros=False)
|
556
606
|
|
557
607
|
# Single channeled 16 bit DEM image of terrain.
|
558
608
|
background_dem = cv2.imread(self.not_substracted_path, cv2.IMREAD_UNCHANGED)
|
@@ -570,6 +620,4 @@ class Background(Component):
|
|
570
620
|
elevated_water = np.where(mask, background_dem, elevated_water)
|
571
621
|
elevated_save_path = os.path.join(self.water_directory, "elevated_water.obj")
|
572
622
|
|
573
|
-
self.plane_from_np(
|
574
|
-
elevated_water, elevated_save_path, is_preview=False, include_zeros=False
|
575
|
-
)
|
623
|
+
self.plane_from_np(elevated_water, elevated_save_path, include_zeros=False)
|
maps4fs/generator/component.py
CHANGED
@@ -58,7 +58,7 @@ class Component:
|
|
58
58
|
self.logger = logger
|
59
59
|
self.kwargs = kwargs
|
60
60
|
|
61
|
-
self.logger.
|
61
|
+
self.logger.debug(
|
62
62
|
"Component %s initialized. Map size: %s, map rotated size: %s", # type: ignore
|
63
63
|
self.__class__.__name__,
|
64
64
|
self.map_size,
|
@@ -68,6 +68,7 @@ class Component:
|
|
68
68
|
os.makedirs(self.previews_directory, exist_ok=True)
|
69
69
|
os.makedirs(self.scripts_directory, exist_ok=True)
|
70
70
|
os.makedirs(self.info_layers_directory, exist_ok=True)
|
71
|
+
os.makedirs(self.satellite_directory, exist_ok=True)
|
71
72
|
|
72
73
|
self.save_bbox()
|
73
74
|
self.preprocess()
|
@@ -123,6 +124,15 @@ class Component:
|
|
123
124
|
"""
|
124
125
|
return os.path.join(self.map_directory, "scripts")
|
125
126
|
|
127
|
+
@property
|
128
|
+
def satellite_directory(self) -> str:
|
129
|
+
"""The directory where the satellite images are stored.
|
130
|
+
|
131
|
+
Returns:
|
132
|
+
str: The directory where the satellite images are stored.
|
133
|
+
"""
|
134
|
+
return os.path.join(self.map_directory, "satellite")
|
135
|
+
|
126
136
|
@property
|
127
137
|
def generation_info_path(self) -> str:
|
128
138
|
"""The path to the generation info JSON file.
|
@@ -525,3 +535,26 @@ class Component:
|
|
525
535
|
interpolated_polyline.append(polyline[-1])
|
526
536
|
|
527
537
|
return interpolated_polyline
|
538
|
+
|
539
|
+
def get_z_scaling_factor(self) -> float:
|
540
|
+
"""Calculates the scaling factor for the Z axis based on the map settings.
|
541
|
+
|
542
|
+
Returns:
|
543
|
+
float -- The scaling factor for the Z axis.
|
544
|
+
"""
|
545
|
+
|
546
|
+
scaling_factor = 1 / self.map.dem_settings.multiplier
|
547
|
+
self.logger.debug("Z scaling factor including DEM multiplier: %s", scaling_factor)
|
548
|
+
|
549
|
+
if self.map.shared_settings.height_scale_multiplier:
|
550
|
+
scaling_factor *= self.map.shared_settings.height_scale_multiplier
|
551
|
+
self.logger.debug(
|
552
|
+
"Z scaling factor including height scale multiplier: %s", scaling_factor
|
553
|
+
)
|
554
|
+
if self.map.shared_settings.mesh_z_scaling_factor:
|
555
|
+
scaling_factor *= 1 / self.map.shared_settings.mesh_z_scaling_factor
|
556
|
+
self.logger.debug(
|
557
|
+
"Z scaling factor including mesh z scaling factor: %s", scaling_factor
|
558
|
+
)
|
559
|
+
|
560
|
+
return scaling_factor
|