Source code for myoconverter.xml.bodies.Ground

""" Contains the Ground parser.

@author: Aleksi Ikkala
"""

from scipy.spatial.transform import Rotation
from lxml import etree
import os

from myoconverter.xml.parsers import IParser
from myoconverter.xml import config as cfg
from myoconverter.xml.utils import vec2str
from myoconverter.xml.bodies.utils import get_rgba, copy_mesh_file


[docs]class Ground(IParser): """ This class parses and converts the OpenSim `Ground` XML element to MuJoCo. """
[docs] def parse(self, xml, add_ground_geom=False): """ This function handles the actual parsing and converting. :param xml: OpenSim `Ground` XML element :param add_ground_geom: Boolean to indicate whether a "ground" plane geom should be added to the MuJoCo model :return: None """ # Set name of ground body in MuJoCo cfg.M_GROUND.attrib["name"] = xml.attrib["name"] # We need to rotate the body by 90 degrees wrt x axis rotation = Rotation.from_euler("x", 90, degrees=True) cfg.M_GROUND.attrib["euler"] = vec2str(rotation.as_euler("XYZ")) # Add a ground geom if so instructed if add_ground_geom: etree.SubElement(cfg.M_GROUND, "geom", name="ground-plane", pos="0 0 0", euler=vec2str(rotation.inv().as_euler("XYZ")), size="10 10 0.125", type="plane", rgba="1.0 0.7 0.4 1.0", condim="3") # Check if there are one or multiple components if xml.find("components") is not None: for component in xml.find("components"): self._parse_component(component) else: self._parse_component(xml) # Parse wrapping objects, if there are any cfg.WRAP_OBJECT_PARSER.parse_all(xml.find("WrapObjectSet/objects"), m_body=cfg.M_GROUND)
[docs] def _parse_component(self, xml): # Check if these need to be translated or rotated translation = xml.find("translation") pos = "0 0 0" if translation is None else translation.text orientation = xml.find("orientation") euler = "0 0 0" if orientation is None else orientation.text # Copy any attached geometries for mesh in xml.findall("attached_geometry/Mesh"): mesh_name, mesh_file = copy_mesh_file(mesh.find("mesh_file").text, cfg.GEOMETRY_FOLDER, cfg.OUTPUT_GEOMETRY_FOLDER) etree.SubElement(cfg.M_ASSET, "mesh", name=f"{mesh.attrib['name']}_{mesh_name}", file=os.path.join("Geometry", mesh_file), scale=mesh.find("scale_factors").text) etree.SubElement(cfg.M_GROUND, "geom", name=mesh.attrib["name"], type="mesh", pos=pos, euler=euler, mesh=f"{mesh.attrib['name']}_{mesh_name}", rgba=get_rgba(mesh), group="0")