main.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. #include <igl/AABB.h>
  2. #include <igl/box_faces.h>
  3. #include <igl/placeholders.h>
  4. #include <igl/colon.h>
  5. #include <igl/find.h>
  6. #include <igl/get_seconds.h>
  7. #include <igl/per_face_normals.h>
  8. #include <igl/quad_edges.h>
  9. #include <igl/read_triangle_mesh.h>
  10. #include <igl/unproject_ray.h>
  11. #include <igl/opengl/glfw/Viewer.h>
  12. #include <limits>
  13. #include <deque>
  14. #include <stdio.h>
  15. int main(int argc, char *argv[])
  16. {
  17. Eigen::MatrixXd V,N;
  18. Eigen::MatrixXi F;
  19. igl::read_triangle_mesh(
  20. argc>1?argv[1]:TUTORIAL_SHARED_PATH "/decimated-knight.off",V,F);
  21. // Make mesh into disconnected soup
  22. V = V(Eigen::Map<Eigen::VectorXi>(F.data(),F.size()), igl::placeholders::all).eval();
  23. F = Eigen::Map<Eigen::MatrixXi>(igl::colon<int>(0,V.rows()-1).data(),V.rows()/3,3).eval();
  24. // Cache normals
  25. igl::per_face_normals(V,F,N);
  26. // Build an initial tree. Store as pointer so we can update root.
  27. auto * tree = new igl::AABB<Eigen::MatrixXd, 3>();
  28. tree->init(V,F);
  29. // Gather leaf pointers (these are stable)
  30. const auto leaves = tree->gather_leaves(F.rows());
  31. // Set up visualization and interaction
  32. igl::opengl::glfw::Viewer vr;
  33. Eigen::MatrixXd C = Eigen::RowVector3d(0.9,0.9,0.9).replicate(F.rows(),1);
  34. vr.data().set_mesh(V,F);
  35. vr.data().set_face_based(true);
  36. vr.data().set_colors(C);
  37. // draw the boxes of the tree at a given depth
  38. int depth = 0;
  39. Eigen::MatrixXd TV;
  40. Eigen::MatrixXi TQ;
  41. Eigen::VectorXi TD;
  42. const auto update_edges = [&]()
  43. {
  44. Eigen::MatrixXi TQd = TQ(igl::find((TD.array()==depth).eval()),igl::placeholders::all);
  45. Eigen::MatrixXi TE;
  46. igl::quad_edges(TQd,TE);
  47. vr.data().set_edges(TV,TE,Eigen::RowVector3d(1,1,1));
  48. vr.data().line_width = 2;
  49. };
  50. const auto update_tree_vis = [&]()
  51. {
  52. igl::box_faces(*tree,TV,TQ,TD);
  53. update_edges();
  54. };
  55. // Update the tree for each triangle in hits which might have moved.
  56. const auto update_tree = [&](const std::vector<igl::Hit> & hits)
  57. {
  58. for(const auto hit : hits)
  59. {
  60. const int fid = hit.id;
  61. Eigen::AlignedBox<double,3> box;
  62. box.extend(V.row(F(fid,0)).transpose());
  63. box.extend(V.row(F(fid,1)).transpose());
  64. box.extend(V.row(F(fid,2)).transpose());
  65. // This is O(height) which is typically O(log n)
  66. tree = leaves[fid]->update(box,0)->root();
  67. }
  68. // update the visualization. This is O(n) 🙃
  69. update_tree_vis();
  70. };
  71. update_tree_vis();
  72. std::vector<igl::Hit> hits;
  73. Eigen::RowVector3d dir;
  74. Eigen::RowVector3d red(1,0.2,0.2);
  75. vr.callback_pre_draw = [&](decltype(vr) &)->bool
  76. {
  77. // While mouse is down, pull front (back) faces towards (away from) cursor.
  78. if(hits.size())
  79. {
  80. for(const auto hit : hits)
  81. {
  82. for(int c : {0,1,2})
  83. {
  84. const int fid = hit.id;
  85. V.row(F(fid,c)) +=
  86. ((N.row(fid).dot(dir))>0?1:-1) *
  87. 0.001*dir.cast<double>().transpose();
  88. C.row(fid) = red;
  89. }
  90. }
  91. // Things have moved, so update tree ~O(#hits log n)
  92. update_tree(hits);
  93. // update viewer. This is O(n) 🙃
  94. vr.data().set_vertices(V);
  95. vr.data().set_colors(C);
  96. }
  97. return false;
  98. };
  99. vr.callback_mouse_down = [&](decltype(vr) &, int button, int modifier)->bool
  100. {
  101. // Shoot a ray through cursor into mesh accelerated by current AABB tree
  102. const Eigen::Vector2f pos(
  103. vr.current_mouse_x,vr.core().viewport(3)-vr.current_mouse_y);
  104. const auto model = vr.core().view;
  105. const auto proj = vr.core().proj;
  106. const auto viewport = vr.core().viewport;
  107. Eigen::RowVector3d src;
  108. {
  109. Eigen::Vector3f src_f,dir_f;
  110. igl::unproject_ray(pos,model,proj,viewport,src_f,dir_f);
  111. src = src_f.cast<double>().transpose();
  112. dir = dir_f.cast<double>().transpose();
  113. }
  114. if(tree->intersect_ray(V,F,src,dir,hits))
  115. {
  116. vr.core().is_animating = true;
  117. return true;
  118. }
  119. return false;
  120. };
  121. vr.callback_mouse_up = [&](decltype(vr) &, int button, int modifier)->bool
  122. {
  123. hits.clear();
  124. vr.core().is_animating = false;
  125. return false;
  126. };
  127. vr.callback_key_pressed = [&](decltype(vr) &,unsigned int key, int mod)
  128. {
  129. switch(key)
  130. {
  131. case ',':
  132. case '.':
  133. depth = std::max(depth+(key==','?-1:1),0);
  134. update_edges();
  135. return true;
  136. default:
  137. return false;
  138. }
  139. };
  140. printf(" ,/. to change tree-vis depth\n");
  141. printf(" Click and hold to push triangles\n");
  142. vr.launch();
  143. // delete the tree (and all subtrees/leaves)
  144. delete tree;
  145. }