2
0

main.cpp 5.6 KB

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