from dataclasses import dataclass import os from returns.result import Result, Success, Failure from typing import Optional, Any, List, TypeVar, Callable, Type, cast from enum import Enum from repository.file_system import FileSystemRepository T = TypeVar("T") EnumT = TypeVar("EnumT", bound=Enum) def from_float(x: Any) -> float: assert isinstance(x, (float, int)) and not isinstance(x, bool) return float(x) def from_none(x: Any) -> Any: return x def from_union(fs, x): for f in fs: try: return f(x) except: pass assert False def to_float(x: Any) -> float: assert isinstance(x, float) return x def from_str(x: Any) -> str: assert isinstance(x, str) return x def from_int(x: Any) -> int: assert isinstance(x, int) and not isinstance(x, bool) return x def from_list(f: Callable[[Any], T], x: Any) -> List[T]: assert isinstance(x, list) return [f(y) for y in x] def to_class(c: Type[T], x: Any) -> dict: assert isinstance(x, c) return cast(Any, x).to_dict() def to_enum(c: Type[EnumT], x: Any) -> EnumT: assert isinstance(x, c) return x.value @dataclass class Model: name: Optional[str] = None id: Optional[str] = None path: Optional[str] = None @staticmethod def from_dict(obj: Any) -> "Model": assert isinstance(obj, dict) name = from_union([from_str, from_none], obj.get("name")) id = from_union([from_str, from_none], obj.get("id")) path = from_union([from_str, from_none], obj.get("path")) return Model(name, id, path) def to_dict(self) -> dict: result: dict = {} if self.name is not None: result["name"] = from_union([from_str, from_none], self.name) if self.id is not None: result["id"] = from_union([from_str, from_none], self.id) if self.path is not None: result["path"] = from_union([from_str, from_none], self.path) return result @dataclass class Pose: x: Optional[float] = None y: Optional[float] = None z: Optional[float] = None roll: Optional[float] = None pitch: Optional[float] = None yaw: Optional[float] = None @staticmethod def from_dict(obj: Any) -> "Pose": assert isinstance(obj, dict) x = from_union([from_float, from_none], obj.get("x")) y = from_union([from_float, from_none], obj.get("y")) z = from_union([from_float, from_none], obj.get("z")) roll = from_union([from_float, from_none], obj.get("roll")) pitch = from_union([from_float, from_none], obj.get("pitch")) yaw = from_union([from_float, from_none], obj.get("yaw")) return Pose(x, y, z, roll, pitch, yaw) def to_dict(self) -> dict: result: dict = {} if self.x is not None: result["x"] = from_union([to_float, from_none], self.x) if self.y is not None: result["y"] = from_union([to_float, from_none], self.y) if self.z is not None: result["z"] = from_union([to_float, from_none], self.z) if self.roll is not None: result["roll"] = from_union([to_float, from_none], self.roll) if self.pitch is not None: result["pitch"] = from_union([to_float, from_none], self.pitch) if self.yaw is not None: result["yaw"] = from_union([to_float, from_none], self.yaw) return result class TypeEnum(Enum): ASSET = "asset" LIGHT = "light" @dataclass class Instance: model_name: Optional[str] = None model_id: Optional[str] = None id: Optional[str] = None pose: Optional[Pose] = None scale: Optional[int] = None type: Optional[TypeEnum] = None parent: Optional[str] = None light_type: Optional[str] = None intencity: Optional[int] = None diffuse: Optional[List[float]] = None spot_angle: Optional[int] = None @staticmethod def from_dict(obj: Any) -> "Instance": assert isinstance(obj, dict) model_name = from_union([from_str, from_none], obj.get("model_name")) model_id = from_union([from_str, from_none], obj.get("model_id")) id = from_union([from_str, from_none], obj.get("id")) pose = from_union([Pose.from_dict, from_none], obj.get("pose")) scale = from_union([from_int, from_none], obj.get("scale")) type = from_union([TypeEnum, from_none], obj.get("type")) parent = from_union([from_str, from_none], obj.get("parent")) light_type = from_union([from_str, from_none], obj.get("light_type")) intencity = from_union([from_int, from_none], obj.get("intencity")) diffuse = from_union( [lambda x: from_list(from_float, x), from_none], obj.get("diffuse") ) spot_angle = from_union([from_int, from_none], obj.get("spot_angle")) return Instance( model_name, model_id, id, pose, scale, type, parent, light_type, intencity, diffuse, spot_angle, ) def fromMappingInstanceAtModel( self, models: List[Model] ) -> "MappingInstanceAtModel": for el in models: if el.id == self.model_id: return MappingInstanceAtModel(instance=self, model=el) return Failure("not found model at {self.model_id} ") def to_dict(self) -> dict: result: dict = {} if self.model_name is not None: result["model_name"] = from_union([from_str, from_none], self.model_name) if self.model_id is not None: result["model_id"] = from_union([from_str, from_none], self.model_id) if self.id is not None: result["id"] = from_union([from_str, from_none], self.id) if self.pose is not None: result["pose"] = from_union( [lambda x: to_class(Pose, x), from_none], self.pose ) if self.scale is not None: result["scale"] = from_union([from_int, from_none], self.scale) if self.type is not None: result["type"] = from_union( [lambda x: to_enum(TypeEnum, x), from_none], self.type ) if self.parent is not None: result["parent"] = from_union([from_str, from_none], self.parent) if self.light_type is not None: result["light_type"] = from_union([from_str, from_none], self.light_type) if self.intencity is not None: result["intencity"] = from_union([from_int, from_none], self.intencity) if self.diffuse is not None: result["diffuse"] = from_union( [lambda x: from_list(to_float, x), from_none], self.diffuse ) if self.spot_angle is not None: result["spot_angle"] = from_union([from_int, from_none], self.spot_angle) return result class BasePose: def __init__(self, x: float, y: float, z: float, **kwargs): self.x = x self.y = y self.z = z def toPose(self, sdfXmlMock: str): return ( sdfXmlMock.replace("{x}", str(self.x)) .replace("{y}", str(self.y)) .replace("{z}", str(self.z)) ) class MappingInstanceAtModel(BasePose): instance: Instance model: Model def __init__(self, instance: Instance, model: Model) -> None: self.instance = instance self.model = model pass def toSDF(self): pose = self.instance.pose match self.instance.type: case TypeEnum.ASSET: mock = FileSystemRepository.readFile( os.path.dirname(os.path.realpath(__file__)) + "/../mocks/model_include_sdf.xml" ) # mockPose = self.toPose(mock) return ( mock.replace("{name}", str(self.model.name)) .replace("{x}", str(pose.x)) .replace("{y}", str(pose.y)) .replace("{z}", str(pose.z)) .replace("{pitch}", str(pose.pitch)) .replace("{yaw}", str(pose.yaw)) .replace("{roll}", str(pose.roll)) .replace("{uri}", str(self.model.path)) ) case TypeEnum.LIGHT: pathMock = ( os.path.dirname(os.path.realpath(__file__)) + "/../mocks/light_sdf.xml" ) return ( FileSystemRepository.readFile(pathMock) .replace("{x}", str(pose.x)) .replace("{y}", str(pose.y)) .replace("{z}", str(pose.z)) .replace("{pitch}", str(pose.pitch)) .replace("{yaw}", str(pose.yaw)) .replace("{roll}", str(pose.roll)) .replace("{type_light}", str(self.instance.light_type)) .replace("{name_light}", str("132")) .replace("{r}", self.instance.diffuse[0]) .replace("{g}", self.instance.diffuse[1]) .replace("{b}", self.instance.diffuse[2]) .replace("{a}", self.instance.diffuse[3]) ) @dataclass class Gravity: x: Optional[int] = None y: Optional[int] = None z: Optional[float] = None @staticmethod def from_dict(obj: Any) -> "Gravity": assert isinstance(obj, dict) x = from_union([from_int, from_none], obj.get("x")) y = from_union([from_int, from_none], obj.get("y")) z = from_union([from_float, from_none], obj.get("z")) return Gravity(x, y, z) def to_dict(self) -> dict: result: dict = {} if self.x is not None: result["x"] = from_union([from_int, from_none], self.x) if self.y is not None: result["y"] = from_union([from_int, from_none], self.y) if self.z is not None: result["z"] = from_union([to_float, from_none], self.z) return result @dataclass class Physics: engine_name: Optional[str] = None gravity: Optional[Gravity] = None @staticmethod def from_dict(obj: Any) -> "Physics": assert isinstance(obj, dict) engine_name = from_union([from_str, from_none], obj.get("engine_name")) gravity = from_union([Gravity.from_dict, from_none], obj.get("gravity")) return Physics(engine_name, gravity) def to_dict(self) -> dict: result: dict = {} if self.engine_name is not None: result["engine_name"] = from_union([from_str, from_none], self.engine_name) if self.gravity is not None: result["gravity"] = from_union( [lambda x: to_class(Gravity, x), from_none], self.gravity ) return result def toSDF(self) -> str: pathMock = os.path.dirname(os.path.realpath(__file__)) + "/../mocks/world.xml" gravity = self.gravity return ( FileSystemRepository.readFile(pathMock) .replace("{gravity_x}", str(gravity.x)) .replace("{gravity_y}", str(gravity.y)) .replace("{gravity_z}", str(gravity.z)) .replace("{engine_type}", str(self.engine_name)) ) @dataclass class RobossemblerAssets: models: Optional[List[Model]] = None instances: Optional[List[Instance]] = None physics: Optional[Physics] = None @staticmethod def from_dict(obj: Any) -> "RobossemblerAssets": assert isinstance(obj, dict) models = from_union( [lambda x: from_list(Model.from_dict, x), from_none], obj.get("models") ) instances = from_union( [lambda x: from_list(Instance.from_dict, x), from_none], obj.get("instances"), ) physics = from_union([Physics.from_dict, from_none], obj.get("physics")) return RobossemblerAssets(models, instances, physics) def to_dict(self) -> dict: result: dict = {} if self.models is not None: result["models"] = from_union( [lambda x: from_list(lambda x: to_class(Model, x), x), from_none], self.models, ) if self.instances is not None: result["instances"] = from_union( [lambda x: from_list(lambda x: to_class(Instance, x), x), from_none], self.instances, ) if self.physics is not None: result["physics"] = from_union( [lambda x: to_class(Physics, x), from_none], self.physics ) return result def _getAllAtType(self, type: TypeEnum) -> List[Instance]: return list(filter(lambda x: x.type == type, self.instances)) def getAllLightInstances(self) -> List[Instance]: return list( map( lambda el: el.fromMappingInstanceAtModel(self.models), self._getAllAtType(type=TypeEnum.LIGHT), ) ) def getAllAssetsInstanceAtModel(self) -> List[MappingInstanceAtModel]: return list( map( lambda el: el.fromMappingInstanceAtModel(self.models), self._getAllAtType(type=TypeEnum.ASSET), ) )