knn.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #include "knn.h"
  2. #include "sort.h"
  3. #include "parallel_for.h"
  4. #include <cmath>
  5. #include <queue>
  6. #include <set>
  7. #include <algorithm>
  8. namespace igl {
  9. template <typename DerivedP, typename IndexType,
  10. typename DerivedCH, typename DerivedCN, typename DerivedW,
  11. typename DerivedI>
  12. IGL_INLINE void knn(const Eigen::MatrixBase<DerivedP>& P,
  13. size_t k,
  14. const std::vector<std::vector<IndexType> > & point_indices,
  15. const Eigen::MatrixBase<DerivedCH>& CH,
  16. const Eigen::MatrixBase<DerivedCN>& CN,
  17. const Eigen::MatrixBase<DerivedW>& W,
  18. Eigen::PlainObjectBase<DerivedI> & I) {
  19. knn(P,P,k,point_indices,CH,CN,W,I);
  20. }
  21. template <typename DerivedP, typename DerivedV, typename IndexType,
  22. typename DerivedCH, typename DerivedCN, typename DerivedW,
  23. typename DerivedI>
  24. IGL_INLINE void knn(
  25. const Eigen::MatrixBase<DerivedP>& P,
  26. const Eigen::MatrixBase<DerivedV>& V,
  27. size_t k,
  28. const std::vector<std::vector<IndexType> > & point_indices,
  29. const Eigen::MatrixBase<DerivedCH>& CH,
  30. const Eigen::MatrixBase<DerivedCN>& CN,
  31. const Eigen::MatrixBase<DerivedW>& W,
  32. Eigen::PlainObjectBase<DerivedI> & I) {
  33. typedef typename DerivedCN::Scalar CentersType;
  34. typedef typename DerivedW::Scalar WidthsType;
  35. using Scalar = typename DerivedP::Scalar;
  36. typedef Eigen::Matrix<Scalar, 1, 3> RowVector3PType;
  37. const size_t Psize = P.rows();
  38. const size_t Vsize = V.rows();
  39. if(Vsize <= k) {
  40. I.resize(Psize,Vsize);
  41. for(size_t i = 0; i < Psize; ++i) {
  42. Eigen::Matrix<Scalar,Eigen::Dynamic,1> D = (V.rowwise() - P.row(i)).rowwise().norm();
  43. Eigen::Matrix<Scalar,Eigen::Dynamic,1> S;
  44. Eigen::Vector<typename DerivedI::Scalar,Eigen::Dynamic> R;
  45. igl::sort(D,1,true,S,R);
  46. I.row(i) = R.transpose();
  47. }
  48. return;
  49. }
  50. I.resize(Psize,k);
  51. auto distance_to_width_one_cube = [](const RowVector3PType& point) -> Scalar {
  52. return std::sqrt(std::pow<Scalar>(std::max<Scalar>(std::abs(point(0))-1,0.0),2)
  53. + std::pow<Scalar>(std::max<Scalar>(std::abs(point(1))-1,0.0),2)
  54. + std::pow<Scalar>(std::max<Scalar>(std::abs(point(2))-1,0.0),2));
  55. };
  56. auto distance_to_cube = [&distance_to_width_one_cube]
  57. (const RowVector3PType& point,
  58. Eigen::Matrix<CentersType,1,3> cube_center,
  59. WidthsType cube_width) -> Scalar {
  60. RowVector3PType transformed_point = (point-cube_center)/cube_width;
  61. return cube_width*distance_to_width_one_cube(transformed_point);
  62. };
  63. igl::parallel_for(Psize,[&](size_t i)
  64. {
  65. int points_found = 0;
  66. RowVector3PType point_of_interest = P.row(i);
  67. //To make my priority queue take both points and octree cells,
  68. //I use the indices 0 to n-1 for the n points,
  69. // and the indices n to n+m-1 for the m octree cells
  70. // Using lambda to compare elements.
  71. auto cmp = [&point_of_interest, &V, &CN, &W,
  72. Vsize, &distance_to_cube](int left, int right) {
  73. Scalar leftdistance, rightdistance;
  74. if(left < Vsize){ //left is a point index
  75. leftdistance = (V.row(left) - point_of_interest).norm();
  76. } else { //left is an octree cell
  77. leftdistance = distance_to_cube(point_of_interest,
  78. CN.row(left-Vsize),
  79. W(left-Vsize));
  80. }
  81. if(right < Vsize){ //left is a point index
  82. rightdistance = (V.row(right) - point_of_interest).norm();
  83. } else { //left is an octree cell
  84. rightdistance = distance_to_cube(point_of_interest,
  85. CN.row(right-Vsize),
  86. W(right-Vsize));
  87. }
  88. return leftdistance > rightdistance;
  89. };
  90. std::priority_queue<IndexType, std::vector<IndexType>,
  91. decltype(cmp)> queue(cmp);
  92. queue.push(Vsize); //This is the 0th octree cell (ie the root)
  93. while(points_found < k){
  94. IndexType curr_cell_or_point = queue.top();
  95. queue.pop();
  96. if(curr_cell_or_point < Vsize){ //current index is for is a point
  97. I(i,points_found) = curr_cell_or_point;
  98. points_found++;
  99. } else {
  100. IndexType curr_cell = curr_cell_or_point - Vsize;
  101. if(CH(curr_cell,0) == -1){ //In the case of a leaf
  102. if(point_indices.at(curr_cell).size() > 0){
  103. //Assumption: Leaves either have one point, or none
  104. queue.push(point_indices.at(curr_cell).at(0));
  105. }
  106. } else { //Not a leaf
  107. for(int j = 0; j < 8; j++){
  108. //+n to adjust for the octree cells
  109. queue.push(CH(curr_cell,j)+Vsize);
  110. }
  111. }
  112. }
  113. }
  114. },1000);
  115. }
  116. }
  117. #ifdef IGL_STATIC_LIBRARY
  118. // Explicit template instantiation
  119. // generated by autoexplicit.sh
  120. template void igl::knn<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, 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&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, unsigned long, 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> >&);
  121. template void igl::knn<Eigen::Matrix<double, -1, -1, 0, -1, -1>, int, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, 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&, unsigned long, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
  122. #ifdef WIN32
  123. template void igl::knn<Eigen::Matrix<double,-1,-1,0,-1,-1>,int,Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<double,-1,-1,0,-1,-1>,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 &,unsigned __int64,std::vector<std::vector<int,std::allocator<int> >,std::allocator<std::vector<int,std::allocator<int> > > > const &,Eigen::MatrixBase<Eigen::Matrix<int,-1,-1,0,-1,-1> > const &,Eigen::MatrixBase<Eigen::Matrix<double,-1,-1,0,-1,-1> > const &,Eigen::MatrixBase<Eigen::Matrix<double,-1,1,0,-1,1> > const &,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,-1,0,-1,-1> > &);
  124. template void igl::knn<Eigen::Matrix<double,-1,-1,0,-1,-1>,Eigen::Matrix<double,-1,-1,0,-1,-1>,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 &,Eigen::MatrixBase<Eigen::Matrix<double,-1,-1,0,-1,-1> > const &,unsigned __int64,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> > &);
  125. #endif
  126. #endif