main.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  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 (% 8ld points): %g secs\n",
  94. P.rows(),
  95. time([&](){igl::fast_winding_number(P,N,A,O_PI,O_CH,2,O_CM,O_R,O_EC);}));
  96. Eigen::VectorXd WiP;
  97. printf(" point cloud evaluation (% 8ld queries): %g secs\n",
  98. Q.rows(),
  99. time([&](){igl::fast_winding_number(P,N,A,O_PI,O_CH,O_CM,O_R,O_EC,Q,2,WiP);}));
  100. igl::slice_mask(Q,(WiP.array()>0.5).eval(),1,QiP);
  101. }
  102. // Positions of points inside of triangle soup (V,F)
  103. Eigen::MatrixXd QiV;
  104. {
  105. igl::FastWindingNumberBVH fwn_bvh;
  106. printf("triangle soup precomputation (% 8ld triangles): %g secs\n",
  107. F.rows(),
  108. time([&](){igl::fast_winding_number(V.cast<float>().eval(),F,2,fwn_bvh);}));
  109. Eigen::VectorXf WiV;
  110. printf(" triangle soup evaluation (% 8ld queries): %g secs\n",
  111. Q.rows(),
  112. time([&](){igl::fast_winding_number(fwn_bvh,2,Q.cast<float>().eval(),WiV);}));
  113. igl::slice_mask(Q,WiV.array()>0.5,1,QiV);
  114. }
  115. // Visualization
  116. igl::opengl::glfw::Viewer viewer;
  117. // For dislpaying normals as little line segments
  118. Eigen::MatrixXd PN(2*P.rows(),3);
  119. Eigen::MatrixXi E(P.rows(),2);
  120. const double bbd = igl::bounding_box_diagonal(V);
  121. for(int p = 0;p<P.rows();p++)
  122. {
  123. E(p,0) = 2*p;
  124. E(p,1) = 2*p+1;
  125. PN.row(E(p,0)) = P.row(p);
  126. PN.row(E(p,1)) = P.row(p)+bbd*0.01*N.row(p);
  127. }
  128. bool show_P = false;
  129. int show_Q = 0;
  130. int query_data = 0;
  131. viewer.data_list[query_data].set_mesh(V,F);
  132. viewer.data_list[query_data].clear();
  133. viewer.data_list[query_data].point_size = 2;
  134. viewer.append_mesh();
  135. int object_data = 1;
  136. viewer.data_list[object_data].set_mesh(V,F);
  137. viewer.data_list[object_data].point_size = 5;
  138. const auto update = [&]()
  139. {
  140. viewer.data_list[query_data].clear();
  141. switch(show_Q)
  142. {
  143. case 1:
  144. // show all Q
  145. viewer.data_list[query_data].set_points(Q,Eigen::RowVector3d(0.996078,0.760784,0.760784));
  146. break;
  147. case 2:
  148. // show all Q inside
  149. if(show_P)
  150. {
  151. viewer.data_list[query_data].set_points(QiP,Eigen::RowVector3d(0.564706,0.847059,0.768627));
  152. }else
  153. {
  154. viewer.data_list[query_data].set_points(QiV,Eigen::RowVector3d(0.564706,0.847059,0.768627));
  155. }
  156. break;
  157. }
  158. viewer.data_list[object_data].clear();
  159. if(show_P)
  160. {
  161. viewer.data_list[object_data].set_points(P,Eigen::RowVector3d(1,1,1));
  162. viewer.data_list[object_data].set_edges(PN,E,Eigen::RowVector3d(0.8,0.8,0.8));
  163. }else
  164. {
  165. viewer.data_list[object_data].set_mesh(V,F);
  166. }
  167. };
  168. viewer.callback_key_pressed =
  169. [&](igl::opengl::glfw::Viewer &, unsigned int key, int mod)
  170. {
  171. switch(key)
  172. {
  173. default:
  174. return false;
  175. case '1':
  176. show_P = !show_P;
  177. break;
  178. case '2':
  179. show_Q = (show_Q+1) % 3;
  180. break;
  181. }
  182. update();
  183. return true;
  184. };
  185. std::cout<<R"(
  186. FastWindingNumber
  187. 1 Toggle point cloud and triangle soup
  188. 2 Toggle hiding query points, showing query points, showing inside queries
  189. )";
  190. update();
  191. viewer.launch();
  192. }