From 98353081035d7f1075892d3a28f994a1cc1d97ec Mon Sep 17 00:00:00 2001 From: Stan Soldatov Date: Tue, 7 Jan 2025 19:16:22 +0100 Subject: [PATCH] Select base grass. --- maps4fs/generator/background.py | 23 ----------------------- maps4fs/generator/component.py | 23 +++++++++++++++++++++++ maps4fs/generator/grle.py | 33 ++++++++++++++++++++++++++------- maps4fs/generator/i3d.py | 5 +---- maps4fs/generator/settings.py | 1 + webui/generator.py | 2 ++ webui/templates.py | 1 + 7 files changed, 54 insertions(+), 34 deletions(-) diff --git a/maps4fs/generator/background.py b/maps4fs/generator/background.py index 894c810..e60df67 100644 --- a/maps4fs/generator/background.py +++ b/maps4fs/generator/background.py @@ -393,29 +393,6 @@ def plane_from_np( mesh.apply_scale([0.5, 0.5, 0.5]) self.mesh_to_stl(mesh) - def get_z_scaling_factor(self) -> float: - """Calculates the scaling factor for the Z axis based on the map settings. - - Returns: - float -- The scaling factor for the Z axis. - """ - - scaling_factor = 1 / self.map.dem_settings.multiplier - self.logger.debug("Z scaling factor including DEM multiplier: %s", scaling_factor) - - if self.map.shared_settings.height_scale_multiplier: - scaling_factor *= self.map.shared_settings.height_scale_multiplier - self.logger.debug( - "Z scaling factor including height scale multiplier: %s", scaling_factor - ) - if self.map.shared_settings.mesh_z_scaling_factor: - scaling_factor *= 1 / self.map.shared_settings.mesh_z_scaling_factor - self.logger.debug( - "Z scaling factor including mesh z scaling factor: %s", scaling_factor - ) - - return scaling_factor - def mesh_to_stl(self, mesh: trimesh.Trimesh) -> None: """Converts the mesh to an STL file and saves it in the previews directory. Uses powerful simplification to reduce the size of the file since it will be used diff --git a/maps4fs/generator/component.py b/maps4fs/generator/component.py index 0277f1b..60c0eb6 100644 --- a/maps4fs/generator/component.py +++ b/maps4fs/generator/component.py @@ -535,3 +535,26 @@ def interpolate_points( interpolated_polyline.append(polyline[-1]) return interpolated_polyline + + def get_z_scaling_factor(self) -> float: + """Calculates the scaling factor for the Z axis based on the map settings. + + Returns: + float -- The scaling factor for the Z axis. + """ + + scaling_factor = 1 / self.map.dem_settings.multiplier + self.logger.debug("Z scaling factor including DEM multiplier: %s", scaling_factor) + + if self.map.shared_settings.height_scale_multiplier: + scaling_factor *= self.map.shared_settings.height_scale_multiplier + self.logger.debug( + "Z scaling factor including height scale multiplier: %s", scaling_factor + ) + if self.map.shared_settings.mesh_z_scaling_factor: + scaling_factor *= 1 / self.map.shared_settings.mesh_z_scaling_factor + self.logger.debug( + "Z scaling factor including mesh z scaling factor: %s", scaling_factor + ) + + return scaling_factor diff --git a/maps4fs/generator/grle.py b/maps4fs/generator/grle.py index ea3b1a0..23d85f9 100644 --- a/maps4fs/generator/grle.py +++ b/maps4fs/generator/grle.py @@ -19,6 +19,23 @@ ISLAND_ROUNDING_RADIUS = 15 +def plant_to_pixel_value(plant_name: str) -> int | None: + """Returns the pixel value representation of the plant. + If not found, returns None. + + Arguments: + plant_name (str): name of the plant + + Returns: + int | None: pixel value of the plant or None if not found. + """ + plants = { + "smallDenseMix": 33, + "meadow": 131, + } + return plants.get(plant_name) + + # pylint: disable=W0223 class GRLE(Component): """Component for to generate InfoLayer PNG files based on GRLE schema. @@ -324,10 +341,13 @@ def _add_plants(self) -> None: grass_image[forest_image != 0] = 255 # B and G channels remain the same (zeros), while we change the R channel. - possible_R_values = [33, 65, 97, 129, 161, 193, 225] # pylint: disable=C0103 + possible_R_values = [65, 97, 129, 161, 193, 225] # pylint: disable=C0103 - # 1st approach: Change the non zero values in the base image to 33 (for debug). - # And use the base image as R channel in the density map. + base_layer_pixel_value = plant_to_pixel_value( + self.map.grle_settings.base_grass # type:ignore + ) + if not base_layer_pixel_value: + base_layer_pixel_value = 131 # pylint: disable=no-member def create_island_of_plants(image: np.ndarray, count: int) -> np.ndarray: @@ -409,9 +429,9 @@ def get_rounded_polygon( grass_image_copy = grass_image.copy() if forest_image is not None: # Add the forest layer to the base image, to merge the masks. - grass_image_copy[forest_image != 0] = 33 - # Set all the non-zero values to 33. - grass_image_copy[grass_image != 0] = 33 + grass_image_copy[forest_image != 0] = base_layer_pixel_value + + grass_image_copy[grass_image != 0] = base_layer_pixel_value # Add islands of plants to the base image. island_count = self.map_size @@ -434,7 +454,6 @@ def get_rounded_polygon( grass_image_copy[:, 0] = 0 # Left side grass_image_copy[:, -1] = 0 # Right side - # Value of 33 represents the base grass plant. # After painting it with base grass, we'll create multiple islands of different plants. # On the final step, we'll remove all the values which in pixels # where zerons in the original base image (so we don't paint grass where it should not be). diff --git a/maps4fs/generator/i3d.py b/maps4fs/generator/i3d.py index a5d0995..8565480 100644 --- a/maps4fs/generator/i3d.py +++ b/maps4fs/generator/i3d.py @@ -15,12 +15,9 @@ from maps4fs.generator.texture import Texture DISPLACEMENT_LAYER_SIZE_FOR_BIG_MAPS = 32768 -DEFAULT_MAX_LOD_DISTANCE = 10000 -DEFAULT_MAX_LOD_OCCLUDER_DISTANCE = 10000 NODE_ID_STARTING_VALUE = 2000 SPLINES_NODE_ID_STARTING_VALUE = 5000 TREE_NODE_ID_STARTING_VALUE = 10000 -DEFAULT_FOREST_DENSITY = 10 # pylint: disable=R0903 @@ -248,7 +245,7 @@ def _add_splines(self) -> None: y = max(0, min(y, dem_y_size - 1)) z = not_resized_dem[y, x] - z /= 32 # Yes, it's a magic number here. + z *= self.get_z_scaling_factor() # type: ignore cv_node = ET.Element("cv") cv_node.set("c", f"{cx}, {z}, {cy}") diff --git a/maps4fs/generator/settings.py b/maps4fs/generator/settings.py index 5f1a710..36ecb0a 100644 --- a/maps4fs/generator/settings.py +++ b/maps4fs/generator/settings.py @@ -121,6 +121,7 @@ class GRLESettings(SettingsModel): farmland_margin: int = 0 random_plants: bool = True add_farmyards: bool = False + base_grass: tuple | str = ("smallDenseMix", "meadow") class I3DSettings(SettingsModel): diff --git a/webui/generator.py b/webui/generator.py index 2437689..6162e8a 100644 --- a/webui/generator.py +++ b/webui/generator.py @@ -203,6 +203,8 @@ def _create_widget( ) elif type(value) is bool: return st.checkbox(label=field_name, value=value, key=raw_field_name, disabled=disabled) + elif type(value) is tuple: + return st.selectbox(label=field_name, options=value) else: raise ValueError(f"Unsupported type of the value: {type(value)}") diff --git a/webui/templates.py b/webui/templates.py index a78dcff..50be3f3 100644 --- a/webui/templates.py +++ b/webui/templates.py @@ -178,6 +178,7 @@ class Settings: "corresponding field. It can be useful if you want to add some farmland in the " "regions without fields." ) + BASE_GRASS = "Select the plant that will be used as a base grass." # I3D Settings