build_octree.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. #include "build_octree.h"
  2. #include <vector>
  3. #include <queue>
  4. const int MAX_DEPTH = 1000;
  5. int get_octant(const Eigen::RowVector3d & location, const Eigen::RowVector3d & center){
  6. //Binary numbering of children:
  7. //if we treat location as the origin,
  8. //first bit is 1 if x is positive, 0 if not
  9. //second bit is 1 if y is positive, 0 if not
  10. //third bit is 1 if z is positive, 0 if not
  11. //for example, the quadrant with negative x, positive y, positive z is:
  12. //110 binary = 6 decimal
  13. int index = 0;
  14. if( location(0) >= center(0)){
  15. index = index + 1;
  16. }
  17. if( location(1) >= center(1)){
  18. index = index + 2;
  19. }
  20. if( location(2) >= center(2)){
  21. index = index + 4;
  22. }
  23. return index;
  24. }
  25. Eigen::RowVector3d translate_center(const Eigen::RowVector3d & parent_center, double h, int child_index){
  26. Eigen::RowVector3d change_vector;
  27. change_vector << h,h,h;
  28. if(child_index % 2){ //positive x chilren are 1,3,4,7
  29. change_vector(0) = -h;
  30. }
  31. if(child_index == 2 || child_index == 3 ||
  32. child_index == 6 || child_index == 7){ //positive y children are 2,3,6,7
  33. change_vector(1) = -h;
  34. }
  35. if(child_index > 3){ //positive z children are 4,5,6,7
  36. change_vector(2) = -h;
  37. }
  38. return parent_center - change_vector;
  39. }
  40. void build_octree(const Eigen::MatrixXd & P,
  41. std::vector<std::vector<int> > & point_indices,
  42. std::vector<Eigen::Matrix<int,8,1>, Eigen::aligned_allocator<Eigen::Matrix<int,8,1>>> & children,
  43. std::vector<Eigen::RowVector3d, Eigen::aligned_allocator<Eigen::RowVector3d>> & centers,
  44. std::vector<double> & widths
  45. ){
  46. typedef Eigen::Matrix<int,8,1> Vector8i;
  47. typedef Eigen::Matrix<double,8,1> Vector8d;
  48. // How many cells do we have so far?
  49. int m = 0;
  50. // Useful list of number 0..7
  51. const Vector8i zero_to_seven = (Vector8i()<<0,1,2,3,4,5,6,7).finished();
  52. const Vector8i neg_ones = (Vector8i()<<-1,-1,-1,-1,-1,-1,-1,-1).finished();
  53. // This function variable needs to be declared before it is defined so that
  54. // you can capture it and call it recursively. Annoyingly this means you need
  55. // to fill in the function prototype here, too.
  56. std::function< void(const int, const int) > helper;
  57. helper = [
  58. // These variables from the parent scope are "captured" you can read and
  59. // write to them
  60. &helper,
  61. &zero_to_seven,&neg_ones,&P,&point_indices,&children,&centers,&widths,&m]
  62. // The "-> bool" means that this function will return bool (I don't think
  63. // you need this, but in case you do.)
  64. (const int index, const int depth)-> void
  65. {
  66. if(point_indices.at(index).size() > 1 && depth < MAX_DEPTH){
  67. //give the parent access to the children
  68. children.at(index) = zero_to_seven.array() + m;
  69. //make the children's data in our arrays
  70. //Add the children to the lists, as default children
  71. double h = widths.at(index)/2;
  72. Eigen::RowVector3d curr_center = centers.at(index);
  73. for(int i = 0; i < 8; i++){
  74. children.emplace_back(-1 * Eigen::MatrixXi::Ones(8,1));
  75. point_indices.emplace_back(std::vector<int>());
  76. centers.emplace_back(translate_center(curr_center,h,i));
  77. widths.emplace_back(h);
  78. }
  79. //Split up the points into the corresponding children
  80. for(int j = 0; j < point_indices.at(index).size(); j++){
  81. int curr_point_index = point_indices.at(index).at(j);
  82. int cell_of_curr_point = get_octant(P.row(curr_point_index),curr_center)+m;
  83. point_indices.at(cell_of_curr_point).emplace_back(curr_point_index);
  84. }
  85. //Now increase m
  86. m += 8;
  87. // Look ma, I'm calling myself.
  88. for(int i = 0; i < 8; i++){
  89. helper(children.at(index)(i),depth+1);
  90. }
  91. }
  92. };
  93. {
  94. std::vector<int> all(P.rows());
  95. for(int i = 0;i<all.size();i++) all[i]=i;
  96. point_indices.emplace_back(all);
  97. }
  98. children.emplace_back(-1 * Eigen::MatrixXi::Ones(8,1));
  99. //Get the minimum AABB for the points
  100. Eigen::RowVector3d backleftbottom(P.col(0).minCoeff(),P.col(1).minCoeff(),P.col(2).minCoeff());
  101. Eigen::RowVector3d frontrighttop(P.col(0).maxCoeff(),P.col(1).maxCoeff(),P.col(2).maxCoeff());
  102. Eigen::RowVector3d aabb_center = (backleftbottom+frontrighttop)/2.0;
  103. double aabb_width = std::max(std::max(frontrighttop(0) - backleftbottom(0),
  104. frontrighttop(1) - backleftbottom(1)),
  105. frontrighttop(2) - backleftbottom(2));
  106. centers.emplace_back( aabb_center );
  107. widths.emplace_back( aabb_width ); //Widths are the side length of the cube, (not half the side length)
  108. m++;
  109. // then you have to actually call the function
  110. helper(0,0);
  111. assert(point_indices.size() == m);
  112. assert(children.size() == m);
  113. assert(centers.size() == m);
  114. assert(widths.size() == m);
  115. }
  116. //}
  117. //#ifndef IGL_STATIC_LIBRARY
  118. //# include "point_areas_and_normals.cpp"
  119. //#endif
  120. //#endif