template <typename PointSource, typename PointTarget, typename NormalT, typename Scalar> void
pcl::registration::CorrespondenceEstimationBackProjection<PointSource, PointTarget, NormalT, Scalar>::determineReciprocalCorrespondences (
    pcl::Correspondences &correspondences, double max_distance)
{
  if (!initCompute ())
    return;

  typedef typename pcl::traits::fieldList<PointTarget>::type FieldListTarget;
  
  // Set the internal point representation of choice
  if(!initComputeReciprocal())
    return;

  correspondences.resize (indices_->size ());

  std::vector<int> nn_indices (k_);
  std::vector<float> nn_dists (k_);
  std::vector<int> index_reciprocal (1);
  std::vector<float> distance_reciprocal (1);

  float min_dist = std::numeric_limits<float>::max ();
  int min_index = 0;
  
  pcl::Correspondence corr;
  unsigned int nr_valid_correspondences = 0;
  int target_idx = 0;

  // Check if the template types are the same. If true, avoid a copy.
  // Both point types MUST be registered using the POINT_CLOUD_REGISTER_POINT_STRUCT macro!
  if (isSamePointType<PointSource, PointTarget> ())
  {
    PointTarget pt;
    // Iterate over the input set of source indices
    for (std::vector<int>::const_iterator idx_i = indices_->begin (); idx_i != indices_->end (); ++idx_i)
    {
      tree_->nearestKSearch (input_->points[*idx_i], k_, nn_indices, nn_dists);

      // Among the K nearest neighbours find the one with minimum perpendicular distance to the normal
      min_dist = std::numeric_limits<float>::max ();
      
      // Find the best correspondence
      for (size_t j = 0; j < nn_indices.size (); j++)
      {
        float cos_angle = source_normals_->points[*idx_i].normal_x * target_normals_->points[nn_indices[j]].normal_x +
                          source_normals_->points[*idx_i].normal_y * target_normals_->points[nn_indices[j]].normal_y +
                          source_normals_->points[*idx_i].normal_z * target_normals_->points[nn_indices[j]].normal_z ;
        float dist = nn_dists[j] * (2.0f - cos_angle * cos_angle);
        
        if (dist < min_dist)
        {
          min_dist = dist;
          min_index = static_cast<int> (j);
        }
      }
      if (min_dist > max_distance)
        continue;

      // Check if the correspondence is reciprocal
      target_idx = nn_indices[min_index];
      tree_reciprocal_->nearestKSearch (target_->points[target_idx], 1, index_reciprocal, distance_reciprocal);

      if (*idx_i != index_reciprocal[0])
        continue;

      corr.index_query = *idx_i;
      corr.index_match = nn_indices[min_index];
      corr.distance = nn_dists[min_index];//min_dist;
      correspondences[nr_valid_correspondences++] = corr;
    }
  }
  else
  {
    PointTarget pt;
    
    // Iterate over the input set of source indices
    for (std::vector<int>::const_iterator idx_i = indices_->begin (); idx_i != indices_->end (); ++idx_i)
    {
      tree_->nearestKSearch (input_->points[*idx_i], k_, nn_indices, nn_dists);
 
      // Among the K nearest neighbours find the one with minimum perpendicular distance to the normal
      min_dist = std::numeric_limits<float>::max ();
      
      // Find the best correspondence
      for (size_t j = 0; j < nn_indices.size (); j++)
      {
        PointSource pt_src;
        // Copy the source data to a target PointTarget format so we can search in the tree
        pcl::for_each_type <FieldListTarget> (pcl::NdConcatenateFunctor <PointSource, PointTarget> (
            input_->points[*idx_i], 
            pt_src));

        float cos_angle = source_normals_->points[*idx_i].normal_x * target_normals_->points[nn_indices[j]].normal_x +
                          source_normals_->points[*idx_i].normal_y * target_normals_->points[nn_indices[j]].normal_y +
                          source_normals_->points[*idx_i].normal_z * target_normals_->points[nn_indices[j]].normal_z ;
        float dist = nn_dists[j] * (2.0f - cos_angle * cos_angle);
        
        if (dist < min_dist)
        {
          min_dist = dist;
          min_index = static_cast<int> (j);
        }
      }
      if (min_dist > max_distance)
        continue;
      
      // Check if the correspondence is reciprocal
      target_idx = nn_indices[min_index];
      tree_reciprocal_->nearestKSearch (target_->points[target_idx], 1, index_reciprocal, distance_reciprocal);

      if (*idx_i != index_reciprocal[0])
        continue;

      corr.index_query = *idx_i;
      corr.index_match = nn_indices[min_index];
      corr.distance = nn_dists[min_index];//min_dist;
      correspondences[nr_valid_correspondences++] = corr;
    }
  }
  correspondences.resize (nr_valid_correspondences);
  deinitCompute ();
}
template <typename PointSource, typename PointTarget, typename NormalT, typename Scalar> void
pcl::registration::CorrespondenceEstimationNormalShooting<PointSource, PointTarget, NormalT, Scalar>::determineReciprocalCorrespondences (
    pcl::Correspondences &correspondences, double max_distance)
{
  if (!initCompute ())
    return;

  typedef typename pcl::traits::fieldList<PointSource>::type FieldListSource;
  typedef typename pcl::traits::fieldList<PointTarget>::type FieldListTarget;
  typedef typename pcl::intersect<FieldListSource, FieldListTarget>::type FieldList;
  
  // setup tree for reciprocal search
  // Set the internal point representation of choice
  if (!initComputeReciprocal ())
    return;

  correspondences.resize (indices_->size ());

  std::vector<int> nn_indices (k_);
  std::vector<float> nn_dists (k_);
  std::vector<int> index_reciprocal (1);
  std::vector<float> distance_reciprocal (1);

  double min_dist = std::numeric_limits<double>::max ();
  int min_index = 0;
  
  pcl::Correspondence corr;
  unsigned int nr_valid_correspondences = 0;
  int target_idx = 0;

  // Check if the template types are the same. If true, avoid a copy.
  // Both point types MUST be registered using the POINT_CLOUD_REGISTER_POINT_STRUCT macro!
  if (isSamePointType<PointSource, PointTarget> ())
  {
    PointTarget pt;
    // Iterate over the input set of source indices
    for (std::vector<int>::const_iterator idx_i = indices_->begin (); idx_i != indices_->end (); ++idx_i)
    {
      tree_->nearestKSearch (input_->points[*idx_i], k_, nn_indices, nn_dists);

      // Among the K nearest neighbours find the one with minimum perpendicular distance to the normal
      min_dist = std::numeric_limits<double>::max ();
      
      // Find the best correspondence
      for (size_t j = 0; j < nn_indices.size (); j++)
      {
        // computing the distance between a point and a line in 3d. 
        // Reference - http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
        pt.x = target_->points[nn_indices[j]].x - input_->points[*idx_i].x;
        pt.y = target_->points[nn_indices[j]].y - input_->points[*idx_i].y;
        pt.z = target_->points[nn_indices[j]].z - input_->points[*idx_i].z;

        const NormalT &normal = source_normals_->points[*idx_i];
        Eigen::Vector3d N (normal.normal_x, normal.normal_y, normal.normal_z);
        Eigen::Vector3d V (pt.x, pt.y, pt.z);
        Eigen::Vector3d C = N.cross (V);
        
        // Check if we have a better correspondence
        double dist = C.dot (C);
        if (dist < min_dist)
        {
          min_dist = dist;
          min_index = static_cast<int> (j);
        }
      }
      if (min_dist > max_distance)
        continue;

      // Check if the correspondence is reciprocal
      target_idx = nn_indices[min_index];
      tree_reciprocal_->nearestKSearch (target_->points[target_idx], 1, index_reciprocal, distance_reciprocal);

      if (*idx_i != index_reciprocal[0])
        continue;

      // Correspondence IS reciprocal, save it and continue
      corr.index_query = *idx_i;
      corr.index_match = nn_indices[min_index];
      corr.distance = nn_dists[min_index];//min_dist;
      correspondences[nr_valid_correspondences++] = corr;
    }
  }
  else
  {
    PointTarget pt;
    
    // Iterate over the input set of source indices
    for (std::vector<int>::const_iterator idx_i = indices_->begin (); idx_i != indices_->end (); ++idx_i)
    {
      tree_->nearestKSearch (input_->points[*idx_i], k_, nn_indices, nn_dists);

      // Among the K nearest neighbours find the one with minimum perpendicular distance to the normal
      min_dist = std::numeric_limits<double>::max ();
      
      // Find the best correspondence
      for (size_t j = 0; j < nn_indices.size (); j++)
      {
        PointSource pt_src;
        // Copy the source data to a target PointTarget format so we can search in the tree
        pcl::for_each_type <FieldListTarget> (pcl::NdConcatenateFunctor <PointSource, PointTarget> (
            input_->points[*idx_i], 
            pt_src));

        // computing the distance between a point and a line in 3d. 
        // Reference - http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
        pt.x = target_->points[nn_indices[j]].x - pt_src.x;
        pt.y = target_->points[nn_indices[j]].y - pt_src.y;
        pt.z = target_->points[nn_indices[j]].z - pt_src.z;
        
        const NormalT &normal = source_normals_->points[*idx_i];
        Eigen::Vector3d N (normal.normal_x, normal.normal_y, normal.normal_z);
        Eigen::Vector3d V (pt.x, pt.y, pt.z);
        Eigen::Vector3d C = N.cross (V);
        
        // Check if we have a better correspondence
        double dist = C.dot (C);
        if (dist < min_dist)
        {
          min_dist = dist;
          min_index = static_cast<int> (j);
        }
      }
      if (min_dist > max_distance)
        continue;

      // Check if the correspondence is reciprocal
      target_idx = nn_indices[min_index];
      tree_reciprocal_->nearestKSearch (target_->points[target_idx], 1, index_reciprocal, distance_reciprocal);

      if (*idx_i != index_reciprocal[0])
        continue;

      // Correspondence IS reciprocal, save it and continue
      corr.index_query = *idx_i;
      corr.index_match = nn_indices[min_index];
      corr.distance = nn_dists[min_index];//min_dist;
      correspondences[nr_valid_correspondences++] = corr;
    }
  }
  correspondences.resize (nr_valid_correspondences);
  deinitCompute ();
}