AABB.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. #include <test_common.h>
  2. #include <igl/AABB.h>
  3. #include <igl/EPS.h>
  4. #include <igl/avg_edge_length.h>
  5. #include <igl/barycenter.h>
  6. #include <igl/colon.h>
  7. #include <igl/get_seconds.h>
  8. #include <igl/point_mesh_squared_distance.h>
  9. #include <igl/point_simplex_squared_distance.h>
  10. #include <igl/randperm.h>
  11. #include <igl/read_triangle_mesh.h>
  12. #include <iostream>
  13. TEST_CASE("AABB: find_2d", "[igl]")
  14. {
  15. Eigen::MatrixXd V(6,2);
  16. V <<
  17. 0,0,
  18. 1,0,
  19. 0,1,
  20. 2,1,
  21. 2,2,
  22. 1,2;
  23. Eigen::MatrixXi F(4,3);
  24. F<<
  25. 2,0,1,
  26. 2,1,5,
  27. 5,3,4,
  28. 5,1,3;
  29. igl::AABB<Eigen::MatrixXd,2> tree;
  30. tree.init(V,F);
  31. Eigen::RowVector2d q(0.5,0.5);
  32. std::vector<int> r = tree.find(V,F,q);
  33. REQUIRE(r.size() == 2);
  34. REQUIRE(r[0] == 0);
  35. REQUIRE(r[1] == 1);
  36. }
  37. TEST_CASE("AABB: find_3d", "[igl]")
  38. {
  39. Eigen::MatrixXd V(7,3);
  40. V << 0,0,1,
  41. 1,0,1,
  42. 0,1,1,
  43. 2,1,1,
  44. 2,2,1,
  45. 1,2,1,
  46. 0,0,0;
  47. Eigen::MatrixXi F(4,4);
  48. F <<
  49. 0,1,2,6,
  50. 1,3,2,6,
  51. 3,4,5,6,
  52. 3,5,1,6;
  53. igl::AABB<Eigen::MatrixXd,3> tree;
  54. tree.init(V,F);
  55. Eigen::RowVector3d q(0.5,0.5,1.0);
  56. std::vector<int> r = tree.find(V,F,q);
  57. REQUIRE(r.size() == 2);
  58. REQUIRE(r[0] == 0);
  59. REQUIRE(r[1] == 1);
  60. }
  61. TEST_CASE("AABB: insert", "[igl]")
  62. {
  63. igl::AABB<Eigen::MatrixXd, 3> * tree = new igl::AABB<Eigen::MatrixXd, 3>();
  64. for(int i = 0;i<3;i++)
  65. {
  66. igl::AABB<Eigen::MatrixXd, 3> * leaf = new igl::AABB<Eigen::MatrixXd, 3>();
  67. leaf->m_box = Eigen::AlignedBox<double, 3>(
  68. Eigen::RowVector3d(-i,-i,-i),
  69. Eigen::RowVector3d(i,i,i));
  70. auto * ret = tree->insert(leaf);
  71. tree = ret->root();
  72. REQUIRE(leaf->is_leaf());
  73. }
  74. REQUIRE(tree->is_root());
  75. delete tree;
  76. }
  77. TEST_CASE("AABB: dynamic", "[igl]")
  78. {
  79. const int MAX_RUNS = 10;
  80. const auto test_case = [&MAX_RUNS](const std::string &param)
  81. {
  82. IGL_TICTOC_LAMBDA;
  83. Eigen::MatrixXd V;
  84. Eigen::MatrixXi F;
  85. // Load example mesh: GetParam() will be name of mesh file
  86. igl::read_triangle_mesh(test_common::data_path(param), V, F);
  87. // Make into soup
  88. V = V(Eigen::Map<Eigen::VectorXi>(F.data(),F.size()), Eigen::placeholders::all).eval();
  89. F = Eigen::Map<Eigen::MatrixXi>(igl::colon<int>(0,V.rows()-1).data(),V.rows()/3,3).eval();
  90. Eigen::MatrixXd BC;
  91. igl::barycenter(V,F,BC);
  92. Eigen::VectorXi I_gt = igl::colon<int>(0,F.rows()-1);
  93. Eigen::VectorXd sqrD_gt = Eigen::VectorXd::Zero(F.rows());
  94. Eigen::VectorXd sqrD;
  95. Eigen::VectorXi I;
  96. Eigen::MatrixXd C;
  97. igl::AABB<Eigen::MatrixXd, 3> * tree = new igl::AABB<Eigen::MatrixXd, 3>();
  98. tree->init(V,F);
  99. tictoc();
  100. tree->squared_distance(V,F,BC,sqrD,I,C);
  101. const double t0 = tictoc();
  102. test_common::assert_eq(I,I_gt);
  103. test_common::assert_near(sqrD,sqrD_gt,1e-15);
  104. REQUIRE(tree->size() == 2*F.rows()-1);
  105. const double pad = igl::EPS<double>();
  106. const double h = igl::avg_edge_length(V,F);
  107. const auto leaves = tree->gather_leaves(F.rows());
  108. for(auto * leaf : leaves)
  109. {
  110. REQUIRE(leaf);
  111. REQUIRE(leaf->is_leaf());
  112. }
  113. // This is slow. Only test on small meshes
  114. if(F.rows() < 4000)
  115. {
  116. // Gather list of pointers to leaves and pad by ε to force rebuild
  117. tree = tree->pad(leaves,pad,2);
  118. REQUIRE(tree->is_root());
  119. REQUIRE(tree == tree->root());
  120. for(auto * leaf : leaves)
  121. {
  122. REQUIRE(leaf);
  123. REQUIRE(leaf->is_leaf());
  124. }
  125. tictoc();
  126. tree->squared_distance(V,F,BC,sqrD,I,C);
  127. const double t1 = tictoc();
  128. REQUIRE(t1 < 10*t0);
  129. test_common::assert_eq(I,I_gt);
  130. test_common::assert_near(sqrD,sqrD_gt,1e-15);
  131. REQUIRE(tree->size() == 2*F.rows()-1);
  132. }
  133. #ifndef NDEBUG
  134. if(F.rows()>10000)
  135. {
  136. std::cerr<<"#ifndef NDEBUG: Skipping timing test."<<std::endl;
  137. delete tree;
  138. return;
  139. }
  140. #endif
  141. Eigen::VectorXi RV;
  142. Eigen::VectorXi RF;
  143. // Perturb a small subset of the triangles
  144. {
  145. {
  146. igl::randperm(F.rows(),RF);
  147. RF = RF.topRows(std::min(12,(int)F.rows())).eval();
  148. RV.resize(RF.size()*3);
  149. RV << RF, RF.array()+F.rows(), RF.array()+2*F.rows();
  150. }
  151. Eigen::MatrixXd TF = 0.1*h*Eigen::MatrixXd::Random(RF.size(),3);
  152. Eigen::MatrixXd TV(RV.rows(),3);
  153. TV<<TF,TF,TF;
  154. V(RV,Eigen::placeholders::all) += TV;
  155. igl::barycenter(V,F,BC);
  156. }
  157. const int qi = RF(0);
  158. double t_dynamic_tree;
  159. {
  160. tictoc();
  161. // update those perturbed triangles
  162. for(int i = 0;i<RF.size();i++)
  163. {
  164. tree = leaves[RF(i)]->update_primitive(V,F,pad)->root();
  165. }
  166. const double t_refit = tictoc();
  167. for(int r = 0;r<MAX_RUNS;r++)
  168. {
  169. tree->squared_distance(V,F,Eigen::MatrixXd(BC.row(qi)),sqrD,I,C);
  170. }
  171. const double t_query = tictoc()/MAX_RUNS;
  172. REQUIRE(I(0) == qi);
  173. t_dynamic_tree = t_refit+t_query;
  174. }
  175. double t_static_tree;
  176. {
  177. tictoc();
  178. for(int r = 0;r<MAX_RUNS;r++)
  179. {
  180. igl::point_mesh_squared_distance(
  181. Eigen::MatrixXd(BC.row(qi)),V,F,sqrD,I,C);
  182. }
  183. t_static_tree = tictoc()/MAX_RUNS;
  184. REQUIRE(I(0) == qi);
  185. }
  186. double t_brute_force;
  187. {
  188. tictoc();
  189. double min_dist;
  190. int min_i;
  191. for(int r = 0;r<MAX_RUNS;r++)
  192. {
  193. min_dist = std::numeric_limits<double>::infinity();
  194. min_i = -1;
  195. Eigen::RowVector3d q = Eigen::RowVector3d(BC.row(qi));
  196. for(int i = 0;i<F.rows();i++)
  197. {
  198. Eigen::RowVector3d c;
  199. double d;
  200. igl::point_simplex_squared_distance<3>(q,V,F,i,d,c);
  201. if(d < min_dist)
  202. {
  203. min_dist = d;
  204. min_i = i;
  205. }
  206. }
  207. }
  208. t_brute_force = tictoc()/MAX_RUNS;
  209. REQUIRE(min_i == qi);
  210. }
  211. // Only compare speeds on large meshes
  212. if(F.rows() > 300)
  213. {
  214. REQUIRE(t_dynamic_tree < t_static_tree);
  215. REQUIRE(t_dynamic_tree < t_brute_force);
  216. }
  217. delete tree;
  218. };
  219. test_common::run_test_cases(test_common::all_meshes(), test_case);
  220. }