Source code for skbot.ignition.sdformat.generic_sdf.sdf

"""<element name="sdf" required="1">
  <description>SDFormat base element that can include one model, actor, light, or worlds. A user of multiple worlds could run parallel instances of simulation, or offer selection of a world at runtime.</description>

  <attribute name="version" type="string" default="1.8" required="1">
    <description>Version number of the SDFormat specification.</description>
  </attribute>

  <include filename="world.sdf" required="*"/>
  <include filename="model.sdf" required="0"/>
  <include filename="actor.sdf" required="0"/>
  <include filename="light.sdf" required="0"/>

</element> <!-- End SDF -->"""

from typing import List, Union, Dict, Any, Tuple
import warnings

from .base import ElementBase
from .world import World
from .actor import Actor
from .model import Model
from .light import Light
from ..exceptions import ParseError
from .... import transform as tf


[docs]class Sdf(ElementBase): """SDFormat Root Element This element is a container for multiple simulation worlds (can be one) or for a single fragment of a world (Model, Actor, Light). Parameters ---------- payload : Union[List[World], Model, Light, Actor] The element contained in this SDF. This can be one :class:`Model`, one :class:`Actor`, one :class:`Light`, or a list of :class:`Worlds`. version : str The SDFormat version. worlds : List[World] The worlds contained in this SDF. .. deprecated:: SDFormat v1.8 Worlds, models, lights, and/or actors can no longer be combined. Use `payload` instead. models : List[Model] .. deprecated:: SDFormat v1.8 Starting with SDFormat v1.8 only a single model is supported. Use the `model` kwarg instead. The models contained in this SDF. lights : List[Light] .. deprecated:: SDFormat v1.8 Starting with SDFormat v1.8 only a single light is supported. Use the `light` kwarg instead. The lights contained in this SDF. actors : List[Actor] .. deprecated:: SDFormat v1.8 Starting with SDFormat v1.8 only a single actor is supported. Use the `actor` kwarg instead. The actors contained in this SDF. Attributes ---------- worlds : List[World] The worlds contained in the SDF file. model: Model The model contained in the SDF file. light: Light The light contained in the SDF file. actor: Actor The actor contained in the SDF file. version : str The SDFormat version. models : List[Model] .. deprecated:: SDFormat v1.8 Use the `Sdf.model` instead. lights : List[Light] .. deprecated:: SDFormat v1.8 Use the `Sdf.light` instead. actors : List[Actor] .. deprecated:: SDFormat v1.8 Use the `Sdf.actor` instead. """
[docs] def __init__( self, *, payload: Union[List[World], Model, Light, Actor] = None, version: str = "1.8", worlds: List[World] = None, models: List[Model] = None, lights: List[Light] = None, actors: List[Actor] = None, ) -> None: super().__init__(sdf_version=version) self.version = version self.worlds: List[World] = [] self._actors: List[Actor] = [] self._models: List[Model] = [] self._lights: List[Light] = [] if self.sdf_version == "1.8": if isinstance(payload, list) and all( [isinstance(x, World) for x in payload] ): self.worlds = payload elif isinstance(payload, Actor): self._actors.append(payload) elif isinstance(payload, Model): self._models.append(payload) elif isinstance(payload, Light): self._lights.append(payload) else: raise ParseError("Invalid `Sdf` element.") elif version in ["1.7", "1.6", "1.5", "1.4", "1.3"]: self.worlds.extend(worlds) self._models.extend(models) self._lights.extend(lights) self._actors.extend(actors) else: raise ParseError("`Sdf` does not exist prior to SDFormat v1.3.") for model in self._models: if model.pose.relative_to is None: model.pose.relative_to = "world"
@property def actor(self) -> Actor: try: return self._actors[0] except IndexError: return None @property def model(self) -> Model: try: return self._models[0] except IndexError: return None @property def light(self) -> Light: try: return self._lights[0] except IndexError: return None # deprecated properties @property def actors(self) -> List[Actor]: warnings.warn( "`sdf.actors` is deprecated since SDFormat v1.8. Use `sdf.actor` instead.", DeprecationWarning, ) return self._actors @property def models(self) -> List[Model]: warnings.warn( "`sdf.models` is deprecated since SDFormat v1.8. Use `sdf.models` instead.", DeprecationWarning, ) return self._models @property def lights(self) -> List[Light]: warnings.warn( "`sdf.lights` is deprecated since SDFormat v1.8. Use `sdf.lights` instead.", DeprecationWarning, ) return self._lights @classmethod def from_specific(cls, sdf: Any, *, version: str) -> "Sdf": """Create a generic Sdf object from a specific one. Parameters ---------- sdf : Any The SDF object that should be turned into a generic object. It can come from any version of the specific SDFormat bindings provided by scikit-bot. version : str The version of the given SDF element. Returns ------- generic_sdf : Sdf The generic equivalent of the provided specific Sdf object. """ if version == "1.8": payload: Union[List[World], Model, Light, Actor] if sdf.world is not None and len(sdf.world) > 0: payload = [World.from_specific(x, version=version) for x in sdf.world] elif sdf.actor is not None: payload = Actor.from_specific(sdf.actor, version=version) elif sdf.model is not None: payload = Model.from_specific(sdf.model, version=version) elif sdf.light is not None: payload = Light.from_specific(sdf.light, version=version) else: raise ParseError("Can not convert `sdf` element without payload.") return Sdf(payload=payload, version=version) else: return Sdf( worlds=[World.from_specific(x, version=version) for x in sdf.world], actors=[Actor.from_specific(x, version=version) for x in sdf.actor], models=[Model.from_specific(x, version=version) for x in sdf.model], lights=[Light.from_specific(x, version=version) for x in sdf.light], version=version, ) def declared_frames( self, ) -> Dict[str, Union[List[Dict[str, tf.Frame]], Dict[str, tf.Frame]]]: declared_frames = { "worlds": [x.declared_frames() for x in self.worlds], "models": [x.declared_frames() for x in self._models], } if self.model is not None: declared_frames["model"] = declared_frames["models"][0] return declared_frames def to_static_graph( self, declared_frames: Dict[str, List[tf.Frame]], *, seed: int = None, shape: Tuple[int] = (3,), axis: int = -1, ) -> Dict[str, List[tf.Frame]]: graphs = { "worlds": list(), "models": list(), } for idx, world in enumerate(self.worlds): try: static_frames = declared_frames["worlds"][idx] except IndexError: break root = world.to_static_graph( static_frames, seed=seed, shape=shape, axis=axis ) graphs["worlds"].append(root) for idx, model in enumerate(self._models): try: static_frames = declared_frames["models"][idx] except IndexError: break if "world" not in static_frames: static_frames["world"] = tf.Frame(3, name="world") root = model.to_static_graph( static_frames, seed=seed, shape=shape, axis=axis ) graphs["models"].append(root) model.pose.to_static_graph( static_frames, "__model__", shape=shape, axis=axis ) return graphs def to_dynamic_graph( self, declared_frames: Dict[str, List[tf.Frame]], *, seed: int = None, shape: Tuple[int] = (3,), axis: int = -1, apply_state: bool = True, ) -> Dict[str, List[tf.Frame]]: graphs = { "worlds": list(), "models": list(), } scaffold = self.declared_frames() self.to_static_graph(scaffold, seed=seed, shape=shape, axis=axis) for idx, world in enumerate(self.worlds): try: frames = declared_frames["worlds"][idx] except IndexError: break root = world.to_dynamic_graph(frames, seed=seed, shape=shape, axis=axis) graphs["worlds"].append(root) for idx, model in enumerate(self._models): try: frames = declared_frames["models"][idx] except IndexError: break static_frames = scaffold["models"][idx] if "world" not in frames: frames["world"] = tf.Frame(3, name="world") root = model.to_dynamic_graph( frames, seed=seed, shape=shape, axis=axis, _scaffolding=static_frames ) graphs["models"].append(root) return graphs