maps4fs 2.9.2__py3-none-any.whl → 2.9.37__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/generator/component/background.py +18 -3
- maps4fs/generator/component/building.py +706 -0
- maps4fs/generator/component/grle.py +57 -0
- maps4fs/generator/component/i3d.py +59 -5
- maps4fs/generator/component/layer.py +19 -0
- maps4fs/generator/component/road.py +648 -0
- maps4fs/generator/component/texture.py +16 -4
- maps4fs/generator/config.py +79 -11
- maps4fs/generator/game.py +64 -3
- maps4fs/generator/map.py +3 -0
- maps4fs/generator/settings.py +18 -1
- maps4fs/generator/utils.py +15 -1
- {maps4fs-2.9.2.dist-info → maps4fs-2.9.37.dist-info}/METADATA +6 -4
- maps4fs-2.9.37.dist-info/RECORD +32 -0
- maps4fs-2.9.37.dist-info/licenses/LICENSE.md +416 -0
- maps4fs-2.9.2.dist-info/RECORD +0 -30
- maps4fs-2.9.2.dist-info/licenses/LICENSE.md +0 -651
- {maps4fs-2.9.2.dist-info → maps4fs-2.9.37.dist-info}/WHEEL +0 -0
- {maps4fs-2.9.2.dist-info → maps4fs-2.9.37.dist-info}/top_level.txt +0 -0
|
@@ -542,6 +542,17 @@ class GRLE(ImageComponent, XMLComponent):
|
|
|
542
542
|
|
|
543
543
|
for layer in texture_component.get_area_type_layers():
|
|
544
544
|
pixel_value = area_type_to_pixel_value(layer.area_type) # type: ignore
|
|
545
|
+
# * Not enabled for now.
|
|
546
|
+
# * If the layer is invisible, we need to draw the mask from the info layer.
|
|
547
|
+
# if layer.invisible:
|
|
548
|
+
# self.logger.debug("Processing invisible area type layer: %s.", layer.name)
|
|
549
|
+
# if layer.info_layer:
|
|
550
|
+
# self.logger.debug("Info layer available: %s.", layer.info_layer)
|
|
551
|
+
# weight_image = self.draw_invisible_layer_mask(layer, environment_size)
|
|
552
|
+
# else:
|
|
553
|
+
# self.logger.debug("No info layer available for layer: %s.", layer.name)
|
|
554
|
+
# continue
|
|
555
|
+
# else:
|
|
545
556
|
weight_image = self.get_resized_weight(layer, environment_size) # type: ignore
|
|
546
557
|
if weight_image is None:
|
|
547
558
|
self.logger.warning("Weight image for area type layer not found in %s.", layer.name)
|
|
@@ -562,6 +573,52 @@ class GRLE(ImageComponent, XMLComponent):
|
|
|
562
573
|
self.logger.debug("Environment InfoLayer PNG file saved: %s.", info_layer_environment_path)
|
|
563
574
|
self.preview_paths["environment"] = info_layer_environment_path
|
|
564
575
|
|
|
576
|
+
# def draw_invisible_layer_mask(self, layer: Layer, resize_to: int) -> np.ndarray:
|
|
577
|
+
# """Draw the mask for the invisible layer.
|
|
578
|
+
|
|
579
|
+
# Arguments:
|
|
580
|
+
# layer (Layer): The layer for which to draw the mask.
|
|
581
|
+
# resize_to (int): The size to which the mask should be resized.
|
|
582
|
+
|
|
583
|
+
# Returns:
|
|
584
|
+
# np.ndarray: The resized mask.
|
|
585
|
+
# """
|
|
586
|
+
# mask = np.zeros((self.map.size, self.map.size), dtype=np.uint8)
|
|
587
|
+
# polygons = self.get_infolayer_data(Parameters.TEXTURES, layer.info_layer)
|
|
588
|
+
# self.logger.debug("Found %d polygons in info layer %s.", len(polygons), layer.info_layer)
|
|
589
|
+
|
|
590
|
+
# for polygon in polygons:
|
|
591
|
+
# try:
|
|
592
|
+
# fitted_polygon = self.fit_object_into_bounds(
|
|
593
|
+
# polygon_points=polygon,
|
|
594
|
+
# # margin=self.map.grle_settings.farmland_margin,
|
|
595
|
+
# angle=self.rotation,
|
|
596
|
+
# )
|
|
597
|
+
# except ValueError as e:
|
|
598
|
+
# self.logger.debug(
|
|
599
|
+
# "Polygon could not be fitted into the map bounds with error: %s",
|
|
600
|
+
# e,
|
|
601
|
+
# )
|
|
602
|
+
# continue
|
|
603
|
+
# polygon_np = self.polygon_points_to_np(fitted_polygon)
|
|
604
|
+
|
|
605
|
+
# try:
|
|
606
|
+
# cv2.fillPoly(mask, [polygon_np], (float(255),)) # type: ignore
|
|
607
|
+
# except Exception as e:
|
|
608
|
+
# self.logger.debug(
|
|
609
|
+
# "Polygon could not be added to the mask with error: %s",
|
|
610
|
+
# e,
|
|
611
|
+
# )
|
|
612
|
+
# continue
|
|
613
|
+
|
|
614
|
+
# resized_mask = cv2.resize(
|
|
615
|
+
# mask,
|
|
616
|
+
# (resize_to, resize_to),
|
|
617
|
+
# interpolation=cv2.INTER_NEAREST,
|
|
618
|
+
# )
|
|
619
|
+
|
|
620
|
+
# return resized_mask
|
|
621
|
+
|
|
565
622
|
@monitor_performance
|
|
566
623
|
def get_resized_weight(
|
|
567
624
|
self, layer: Layer, resize_to: int, dilations: int = 3
|
|
@@ -12,13 +12,14 @@ import cv2
|
|
|
12
12
|
import numpy as np
|
|
13
13
|
from tqdm import tqdm
|
|
14
14
|
|
|
15
|
+
from maps4fs.generator.component.base.component_image import ImageComponent
|
|
15
16
|
from maps4fs.generator.component.base.component_xml import XMLComponent
|
|
16
17
|
from maps4fs.generator.monitor import monitor_performance
|
|
17
18
|
from maps4fs.generator.settings import Parameters
|
|
18
19
|
|
|
19
20
|
NODE_ID_STARTING_VALUE = 2000
|
|
20
21
|
SPLINES_NODE_ID_STARTING_VALUE = 5000
|
|
21
|
-
TREE_NODE_ID_STARTING_VALUE =
|
|
22
|
+
TREE_NODE_ID_STARTING_VALUE = 30000
|
|
22
23
|
|
|
23
24
|
FIELDS_ATTRIBUTES = [
|
|
24
25
|
("angle", "integer", "0"),
|
|
@@ -30,7 +31,7 @@ FIELDS_ATTRIBUTES = [
|
|
|
30
31
|
]
|
|
31
32
|
|
|
32
33
|
|
|
33
|
-
class I3d(XMLComponent):
|
|
34
|
+
class I3d(XMLComponent, ImageComponent):
|
|
34
35
|
"""Component for map i3d file settings and configuration.
|
|
35
36
|
|
|
36
37
|
Arguments:
|
|
@@ -690,9 +691,13 @@ class I3d(XMLComponent):
|
|
|
690
691
|
|
|
691
692
|
return recommended_step if not current_step else max(recommended_step, current_step)
|
|
692
693
|
|
|
693
|
-
def get_not_resized_dem(self) -> np.ndarray | None:
|
|
694
|
+
def get_not_resized_dem(self, with_foundations: bool = False) -> np.ndarray | None:
|
|
694
695
|
"""Reads the not resized DEM image from the background component.
|
|
695
696
|
|
|
697
|
+
Arguments:
|
|
698
|
+
with_foundations (bool, optional): Whether to get the DEM with foundations.
|
|
699
|
+
Defaults to False.
|
|
700
|
+
|
|
696
701
|
Returns:
|
|
697
702
|
np.ndarray | None: The not resized DEM image or None if the image could not be read.
|
|
698
703
|
"""
|
|
@@ -701,11 +706,60 @@ class I3d(XMLComponent):
|
|
|
701
706
|
self.logger.warning("Background component not found.")
|
|
702
707
|
return None
|
|
703
708
|
|
|
704
|
-
|
|
709
|
+
dem_path = (
|
|
710
|
+
background_component.not_resized_with_foundations_path
|
|
711
|
+
if with_foundations
|
|
712
|
+
else background_component.not_resized_path
|
|
713
|
+
)
|
|
714
|
+
|
|
715
|
+
if not dem_path or not os.path.isfile(dem_path):
|
|
705
716
|
self.logger.warning("Not resized DEM path not found.")
|
|
706
717
|
return None
|
|
707
718
|
|
|
708
|
-
not_resized_dem = cv2.imread(
|
|
719
|
+
not_resized_dem = cv2.imread(dem_path, cv2.IMREAD_UNCHANGED)
|
|
720
|
+
|
|
721
|
+
return not_resized_dem
|
|
722
|
+
|
|
723
|
+
def get_not_resized_dem_with_foundations(
|
|
724
|
+
self, allow_fallback: bool = False
|
|
725
|
+
) -> np.ndarray | None:
|
|
726
|
+
"""Gets the not resized DEM with foundations. If the DEM with foundations is not found
|
|
727
|
+
and allow_fallback is True, the method returns the not resized DEM without foundations.
|
|
728
|
+
|
|
729
|
+
Arguments:
|
|
730
|
+
allow_fallback (bool, optional): Whether to allow fallback to DEM without
|
|
731
|
+
foundations. Defaults to False.
|
|
732
|
+
|
|
733
|
+
Returns:
|
|
734
|
+
np.ndarray | None: The not resized DEM image or None if the image could not be read.
|
|
735
|
+
"""
|
|
736
|
+
dem_with_foundations = self.get_not_resized_dem(with_foundations=True)
|
|
737
|
+
|
|
738
|
+
if dem_with_foundations is not None:
|
|
739
|
+
return dem_with_foundations
|
|
740
|
+
self.logger.warning("Not resized DEM with foundations not found.")
|
|
741
|
+
if allow_fallback:
|
|
742
|
+
return self.get_not_resized_dem(with_foundations=False)
|
|
743
|
+
return None
|
|
744
|
+
|
|
745
|
+
def get_not_resized_dem_with_flattened_roads(self) -> np.ndarray | None:
|
|
746
|
+
"""Gets the not resized DEM with flattened roads.
|
|
747
|
+
|
|
748
|
+
Returns:
|
|
749
|
+
np.ndarray | None: The not resized DEM image or None if the image could not be read.
|
|
750
|
+
"""
|
|
751
|
+
background_component = self.map.get_background_component()
|
|
752
|
+
if not background_component:
|
|
753
|
+
self.logger.warning("Background component not found.")
|
|
754
|
+
return None
|
|
755
|
+
|
|
756
|
+
dem_path = background_component.not_resized_with_flattened_roads_path
|
|
757
|
+
|
|
758
|
+
if not dem_path or not os.path.isfile(dem_path):
|
|
759
|
+
self.logger.warning("Not resized DEM with flattened roads path not found.")
|
|
760
|
+
return None
|
|
761
|
+
|
|
762
|
+
not_resized_dem = cv2.imread(dem_path, cv2.IMREAD_UNCHANGED)
|
|
709
763
|
|
|
710
764
|
return not_resized_dem
|
|
711
765
|
|
|
@@ -21,6 +21,16 @@ class Layer:
|
|
|
21
21
|
usage (str | None): Usage of the layer.
|
|
22
22
|
background (bool): Flag to determine if the layer is a background.
|
|
23
23
|
invisible (bool): Flag to determine if the layer is invisible.
|
|
24
|
+
procedural (list[str] | None): List of procedural textures to apply.
|
|
25
|
+
border (int | None): Border size in pixels.
|
|
26
|
+
precise_tags (dict[str, str | list[str]] | None): Dictionary of precise tags to search for.
|
|
27
|
+
precise_usage (str | None): Precise usage of the layer.
|
|
28
|
+
area_type (str | None): Type of the area (e.g., residential, commercial).
|
|
29
|
+
area_water (bool): Flag to determine if the area is water.
|
|
30
|
+
indoor (bool): Flag to determine if the layer is indoor.
|
|
31
|
+
merge_into (str | None): Name of the layer to merge into.
|
|
32
|
+
building_category (str | None): Category of the building.
|
|
33
|
+
external (bool): External layers not being used by the game directly.
|
|
24
34
|
|
|
25
35
|
Attributes:
|
|
26
36
|
name (str): Name of the layer.
|
|
@@ -50,6 +60,9 @@ class Layer:
|
|
|
50
60
|
area_water: bool = False,
|
|
51
61
|
indoor: bool = False,
|
|
52
62
|
merge_into: str | None = None,
|
|
63
|
+
building_category: str | None = None,
|
|
64
|
+
external: bool = False,
|
|
65
|
+
road_texture: str | None = None,
|
|
53
66
|
):
|
|
54
67
|
self.name = name
|
|
55
68
|
self.count = count
|
|
@@ -70,6 +83,9 @@ class Layer:
|
|
|
70
83
|
self.area_water = area_water
|
|
71
84
|
self.indoor = indoor
|
|
72
85
|
self.merge_into = merge_into
|
|
86
|
+
self.building_category = building_category
|
|
87
|
+
self.external = external
|
|
88
|
+
self.road_texture = road_texture
|
|
73
89
|
|
|
74
90
|
def to_json(self) -> dict[str, str | list[str] | bool]: # type: ignore
|
|
75
91
|
"""Returns dictionary with layer data.
|
|
@@ -96,6 +112,9 @@ class Layer:
|
|
|
96
112
|
"area_water": self.area_water,
|
|
97
113
|
"indoor": self.indoor,
|
|
98
114
|
"merge_into": self.merge_into,
|
|
115
|
+
"building_category": self.building_category,
|
|
116
|
+
"external": self.external,
|
|
117
|
+
"road_texture": self.road_texture,
|
|
99
118
|
}
|
|
100
119
|
|
|
101
120
|
data = {k: v for k, v in data.items() if v is not None}
|