Repository: Genesis-Embodied-AI/Genesis
File: genesis/engine/entities/rigid_entity/rigid_link.py (Python)

Code before:
                self._inertial_pos = np.zeros(3, dtype=gs.np_float)
                self._inertial_i = np.zeros((3, 3), dtype=gs.np_float)
                geom_list = []

            # Process each geom individually and compose their properties
            if len(geom_list) > 0:
                total_mass = 0.0
                total_com = np.zeros(3, dtype=gs.np_float)
                total_inertia = np.zeros((3, 3), dtype=gs.np_float)

                for geom in geom_list:
                    inertia_mesh = get_mesh(geom)
                    geom_pos = get_pos(geom)
                    geom_quat = get_quat(geom)

                    if inertia_mesh.is_watertight:
                        geom_mass = inertia_mesh.volume * self.entity.material.rho
                    else:
                        geom_mass = 1e-3

                    geom_com_local = np.array(inertia_mesh.center_mass, dtype=gs.np_float)

                    if not inertia_mesh.is_watertight:
                        inertia_mesh = trimesh.convex.convex_hull(inertia_mesh)

                    if inertia_mesh.is_watertight and inertia_mesh.mass > 0:
                        # density conversion
                        geom_inertia_local = inertia_mesh.moment_inertia / inertia_mesh.mass * geom_mass

                    else:
                        # Approximate with sphere
                        radius = (
                            max(inertia_mesh.bounds[1] - inertia_mesh.bounds[0]) / 2.0
                            if inertia_mesh.bounds is not None
                            else 0.1
                        )
                        geom_inertia_local = 0.4 * geom_mass * radius**2 * np.eye(3)

                    # Transform geom properties to link frame
                    geom_com_link = gu.transform_by_quat(geom_com_local, geom_quat) + geom_pos
                    geom_inertia_link = rotate_inertia(geom_inertia_local, gu.quat_to_R(geom_quat))

                    # Compose with accumulated properties
                    if total_mass == 0.0:
                        # First geom
                        total_mass = geom_mass
                        total_com = geom_com_link
                        total_inertia = geom_inertia_link
                    else:
                        # Compose with existing properties
                        total_mass, total_com, total_inertia = compose_inertial_properties(

Review comment (suggestion):
You should just raise an exception is `inertia_mesh.mass < gs.EPS`. No point to support this, it will just cause more issues later on.

Code after:
                    f"link '{self.name}'. Inertial and mass are set to zero."
                )
                self._inertial_mass = gs.EPS
                self._inertial_pos = np.zeros(3, dtype=gs.np_float)
                self._inertial_i = np.eye(3, dtype=gs.np_float) * gs.EPS
                geom_list = []

            # Process each geom individually and compose their properties
            if len(geom_list) > 0:
                total_mass = gs.EPS  # to avoid nan in inv_mass in interactive mode
                total_com = np.zeros(3, dtype=gs.np_float)
                total_inertia = np.eye(3, dtype=gs.np_float) * gs.EPS

                for geom in geom_list:
                    # Create mesh based on geom type
                    if is_visual:
                        inertia_mesh = trimesh.Trimesh(geom.init_vverts, geom.init_vfaces)
                    else:
                        inertia_mesh = trimesh.Trimesh(geom.init_verts, geom.init_faces)

                    geom_pos = geom._init_pos
                    geom_quat = geom._init_quat

                    if not inertia_mesh.is_watertight:
                        inertia_mesh = trimesh.convex.convex_hull(inertia_mesh)

                    # TODO: without this check, some geom will have negative volume
                    # even after the above convex hull operation.
                    # tests/test_examples.py::test_example[rigid/terrain_from_mesh.py-None]
                    if inertia_mesh.volume < -gs.EPS:
                        inertia_mesh.invert()

                    geom_mass = inertia_mesh.volume * self.entity.material.rho
                    geom_com_local = np.array(inertia_mesh.center_mass, dtype=gs.np_float)

                    geom_inertia_local = inertia_mesh.moment_inertia / inertia_mesh.mass * geom_mass

                    # Transform geom properties to link frame
                    geom_com_link = gu.transform_by_quat(geom_com_local, geom_quat) + geom_pos
                    geom_inertia_link = rotate_inertia(geom_inertia_local, gu.quat_to_R(geom_quat))

                    # Compose with existing properties
                    total_mass, total_com, total_inertia = compose_inertial_properties(
                        total_mass, total_com, total_inertia, geom_mass, geom_com_link, geom_inertia_link
                    )

                self._inertial_mass = total_mass
                self._inertial_pos = total_com
                self._inertial_i = total_inertia

        # Postpone computation of inverse weight if not specified