code: def _prepare_features(self, x, pos, new_pos, idx, scale_idx):
      new_pos_trans = pos.transpose(1, 2).contiguous()
      grouped_pos = tp.grouping_operation(
          new_pos_trans, idx
      )  # (B, 3, npoint, nsample)
      grouped_pos -= new_pos.transpose(1, 2).unsqueeze(-1)
  
      if self.normalize_xyz:
          grouped_pos /= self.radii[scale_idx]
  
      if x is not None:
          grouped_features = tp.grouping_operation(x, idx)
          if self.use_xyz:
              new_features = torch.cat(
                  [grouped_pos, grouped_features], dim=1
              )  # (B, C + 3, npoint, nsample)
          else:
              new_features = grouped_features
      else:
          assert (
              self.use_xyz
          ), "Cannot have not features and not use xyz as a feature!"
          new_features = grouped_pos
  
      return new_features
  
file_path: torch-points3d/torch_points3d/modules/pointnet2/dense.py
imports: import torch
  import torch.nn
  import torch.nn.functional
  import torch_points_kernels
  from torch_points3d.core.base_conv.dense import *
  from torch_points3d.core.spatial_ops import DenseRadiusNeighbourFinder, DenseFPSSampler
  from torch_points3d.utils.model_building_utils.activation_resolver import get_activation
label_desc: Use image node_id 2 for calling the PointNetMSGDown obj's underlying member method code with example usage: obj._prepare_features(x, pos, new_pos, idx, scale_idx) and returns: new_features