Repository: Genesis-Embodied-AI/Genesis
File: genesis/options/morphs.py (Python)

Code before:
        The name of the terrain to save
    from_stored : str, optional
        The path of the stored terrain to load
    subterrain_parameters : dictionary, optional
        Lets users pick their own subterrain parameters.
    """

    is_free: bool = False
    randomize: bool = False  # whether to randomize the terrain
    n_subterrains: Tuple[int, int] = (3, 3)  # number of subterrains in x and y directions
    subterrain_size: Tuple[float, float] = (12.0, 12.0)  # meter
    horizontal_scale: float = 0.25  # meter size of each cell in the subterrain
    vertical_scale: float = 0.005  # meter height of each step in the subterrain
    subterrain_types: Any = [
        ["flat_terrain", "random_uniform_terrain", "stepping_stones_terrain"],
        ["pyramid_sloped_terrain", "discrete_obstacles_terrain", "wave_terrain"],
        ["random_uniform_terrain", "pyramid_stairs_terrain", "sloped_terrain"],
    ]
    height_field: Any = None
    name: str = "default"  # name to store and reuse the terrain
    from_stored: Any = None
    subterrain_parameters: dict[str, dict] | None = None

    def __init__(self, **data):
        custom_params = data.get("subterrain_parameters") or {}
        keys = set(self.default_params) | set(custom_params)
        effective_params = {}

        for key in keys:
            default_value = self.default_params.get(key, {})
            custom_value = custom_params.get(key, {})
            effective_params[key] = default_value | custom_value

        data["subterrain_parameters"] = effective_params
        super().__init__(**data)

        self._subterrain_parameters = effective_params

        supported_subterrain_types = [
            "flat_terrain",
            "fractal_terrain",
            "random_uniform_terrain",
            "sloped_terrain",
            "pyramid_sloped_terrain",
            "discrete_obstacles_terrain",
            "wave_terrain",
            "stairs_terrain",
            "pyramid_stairs_terrain",
            "stepping_stones_terrain",
        ]


Review comment (suggestion):
Not great but acceptable now. Avoid creating all these temporaries and use them directly, this would be cleaner I think. `key` is still not a great name, and `effective` is weird (custom or overwritten would be more common). But now it is ok.

Code after:
        The size of each cell in the subterrain in meters. Defaults to 0.25.
    vertical_scale : float, optional
        The height of each step in the subterrain in meters. Defaults to 0.005.
    subterrain_types : str or 2D list of str, optional
        The types of subterrains to generate. If a string, it will be repeated for all subterrains. If a 2D list, it should have the same shape as `n_subterrains`.
    height_field : array-like, optional
        The height field to generate the terrain. If specified, all other configurations will be ignored. Defaults to None.
    name : str, optional
        The name of the terrain to save
    from_stored : str, optional
        The path of the stored terrain to load
    subterrain_parameters : dictionary, optional
        Lets users pick their own subterrain parameters.
    """

    is_free: bool = False
    randomize: bool = False  # whether to randomize the terrain
    n_subterrains: Tuple[int, int] = (3, 3)  # number of subterrains in x and y directions
    subterrain_size: Tuple[float, float] = (12.0, 12.0)  # meter
    horizontal_scale: float = 0.25  # meter size of each cell in the subterrain
    vertical_scale: float = 0.005  # meter height of each step in the subterrain
    subterrain_types: Any = [
        ["flat_terrain", "random_uniform_terrain", "stepping_stones_terrain"],
        ["pyramid_sloped_terrain", "discrete_obstacles_terrain", "wave_terrain"],
        ["random_uniform_terrain", "pyramid_stairs_terrain", "sloped_terrain"],
    ]
    height_field: Any = None
    name: str = "default"  # name to store and reuse the terrain
    from_stored: Any = None
    subterrain_parameters: dict[str, dict] | None = None

    def __init__(self, **data):
        custom_params = data.get("subterrain_parameters") or {}
        terrain_types = set(self.default_params) | set(custom_params)
        overwritten_params = {}

        for terrain_type in terrain_types:
            default_value = self.default_params.get(terrain_type, {})
            custom_value = custom_params.get(terrain_type, {})
            overwritten_params[terrain_type] = default_value | custom_value

        data["subterrain_parameters"] = overwritten_params
        super().__init__(**data)

        self._subterrain_parameters = overwritten_params

        supported_subterrain_types = [
            "flat_terrain",
            "fractal_terrain",
            "random_uniform_terrain",
            "sloped_terrain",