def boxes3d_to_rotated_boxes(
    boxes3d, pose_cam_global=CAMERA_TO_VEHICLE_ROTATION, pose_global_bev=VEHICLE_TO_BEV_ROTATION, use_top_surface=True
):
    """

    Parameters
    ----------
    boxes3d: Boxes3D
        3D boxes in camera frame.
    pose_cam_global: Pose
        Transformation from sensor (camera) frame to global frame. Depending on the context, global frame can be
        "vehicle" frame which moves along with the vehicle, or "world" frame which is fixed in the world.
        By default, it is an axis-swapping rotation that convert pinhole camera frame to Vehicle frame, i.e.
            x: forward, y: left, z: up (see above for detail.)
        with no translation (i.e. moves along with camera).
    pose_global_bev: Pose
        Transformation from global frame to bird-eye-view frame. By default, "forward" matches with "up" of BEV image,
        By default, it is an axis-swapping rotation that converts Vehicle frame to BEV frame (see above for detail.)
        with no translation.
    """
    if use_top_surface:
        vertice_inds = [0, 1, 5, 4]  # (front-left, front-right, back-right, back-left) of top surface.
    else:
        # use bottom surface.
        vertice_inds = [3, 2, 6, 7]  # (front-left, front-right, back-right, back-left) of bottom surface.

    surface = boxes3d.corners[:, vertice_inds, :]
    pose_cam_bev = pose_global_bev * pose_cam_global
    cam_to_bev = t3d.Transform3d(matrix=surface.new_tensor(pose_cam_bev.matrix.T))  # Need to transpose!
    # Assumpiton: this is close to rectangles. TODO: assert it?
    rot_boxes_bev = cam_to_bev.transform_points(surface)[:, :, :2]

    # length/width of objects are equivalent to "height"/width of RotatedBoxes
    length = torch.norm(rot_boxes_bev[:, 0, :] - rot_boxes_bev[:, 3, :], dim=1).abs()
    width = torch.norm(rot_boxes_bev[:, 0, :] - rot_boxes_bev[:, 1, :], dim=1).abs()

    center = torch.mean(rot_boxes_bev[:, [0, 2], :], dim=1)
    center_x, center_y = center[:, 0], center[:, 1]

    forward = rot_boxes_bev[:, 0, :] - rot_boxes_bev[:, 3, :]
    # CCW-angle, i.e. rotation wrt -z (or "up") in BEV frame.
    angle = torch.atan2(forward[:, 0], forward[:, 1])
    angle = 180. / np.pi * angle

    rot_boxes = RotatedBoxes(torch.stack([center_x, center_y, width, length, angle], dim=1))
    return rot_boxes


    Parameters
    ----------
    boxes3d: Boxes3D
        3D boxes in camera frame.
    pose_cam_global: Pose
        Transformation from sensor (camera) frame to global frame. Depending on the context, global frame can be
        "vehicle" frame which moves along with the vehicle, or "world" frame which is fixed in the world.
        By default, it is an axis-swapping rotation that convert pinhole camera frame to Vehicle frame, i.e.
            x: forward, y: left, z: up (see above for detail.)
        with no translation (i.e. moves along with camera).
    pose_global_bev: Pose
        Transformation from global frame to bird-eye-view frame. By default, "forward" matches with "up" of BEV image,
        By default, it is an axis-swapping rotation that converts Vehicle frame to BEV frame (see above for detail.)
        with no translation.
    
tridet/layers/bev_nms.py