class_docstr: Class to manage spatial ray sampling.
  
  Args:
      min_depth: sampled rays minimal depth from cameras: float
      max_depth: sampled rays maximal depth from cameras: float
      ndc: convert ray parameters to normalized device coordinates: bool
      device: device for ray tensors: Union[str, torch.device]
docstr: Transforms ray parameters to normalized coordinate device (camera) system (NDC)
  
  Args:
      cameras: scene cameras: PinholeCamera
docstr_tok: ["Transforms","ray","parameters","to","normalized","coordinate","device","(","camera",")","system","(","NDC",")","Args",":","cameras",":","scene","cameras",":","PinholeCamera"]
code: def transform_ray_params_world_to_ndc(
      self, cameras: PinholeCamera
  ) -> Tuple[Tensor, Tensor]:
      r"""Transforms ray parameters to normalized coordinate device (camera) system (NDC)
  
      Args:
          cameras: scene cameras: PinholeCamera
      """
      cams = cameras_for_ids(cameras, self._camera_ids)
      fx = cams.fx
      fy = cams.fy
      widths = cams.width
      heights = cams.height
      fx_widths = 2.0 * fx / (widths - 1.0)
      fy_heights = 2.0 * fy / (heights - 1.0)
  
      # oxoz = self._origins_cam[..., 0] / self._origins_cam[..., 2]
      # oyoz = self._origins_cam[..., 1] / self._origins_cam[..., 2]
  
      oxoz = self._origins[..., 0] / self._origins[..., 2]
      oyoz = self._origins[..., 1] / self._origins[..., 2]
  
      origins_ndc_x = fx_widths * oxoz
      origins_ndc_y = fy_heights * oyoz
  
      # origins_ndc_z = 1 - 2 * self._min_depth / self._origins_cam[..., 2]
  
      origins_ndc_z = 1 - 2 * self._min_depth / self._origins[..., 2]
  
      origins_ndc = torch.stack(
          [origins_ndc_x, origins_ndc_y, origins_ndc_z], dim=-1
      )
  
      # dxdz = self._directions_cam[..., 0] / self._directions_cam[..., 2]
      # dydz = self._directions_cam[..., 1] / self._directions_cam[..., 2]
  
      Rt_inv = _torch_inverse_cast(cams.rotation_matrix)
      directions_rotated_world = (
          Rt_inv @ self._directions_cam[..., None]
      ).squeeze(dim=-1)
  
      dxdz = (
          directions_rotated_world[..., 0]
          / directions_rotated_world[..., 2]
      )
      dydz = (
          directions_rotated_world[..., 1]
          / directions_rotated_world[..., 2]
      )
  
      directions_ndc_x = fx_widths * dxdz - origins_ndc_x
      directions_ndc_y = fy_heights * dydz - origins_ndc_y
      directions_ndc_z = 1 - origins_ndc_z
      directions_ndc = torch.stack(
          [directions_ndc_x, directions_ndc_y, directions_ndc_z], dim=-1
      )
  
      # Rt_inv = _torch_inverse_cast(cams.rotation_matrix)
      # origins_ndc_world = (Rt_inv @ origins_ndc[..., None]).squeeze(dim=-1)
      # directions_ndc_world = (Rt_inv @ directions_ndc[..., None]).squeeze(dim=-1)
  
      origins_ndc_world = origins_ndc
      directions_ndc_world = directions_ndc
  
      return origins_ndc_world, directions_ndc_world
  
imports: import math
  from typing import Dict, List, Tuple
  import torch
  from kornia.core import Device, Tensor, tensor
  from kornia.geometry.camera import PinholeCamera
  from kornia.nerf.camera_utils import cameras_for_ids
  from kornia.utils._compat import torch_meshgrid
  from kornia.utils.helpers import _torch_inverse_cast
label_desc: Use image node_id 9 for calling the RaySampler obj's underlying member method code with example usage: obj.transform_ray_params_world_to_ndc(cameras) and returns: origins_ndc_world,  directions_ndc_world