Repository: Genesis-Embodied-AI/Genesis
File: genesis/vis/camera.py (Python)

Code before:
    def get_transform(self, env_idx=None):
        """
        The current transform matrix of the camera.
        """
        env_idx = () if env_idx is None else env_idx
        transform = self._multi_env_transform_tensor[env_idx]
        if self._batch_renderer is None:
            transform = transform.clone()
            transform[..., :3, 3] += self._envs_offset[env_idx]
        return transform

    def _repr_brief(self):
        return f"{self._repr_type()}: idx: {self._idx}, pos: {self.pos}, lookat: {self.lookat}"

    @property
    def is_built(self):
        """Whether the camera is built."""
        return self._is_built

    @property
    def idx(self):
        """The global integer index of the camera."""
        return self._idx

    @property
    @lru_cache(maxsize=1)
    def b_idx(self):
        """The index of the camera in the batch renderer."""
        assert self._batch_renderer is not None, "Batch renderer is not initialized."
        print(f"{[c.uid for c in self._batch_renderer.cameras]}")
        print(f"self: {self.uid}")
        return self._batch_renderer.cameras.index(self)

    @property
    def uid(self):
        """The unique ID of the camera"""
        return self._uid

    @property
    def model(self):
        """The camera model: `pinhole` or `thinlens`."""
        return self._model

    @property
    def res(self):
        """The resolution of the camera."""
        return self._res

    @property
    def fov(self):
        """The field of view of the camera."""

Review comment (performance):
I would rather keep this inside `_batch_render` rather than make it an official property at camera level. This kind of circular dependency is not great.

Besides, I don't think caching the result is relevant for something as simple as finding an index in a list.

Code after:
        if self._batch_renderer is None:
            transform = transform.clone()
            transform[..., :3, 3] += self._envs_offset[env_idx]
        return transform

    def _repr_brief(self):
        return f"{self._repr_type()}: idx: {self._idx}, pos: {self.pos}, lookat: {self.lookat}"

    @property
    def is_built(self):
        """Whether the camera is built."""
        return self._is_built

    @property
    def idx(self):
        """The global integer index of the camera."""
        return self._idx

    @property
    def uid(self):
        """The unique ID of the camera"""
        return self._uid

    @property
    def model(self):
        """The camera model: `pinhole` or `thinlens`."""
        return self._model

    @property
    def res(self):
        """The resolution of the camera."""
        return self._res

    @property
    def fov(self):
        """The field of view of the camera."""
        return self._fov

    @property
    def aperture(self):
        """The aperture of the camera."""
        return self._aperture

    @property
    def focal_len(self):
        """The focal length for thinlens camera. Returns -1 for pinhole camera."""
        tan_half_fov = np.tan(np.deg2rad(self._fov / 2))
        if self.model == "thinlens":
            if self._res[0] > self._res[1]:
                projected_pixel_size = min(0.036 / self._res[0], 0.024 / self._res[1])
            else: