knn.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. #include "knn.h"
  2. #include "parallel_for.h"
  3. #include <cmath>
  4. #include <queue>
  5. namespace igl {
  6. template <typename DerivedP, typename KType, typename IndexType,
  7. typename DerivedCH, typename DerivedCN, typename DerivedW,
  8. typename DerivedI>
  9. IGL_INLINE void knn(const Eigen::MatrixBase<DerivedP>& P,
  10. const KType & k,
  11. const std::vector<std::vector<IndexType> > & point_indices,
  12. const Eigen::MatrixBase<DerivedCH>& CH,
  13. const Eigen::MatrixBase<DerivedCN>& CN,
  14. const Eigen::MatrixBase<DerivedW>& W,
  15. Eigen::PlainObjectBase<DerivedI> & I)
  16. {
  17. typedef typename DerivedCN::Scalar CentersType;
  18. typedef typename DerivedW::Scalar WidthsType;
  19. typedef Eigen::Matrix<typename DerivedP::Scalar, 1, 3> RowVector3PType;
  20. int n = P.rows();
  21. const KType real_k = std::min(n,k);
  22. auto distance_to_width_one_cube = [](RowVector3PType point){
  23. return std::sqrt(std::pow(std::max(std::abs(point(0))-1,0.0),2)
  24. + std::pow(std::max(std::abs(point(1))-1,0.0),2)
  25. + std::pow(std::max(std::abs(point(2))-1,0.0),2));
  26. };
  27. auto distance_to_cube = [&distance_to_width_one_cube]
  28. (RowVector3PType point,
  29. Eigen::Matrix<CentersType,1,3> cube_center,
  30. WidthsType cube_width){
  31. RowVector3PType transformed_point = (point-cube_center)/cube_width;
  32. return cube_width*distance_to_width_one_cube(transformed_point);
  33. };
  34. I.resize(n,real_k);
  35. igl::parallel_for(n,[&](int i)
  36. {
  37. int points_found = 0;
  38. RowVector3PType point_of_interest = P.row(i);
  39. //To make my priority queue take both points and octree cells,
  40. //I use the indices 0 to n-1 for the n points,
  41. // and the indices n to n+m-1 for the m octree cells
  42. // Using lambda to compare elements.
  43. auto cmp = [&point_of_interest, &P, &CN, &W,
  44. &n, &distance_to_cube](int left, int right) {
  45. double leftdistance, rightdistance;
  46. if(left < n){ //left is a point index
  47. leftdistance = (P.row(left) - point_of_interest).norm();
  48. } else { //left is an octree cell
  49. leftdistance = distance_to_cube(point_of_interest,
  50. CN.row(left-n),
  51. W(left-n));
  52. }
  53. if(right < n){ //left is a point index
  54. rightdistance = (P.row(right) - point_of_interest).norm();
  55. } else { //left is an octree cell
  56. rightdistance = distance_to_cube(point_of_interest,
  57. CN.row(right-n),
  58. W(right-n));
  59. }
  60. return leftdistance > rightdistance;
  61. };
  62. std::priority_queue<IndexType, std::vector<IndexType>,
  63. decltype(cmp)> queue(cmp);
  64. queue.push(n); //This is the 0th octree cell (ie the root)
  65. while(points_found < real_k){
  66. IndexType curr_cell_or_point = queue.top();
  67. queue.pop();
  68. if(curr_cell_or_point < n){ //current index is for is a point
  69. I(i,points_found) = curr_cell_or_point;
  70. points_found++;
  71. } else {
  72. IndexType curr_cell = curr_cell_or_point - n;
  73. if(CH(curr_cell,0) == -1){ //In the case of a leaf
  74. if(point_indices.at(curr_cell).size() > 0){
  75. //Assumption: Leaves either have one point, or none
  76. queue.push(point_indices.at(curr_cell).at(0));
  77. }
  78. } else { //Not a leaf
  79. for(int j = 0; j < 8; j++){
  80. //+n to adjust for the octree cells
  81. queue.push(CH(curr_cell,j)+n);
  82. }
  83. }
  84. }
  85. }
  86. },1000);
  87. }
  88. }
  89. #ifdef IGL_STATIC_LIBRARY
  90. template void igl::knn<Eigen::Matrix<double, -1, -1, 0, -1, -1>, int, int, Eigen::Matrix<int, -1, 8, 0, -1, 8>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 8, 0, -1, 8> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
  91. #endif