main.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. #include <igl/opengl/glfw/Viewer.h>
  2. #include <igl/get_seconds.h>
  3. #include <igl/readDMAT.h>
  4. #include <igl/triangulated_grid.h>
  5. #include <igl/box_simplices.h>
  6. #include <igl/eytzinger_aabb.h>
  7. #include <igl/eytzinger_aabb_sdf.h>
  8. #include <igl/eytzinger_aabb_winding_number_tree.h>
  9. #include <igl/eytzinger_aabb_winding_number.h>
  10. double sdCapsule(
  11. const Eigen::RowVector2d & p,
  12. const Eigen::RowVector2d & a,
  13. const Eigen::RowVector2d & b,
  14. const double & r )
  15. {
  16. using Scalar = double;
  17. Eigen::RowVector2d pa = p - a, ba = b - a;
  18. Scalar h = std::max(Scalar(0), std::min(Scalar(1), pa.dot(ba)/ba.dot(ba)));
  19. return (pa - ba*h).norm() - r;
  20. }
  21. int main(int argc, char * argv[])
  22. {
  23. IGL_TICTOC_LAMBDA;
  24. Eigen::MatrixXd V;
  25. Eigen::MatrixXi E;
  26. igl::readDMAT(argc>1?argv[1]: TUTORIAL_SHARED_PATH "/libigl-cursive-V.dmat",V);
  27. igl::readDMAT(argc>1?argv[2]: TUTORIAL_SHARED_PATH "/libigl-cursive-E.dmat",E);
  28. Eigen::MatrixXi F(E.rows(),3);
  29. F<<E,E.col(1);
  30. Eigen::MatrixXd GV;
  31. Eigen::MatrixXi GF;
  32. {
  33. Eigen::RowVector2d min_corner = V.colwise().minCoeff();
  34. Eigen::RowVector2d max_corner = V.colwise().maxCoeff();
  35. // samples on x-axis
  36. const int sx = 512;
  37. const int sy = sx * (max_corner(1)-min_corner(1)) / (max_corner(0)-min_corner(0));
  38. Eigen::RowVector2d diag = (max_corner - min_corner).eval();
  39. const double bbd = diag.norm();
  40. diag /= diag.norm();
  41. min_corner -= 0.1*bbd*diag;
  42. max_corner += 0.1*bbd*diag;
  43. igl::triangulated_grid(sx,sy,GV,GF);
  44. // Scale and translate grid to fit bounding box
  45. GV.col(0) = (GV.col(0).array() * (max_corner(0)-min_corner(0))) + min_corner(0);
  46. GV.col(1) = (GV.col(1).array() * (max_corner(1)-min_corner(1))) + min_corner(1);
  47. }
  48. tictoc();
  49. Eigen::Matrix<double,Eigen::Dynamic,2,Eigen::RowMajor> EB1,EB2;
  50. igl::box_simplices(V,E,EB1,EB2);
  51. Eigen::Matrix<double,Eigen::Dynamic,2,Eigen::RowMajor> B1,B2;
  52. Eigen::VectorXi leaf;
  53. igl::eytzinger_aabb(EB1,EB2,B1,B2,leaf);
  54. printf("AABB build: %f s\n",tictoc());
  55. Eigen::VectorXi I,C;
  56. igl::eytzinger_aabb_winding_number_tree(E,leaf,I,C);
  57. printf("Winding number tree build: %f s\n",tictoc());
  58. igl::opengl::glfw::Viewer viewer;
  59. viewer.data().set_mesh(GV,GF);
  60. enum Quantity
  61. {
  62. SIGNED_DISTANCE,
  63. UNSIGNED_DISTANCE,
  64. WINDING_NUMBER
  65. } quantity = SIGNED_DISTANCE;
  66. bool naive = false;
  67. const auto update = [&]()
  68. {
  69. tictoc();
  70. Eigen::VectorXd D(GV.rows());
  71. for(int i=0;i<GV.rows();i++)
  72. {
  73. Eigen::RowVector2d p = GV.row(i);
  74. double di,wi;
  75. if(naive)
  76. {
  77. di = std::numeric_limits<double>::infinity();
  78. wi = 0;
  79. for(int e = 0;e<E.rows();e++)
  80. {
  81. if(quantity == UNSIGNED_DISTANCE || quantity == SIGNED_DISTANCE)
  82. {
  83. double d = sdCapsule(
  84. p,
  85. V.row(E(e,0)),
  86. V.row(E(e,1)),
  87. 0.0);
  88. if(d < di){ di = d; }
  89. }
  90. if(quantity == WINDING_NUMBER || quantity == SIGNED_DISTANCE)
  91. {
  92. double angle = std::atan2(
  93. (V(E(e,0),0)-p(0))*(V(E(e,1),1)-p(1)) - (V(E(e,0),1)-p(1))*(V(E(e,1),0)-p(0)),
  94. (V(E(e,0),0)-p(0))*(V(E(e,1),0)-p(0)) + (V(E(e,0),1)-p(1))*(V(E(e,1),1)-p(1))
  95. );
  96. wi += angle;
  97. }
  98. }
  99. }else
  100. {
  101. const std::function<double(const int)> primitive_p = [&](const int e)-> double
  102. {
  103. double d = sdCapsule(
  104. p,
  105. V.row(E(e,0)),
  106. V.row(E(e,1)),
  107. 0.0);
  108. return d;
  109. };
  110. if(quantity == UNSIGNED_DISTANCE || quantity == SIGNED_DISTANCE)
  111. {
  112. igl::eytzinger_aabb_sdf<false>(p,primitive_p,B1,B2,leaf,di);
  113. }
  114. if(quantity == WINDING_NUMBER || quantity == SIGNED_DISTANCE)
  115. {
  116. igl::eytzinger_aabb_winding_number(p,V,E,B1,B2,leaf,I,C,wi);
  117. }
  118. }
  119. switch(quantity)
  120. {
  121. case SIGNED_DISTANCE:
  122. D(i) = di * (std::abs(wi) > 0.5?-1:1);
  123. break;
  124. case UNSIGNED_DISTANCE:
  125. D(i) = di;
  126. break;
  127. case WINDING_NUMBER:
  128. D(i) = wi;
  129. break;
  130. }
  131. }
  132. printf("Compute %s %s: %f s\n",
  133. naive?"naive":"aabb",
  134. quantity==SIGNED_DISTANCE?"signed distance":
  135. quantity==UNSIGNED_DISTANCE?"unsigned distance":"winding number",
  136. tictoc());
  137. viewer.data().set_data(D);
  138. };
  139. update();
  140. viewer.data().show_lines = false;
  141. viewer.data().line_width = 2;
  142. viewer.core().lighting_factor = 0;
  143. viewer.data().set_edges(V,E,Eigen::RowVector3d(0,0,0));
  144. // key
  145. viewer.callback_key_pressed = [&](igl::opengl::glfw::Viewer &, unsigned int key, int mod)->bool
  146. {
  147. switch(key)
  148. {
  149. default:
  150. return false;
  151. case 'N':
  152. case 'n':
  153. naive = !naive;
  154. break;
  155. case 'W':
  156. case 'w':
  157. quantity = WINDING_NUMBER;
  158. break;
  159. case 'U':
  160. case 'u':
  161. quantity = UNSIGNED_DISTANCE;
  162. break;
  163. case 'S':
  164. case 's':
  165. quantity = SIGNED_DISTANCE;
  166. break;
  167. }
  168. update();
  169. return true;
  170. };
  171. std::cout<<R"(
  172. S,s Signed distance
  173. W,w Winding number
  174. U,u Unsigned distance
  175. N,n Toggle naive / accelerated
  176. )"<<std::endl;
  177. viewer.launch();
  178. return 0;
  179. }