main.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. #include "tutorial_shared_path.h"
  2. #include <igl/fast_winding_number.h>
  3. #include <igl/read_triangle_mesh.h>
  4. #include <igl/slice_mask.h>
  5. #include <Eigen/Geometry>
  6. #include <igl/octree.h>
  7. #include <igl/barycenter.h>
  8. #include <igl/knn.h>
  9. #include <igl/random_points_on_mesh.h>
  10. #include <igl/bounding_box_diagonal.h>
  11. #include <igl/per_face_normals.h>
  12. #include <igl/copyleft/cgal/point_areas.h>
  13. #include <igl/opengl/glfw/Viewer.h>
  14. #include <igl/get_seconds.h>
  15. #include <iostream>
  16. #include <cstdlib>
  17. int main(int argc, char *argv[])
  18. {
  19. const auto time = [](std::function<void(void)> func)->double
  20. {
  21. const double t_before = igl::get_seconds();
  22. func();
  23. const double t_after = igl::get_seconds();
  24. return t_after-t_before;
  25. };
  26. Eigen::MatrixXd V;
  27. Eigen::MatrixXi F;
  28. igl::read_triangle_mesh(argc>1?argv[1]:TUTORIAL_SHARED_PATH "/bunny.off",V,F);
  29. // Sample mesh for point cloud
  30. Eigen::MatrixXd P,N;
  31. {
  32. Eigen::VectorXi I;
  33. Eigen::SparseMatrix<double> B;
  34. igl::random_points_on_mesh(10000,V,F,B,I);
  35. P = B*V;
  36. Eigen::MatrixXd FN;
  37. igl::per_face_normals(V,F,FN);
  38. N.resize(P.rows(),3);
  39. for(int p = 0;p<I.rows();p++)
  40. {
  41. N.row(p) = FN.row(I(p));
  42. }
  43. }
  44. // Build octree
  45. std::vector<std::vector<int > > O_PI;
  46. Eigen::MatrixXi O_CH;
  47. Eigen::MatrixXd O_CN;
  48. Eigen::VectorXd O_W;
  49. igl::octree(P,O_PI,O_CH,O_CN,O_W);
  50. Eigen::VectorXd A;
  51. {
  52. Eigen::MatrixXi I;
  53. igl::knn(P,20,O_PI,O_CH,O_CN,O_W,I);
  54. // CGAL is only used to help get point areas
  55. igl::copyleft::cgal::point_areas(P,I,N,A);
  56. }
  57. if(argc<=1)
  58. {
  59. // corrupt mesh
  60. Eigen::MatrixXd BC;
  61. igl::barycenter(V,F,BC);
  62. Eigen::MatrixXd OV = V;
  63. V.resize(F.rows()*3,3);
  64. for(int f = 0;f<F.rows();f++)
  65. {
  66. for(int c = 0;c<3;c++)
  67. {
  68. int v = f+c*F.rows();
  69. // random rotation about barycenter
  70. Eigen::AngleAxisd R(
  71. 0.5*static_cast <double> (rand()) / static_cast <double> (RAND_MAX),
  72. Eigen::Vector3d::Random(3,1));
  73. V.row(v) = (OV.row(F(f,c))-BC.row(f))*R.matrix()+BC.row(f);
  74. F(f,c) = v;
  75. }
  76. }
  77. }
  78. // Generate a list of random query points in the bounding box
  79. Eigen::MatrixXd Q = Eigen::MatrixXd::Random(1000000,3);
  80. const Eigen::RowVector3d Vmin = V.colwise().minCoeff();
  81. const Eigen::RowVector3d Vmax = V.colwise().maxCoeff();
  82. const Eigen::RowVector3d Vdiag = Vmax-Vmin;
  83. for(int q = 0;q<Q.rows();q++)
  84. {
  85. Q.row(q) = (Q.row(q).array()*0.5+0.5)*Vdiag.array() + Vmin.array();
  86. }
  87. // Positions of points inside of point cloud P
  88. Eigen::MatrixXd QiP;
  89. {
  90. Eigen::MatrixXd O_CM;
  91. Eigen::VectorXd O_R;
  92. Eigen::MatrixXd O_EC;
  93. printf(" point cloud precomputation: %g secs\n",
  94. time([&](){igl::fast_winding_number(P,N,A,O_PI,O_CH,2,O_CM,O_R,O_EC);}));
  95. Eigen::VectorXd WiP;
  96. printf(" point cloud evaluation: %g secs\n",
  97. time([&](){igl::fast_winding_number(P,N,A,O_PI,O_CH,O_CM,O_R,O_EC,Q,2,WiP);}));
  98. igl::slice_mask(Q,WiP.array()>0.5,1,QiP);
  99. }
  100. // Positions of points inside of triangle soup (V,F)
  101. Eigen::MatrixXd QiV;
  102. {
  103. igl::FastWindingNumberBVH fwn_bvh;
  104. printf("triangle soup precomputation: %g secs\n",
  105. time([&](){igl::fast_winding_number(V.cast<float>(),F,2,fwn_bvh);}));
  106. Eigen::VectorXf WiV;
  107. printf(" triangle soup evaluation: %g secs\n",
  108. time([&](){igl::fast_winding_number(fwn_bvh,2,Q.cast<float>(),WiV);}));
  109. igl::slice_mask(Q,WiV.array()>0.5,1,QiV);
  110. }
  111. // Visualization
  112. igl::opengl::glfw::Viewer viewer;
  113. // For dislpaying normals as little line segments
  114. Eigen::MatrixXd PN(2*P.rows(),3);
  115. Eigen::MatrixXi E(P.rows(),2);
  116. const double bbd = igl::bounding_box_diagonal(V);
  117. for(int p = 0;p<P.rows();p++)
  118. {
  119. E(p,0) = 2*p;
  120. E(p,1) = 2*p+1;
  121. PN.row(E(p,0)) = P.row(p);
  122. PN.row(E(p,1)) = P.row(p)+bbd*0.01*N.row(p);
  123. }
  124. bool show_P = false;
  125. int show_Q = 0;
  126. int query_data = 0;
  127. viewer.data_list[query_data].set_mesh(V,F);
  128. viewer.data_list[query_data].clear();
  129. viewer.data_list[query_data].point_size = 2;
  130. viewer.append_mesh();
  131. int object_data = 1;
  132. viewer.data_list[object_data].set_mesh(V,F);
  133. viewer.data_list[object_data].point_size = 5;
  134. const auto update = [&]()
  135. {
  136. viewer.data_list[query_data].clear();
  137. switch(show_Q)
  138. {
  139. case 1:
  140. // show all Q
  141. viewer.data_list[query_data].set_points(Q,Eigen::RowVector3d(0.996078,0.760784,0.760784));
  142. break;
  143. case 2:
  144. // show all Q inside
  145. if(show_P)
  146. {
  147. viewer.data_list[query_data].set_points(QiP,Eigen::RowVector3d(0.564706,0.847059,0.768627));
  148. }else
  149. {
  150. viewer.data_list[query_data].set_points(QiV,Eigen::RowVector3d(0.564706,0.847059,0.768627));
  151. }
  152. break;
  153. }
  154. viewer.data_list[object_data].clear();
  155. if(show_P)
  156. {
  157. viewer.data_list[object_data].set_points(P,Eigen::RowVector3d(1,1,1));
  158. viewer.data_list[object_data].set_edges(PN,E,Eigen::RowVector3d(0.8,0.8,0.8));
  159. }else
  160. {
  161. viewer.data_list[object_data].set_mesh(V,F);
  162. }
  163. };
  164. viewer.callback_key_pressed =
  165. [&](igl::opengl::glfw::Viewer &, unsigned int key, int mod)
  166. {
  167. switch(key)
  168. {
  169. default:
  170. return false;
  171. case '1':
  172. show_P = !show_P;
  173. break;
  174. case '2':
  175. show_Q = (show_Q+1) % 3;
  176. break;
  177. }
  178. update();
  179. return true;
  180. };
  181. update();
  182. viewer.launch();
  183. }