Source code for myoconverter.xml.bodies.utils

""" This module contains a collection of utility functions useful for parsing and converting the OpenSim `BodySet`

@author: Aleksi Ikkala
"""

import numpy as np
import os
import trimesh
import pyvista
from shutil import copyfile

from loguru import logger

from myoconverter.xml.utils import create_symmetric_matrix


[docs]def valid_inertia(mass, inertia_vec): """ Check if given inertia vector is valid and can be used in the MuJoCo model. :param mass: Mass of a body/geom :param inertia_vec: Inertia vector :return: Boolean indicating whether the given vector is valid """ values, vectors = np.linalg.eig(create_symmetric_matrix(inertia_vec)) if mass > 0 and np.all(values > 0): return True else: return False
[docs]def copy_mesh_file(mesh_file, geometry_folder, output_geometry_folder): """ This function copies the original mesh file,converts it to stl and fixes unconnected facets (if necessary) :param mesh_file: Path to mesh file :param geometry_folder: Path to the folder where the mesh file is :param output_geometry_folder: Path to folder into which the mesh file will be copied to :return: Name of mesh, filename of converted stl mesh file :raises NotImplementedError: if given mesh file is not vtk or stl """ mesh_name = mesh_file[:-4] stl_filename = mesh_name + ".stl" stl_filepath = os.path.join(output_geometry_folder, stl_filename) # Transform a vtk file into an stl file and repair the mesh if mesh_file[-3:] == "vtp": # Read the vtp file with pyvista pymesh = pyvista.read(os.path.join(geometry_folder, mesh_file)) # Convert into trimesh (see https://github.com/pyvista/pyvista/discussions/2268) pymesh = pymesh.extract_surface().triangulate() faces_as_array = pymesh.faces.reshape((pymesh.n_faces, 4))[:, 1:] tmesh = trimesh.Trimesh(pymesh.points, faces_as_array) # Repair the mesh trimesh.repair.fix_inversion(tmesh, True) trimesh.repair.fix_normals(tmesh, True) trimesh.repair.fill_holes(tmesh) # Save as binary stl file tmesh.export(stl_filepath) # Just copy the stl file elif mesh_file[-3:] == "stl": copyfile(os.path.join(geometry_folder, mesh_file), stl_filepath) else: logger.critical("Geom file is not vtp or stl!") raise NotImplementedError return mesh_name, stl_filename
[docs]def get_rgba(mesh): """ Return rgba string for given mesh :param mesh: XML element :return: Rgba string in format "r g b a" """ color = mesh.find("Appearance/color") opacity = mesh.find("Appearance/opacity") visible = mesh.find("Appearance/visible") # Check if mesh is visible, or transparent if visible is not None: if visible.text=="false": alpha = "0" else: alpha = "1" elif opacity is None: alpha = "1" else: alpha = opacity.text if alpha == "0": logger.warning(f"Setting mesh {mesh.attrib['name']} to invisible") return ("1 1 1" if color is None else color.text) + " " + alpha