code: 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
  
file_path: dgl/examples/pytorch/pointcloud/pointnet/provider.py
imports: import numpy
label_desc: Use image node_id 7 for calling a global function with example usage: rotate_perturbation_point_cloud_with_normal(batch_data, angle_sigma, angle_clip) and returns: rotated_data