Source code for embodichain.lab.sim.shapes
# ----------------------------------------------------------------------------
# Copyright (c) 2021-2025 DexForce Technology Co., Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ----------------------------------------------------------------------------
from __future__ import annotations
from typing import Optional, List, Dict, Union, TYPE_CHECKING, Any
from dataclasses import MISSING
from embodichain.utils import configclass, is_configclass, logger
if TYPE_CHECKING:
from embodichain.lab.sim.material import VisualMaterialCfg
[docs]
@configclass
class LoadOption:
rebuild_normals: bool = False
"""Whether to rebuild normals for the shape. Defaults to False."""
rebuild_tangent: bool = False
"""Whether to rebuild tangents for the shape. Defaults to False."""
rebuild_3rdnormal: bool = False
"""Whether to rebuild the normal for the shape using 3rd party library. Defaults to False."""
rebuild_3rdtangent: bool = False
"""Whether to rebuild the tangent for the shape using 3rd party library. Defaults to False."""
smooth: float = -1.0
"""Angle threshold (in degrees) for smoothing normals. Defaults to -1.0 (no smoothing)."""
[docs]
@classmethod
def from_dict(cls, init_dict: Dict[str, Any]) -> LoadOption:
"""Initialize the configuration from a dictionary."""
cfg = cls()
for key, value in init_dict.items():
if hasattr(cfg, key):
setattr(cfg, key, value)
else:
logger.log_warning(
f"Key '{key}' not found in {cfg.__class__.__name__}."
)
return cfg
[docs]
@configclass
class ShapeCfg:
shape_type: str = MISSING
"""Type of the shape. Must be specified in subclasses."""
visual_material: Optional[VisualMaterialCfg] = None
"""Configuration parameters for the visual material of the shape. Defaults to None."""
[docs]
@classmethod
def from_dict(cls, init_dict: Dict[str, Any]) -> ShapeCfg:
"""Initialize the configuration from a dictionary."""
from embodichain.utils.utility import get_class_instance
if "shape_type" not in init_dict:
logger.log_error("shape type must be specified in the configuration.")
cfg = get_class_instance(
"embodichain.lab.sim.shapes", init_dict["shape_type"] + "Cfg"
)()
for key, value in init_dict.items():
if hasattr(cfg, key):
attr = getattr(cfg, key)
if key == "visual_material" and isinstance(value, dict):
setattr(
cfg,
key,
VisualMaterialCfg.from_dict(value),
)
elif is_configclass(attr):
setattr(cfg, key, attr.from_dict(value))
else:
setattr(cfg, key, value)
else:
logger.log_warning(
f"Key '{key}' not found in {cfg.__class__.__name__}."
)
return cfg
[docs]
@configclass
class MeshCfg(ShapeCfg):
"""Configuration parameters for a triangle mesh shape."""
shape_type: str = "Mesh"
fpath: str = MISSING
"""File path to the shape mesh file."""
load_option: LoadOption = LoadOption()
"""Options for loading and processing the shape."""
compute_uv: bool = False
"""Whether to compute UV coordinates for the shape. Defaults to False.
If the shape already has UV coordinates, setting this to True will recompute and overwrite them.
"""
project_direction: List[float] = [1.0, 1.0, 1.0]
"""Direction to project the UV coordinates. Defaults to [1.0, 1.0, 1.0]."""
[docs]
@configclass
class CubeCfg(ShapeCfg):
"""Configuration parameters for a cube shape."""
shape_type: str = "Cube"
size: List[float] = [1.0, 1.0, 1.0]
"""Size of the cube (in m) as [length, width, height]."""
[docs]
@configclass
class SphereCfg(ShapeCfg):
"""Configuration parameters for a sphere shape."""
shape_type: str = "Sphere"
radius: float = 1.0
"""Radius of the sphere (in m)."""
resolution: int = 20
"""Resolution of the sphere mesh. Defaults to 20."""