def rotate_perturbation_point_cloud_with_normal(
    batch_data, angle_sigma=0.06, angle_clip=0.18
):
    """Randomly perturb the point clouds by small rotations
    Input:
      BxNx6 array, original batch of point clouds and point normals
    Return:
      BxNx3 array, rotated batch of point clouds
    """
    rotated_data = np.zeros(batch_data.shape, dtype=np.float32)
    for k in range(batch_data.shape[0]):
        angles = np.clip(
            angle_sigma * np.random.randn(3), -angle_clip, angle_clip
        )
        Rx = np.array(
            [
                [1, 0, 0],
                [0, np.cos(angles[0]), -np.sin(angles[0])],
                [0, np.sin(angles[0]), np.cos(angles[0])],
            ]
        )
        Ry = np.array(
            [
                [np.cos(angles[1]), 0, np.sin(angles[1])],
                [0, 1, 0],
                [-np.sin(angles[1]), 0, np.cos(angles[1])],
            ]
        )
        Rz = np.array(
            [
                [np.cos(angles[2]), -np.sin(angles[2]), 0],
                [np.sin(angles[2]), np.cos(angles[2]), 0],
                [0, 0, 1],
            ]
        )
        R = np.dot(Rz, np.dot(Ry, Rx))
        shape_pc = batch_data[k, :, 0:3]
        shape_normal = batch_data[k, :, 3:6]
        rotated_data[k, :, 0:3] = np.dot(shape_pc.reshape((-1, 3)), R)
        rotated_data[k, :, 3:6] = np.dot(shape_normal.reshape((-1, 3)), R)
    return rotated_data
Randomly perturb the point clouds by small rotations
    Input:
      BxNx6 array, original batch of point clouds and point normals
    Return:
      BxNx3 array, rotated batch of point clouds
    
examples/pytorch/pointcloud/point_transformer/provider.py