Skip to content

proximity_mixin

ProximityMixin

Bases: MojoBaseModel, ABC

vertex_max_norm

Python
vertex_max_norm(mj_model: MjModel) -> tuple[float, Vec3]

Calculates the tightest sphere that encompasses all vertices, centered at the mesh's bounding box center.

Returns:

Type Description
tuple[float, Vec3]

tuple[float, Vec3]: Tight radius and the local centroid offset.

Source code in src/mujoco_mojo/utils/proximity_mixin.py
Python
def vertex_max_norm(self, mj_model: mujoco.MjModel) -> tuple[float, Vec3]:
    """
    Calculates the tightest sphere that encompasses all vertices, centered at the mesh's bounding box center.

    Returns:
        tuple[float, Vec3]: Tight radius and the local centroid offset.

    """
    volume_self: Proximityable = self  # pyright: ignore[reportAssignmentType]
    if self._local_verts is None:
        mesh_id = volume_self._mesh_dataid(mj_model)
        if mesh_id == -1:
            raise TypeError(f"Volume '{volume_self.name}' does not have mesh data.")

        adr = mj_model.mesh_vertadr[mesh_id]
        num = mj_model.mesh_vertnum[mesh_id]
        self._local_verts = mj_model.mesh_vert[adr : adr + num].copy()

    # find the centroid of the volume
    v_min = np.asarray(np.min(self._local_verts, axis=0))
    v_max = np.asarray(np.max(self._local_verts, axis=0))
    centroid = (v_min + v_max) / 2

    # find furthest distance reletive to the centroid
    distances = np.linalg.norm(self._local_verts - centroid, axis=1)
    radius = float(np.max(distances))

    return radius, centroid

trimesh abstractmethod

Python
trimesh(mj_model: MjModel) -> Trimesh

Generates a trimesh object to be used with proximity calculations.

Source code in src/mujoco_mojo/utils/proximity_mixin.py
Python
@abstractmethod
def trimesh(self, mj_model: mujoco.MjModel) -> trimesh.Trimesh:
    """Generates a trimesh object to be used with proximity calculations."""

bake_proximity

Python
bake_proximity(
    mj_model: MjModel, proximity_type: ProximityType
) -> None

Builds the BVH tree from the comiled MuJoCo mesh data.

Source code in src/mujoco_mojo/utils/proximity_mixin.py
Python
def bake_proximity(
    self, mj_model: mujoco.MjModel, proximity_type: ProximityType
) -> None:
    """Builds the BVH tree from the comiled MuJoCo mesh data."""
    import trimesh

    volume_self: Proximityable = self  # pyright: ignore[reportAssignmentType]

    # cache bounding radius
    # self._rad = volume_self.rbound(mj_model)
    self._rad, self._local_centroid = volume_self.vertex_max_norm(mj_model)

    match proximity_type:
        case ProximityType.SPHERE_TO_SPHERE | ProximityType.CONVEX_HULL:
            return

    self.trimesh(mj_model)
    assert (
        self._baked_mesh
        and self._local_faces is not None
        and self._local_verts is not None
    )

    match proximity_type:
        case ProximityType.FACE_TO_FACE:
            if not volume_self.name:
                msg = "To perform face to face proximity calculations, volume must have a name"
                logger.error(msg)
                raise ValueError(msg)
            self._baked_manager = trimesh.collision.CollisionManager()
            self._baked_manager.add_object(volume_self.name, self._baked_mesh)
        case _:
            self._baked_query = trimesh.proximity.ProximityQuery(self._baked_mesh)

    logger.debug(
        f"Baked proximity mesh for {volume_self.name} ({len(self._local_faces)} faces)"
    )

clear_unpickleable

Python
clear_unpickleable() -> None

Clear the collision managers and other unpicklable objects.

This should be called before serializing/pickling the self for multiprocessing.

Source code in src/mujoco_mojo/utils/proximity_mixin.py
Python
def clear_unpickleable(self) -> None:
    """
    Clear the collision managers and other unpicklable objects.

    This should be called before serializing/pickling the self for multiprocessing.
    """
    self._baked_manager = None
    self._baked_query = None
    self._baked_mesh = None