main.cpp 4.4 KB

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