main.cpp 5.8 KB

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