test_aabbindirect.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. #include <algorithm>
  2. #include <catch2/catch.hpp>
  3. #include <test_utils.hpp>
  4. #include <libslic3r/TriangleMesh.hpp>
  5. #include <libslic3r/AABBTreeIndirect.hpp>
  6. #include <libslic3r/AABBTreeLines.hpp>
  7. using namespace Slic3r;
  8. TEST_CASE("Building a tree over a box, ray caster and closest query", "[AABBIndirect]")
  9. {
  10. TriangleMesh tmesh = make_cube(1., 1., 1.);
  11. auto tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(tmesh.its.vertices, tmesh.its.indices);
  12. REQUIRE(! tree.empty());
  13. igl::Hit hit;
  14. bool intersected = AABBTreeIndirect::intersect_ray_first_hit(
  15. tmesh.its.vertices, tmesh.its.indices,
  16. tree,
  17. Vec3d(0.5, 0.5, -5.),
  18. Vec3d(0., 0., 1.),
  19. hit);
  20. REQUIRE(intersected);
  21. REQUIRE(hit.t == Approx(5.));
  22. std::vector<igl::Hit> hits;
  23. bool intersected2 = AABBTreeIndirect::intersect_ray_all_hits(
  24. tmesh.its.vertices, tmesh.its.indices,
  25. tree,
  26. Vec3d(0.3, 0.5, -5.),
  27. Vec3d(0., 0., 1.),
  28. hits);
  29. REQUIRE(intersected2);
  30. REQUIRE(hits.size() == 2);
  31. REQUIRE(hits.front().t == Approx(5.));
  32. REQUIRE(hits.back().t == Approx(6.));
  33. size_t hit_idx;
  34. Vec3d closest_point;
  35. double squared_distance = AABBTreeIndirect::squared_distance_to_indexed_triangle_set(
  36. tmesh.its.vertices, tmesh.its.indices,
  37. tree,
  38. Vec3d(0.3, 0.5, -5.),
  39. hit_idx, closest_point);
  40. REQUIRE(squared_distance == Approx(5. * 5.));
  41. REQUIRE(closest_point.x() == Approx(0.3));
  42. REQUIRE(closest_point.y() == Approx(0.5));
  43. REQUIRE(closest_point.z() == Approx(0.));
  44. squared_distance = AABBTreeIndirect::squared_distance_to_indexed_triangle_set(
  45. tmesh.its.vertices, tmesh.its.indices,
  46. tree,
  47. Vec3d(0.3, 0.5, 5.),
  48. hit_idx, closest_point);
  49. REQUIRE(squared_distance == Approx(4. * 4.));
  50. REQUIRE(closest_point.x() == Approx(0.3));
  51. REQUIRE(closest_point.y() == Approx(0.5));
  52. REQUIRE(closest_point.z() == Approx(1.));
  53. }
  54. TEST_CASE("Creating a several 2d lines, testing closest point query", "[AABBIndirect]")
  55. {
  56. std::vector<Linef> lines { };
  57. lines.push_back(Linef(Vec2d(0.0, 0.0), Vec2d(1.0, 0.0)));
  58. lines.push_back(Linef(Vec2d(1.0, 0.0), Vec2d(1.0, 1.0)));
  59. lines.push_back(Linef(Vec2d(1.0, 1.0), Vec2d(0.0, 1.0)));
  60. lines.push_back(Linef(Vec2d(0.0, 1.0), Vec2d(0.0, 0.0)));
  61. auto tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(lines);
  62. size_t hit_idx_out;
  63. Vec2d hit_point_out;
  64. auto sqr_dist = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, Vec2d(0.0, 0.0), hit_idx_out,
  65. hit_point_out);
  66. REQUIRE(sqr_dist == Approx(0.0));
  67. REQUIRE((hit_idx_out == 0 || hit_idx_out == 3));
  68. REQUIRE(hit_point_out.x() == Approx(0.0));
  69. REQUIRE(hit_point_out.y() == Approx(0.0));
  70. sqr_dist = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, Vec2d(1.5, 0.5), hit_idx_out,
  71. hit_point_out);
  72. REQUIRE(sqr_dist == Approx(0.25));
  73. REQUIRE(hit_idx_out == 1);
  74. REQUIRE(hit_point_out.x() == Approx(1.0));
  75. REQUIRE(hit_point_out.y() == Approx(0.5));
  76. }
  77. TEST_CASE("Creating a several 2d lines, testing all lines in radius query", "[AABBIndirect]")
  78. {
  79. std::vector<Linef> lines { };
  80. lines.push_back(Linef(Vec2d(0.0, 0.0), Vec2d(10.0, 0.0)));
  81. lines.push_back(Linef(Vec2d(-10.0, 10.0), Vec2d(10.0, -10.0)));
  82. lines.push_back(Linef(Vec2d(-2.0, -1.0), Vec2d(-2.0, 1.0)));
  83. lines.push_back(Linef(Vec2d(-1.0, -1.0), Vec2d(-1.0, -1.0)));
  84. lines.push_back(Linef(Vec2d(1.0, 1.0), Vec2d(1.0, 1.0)));
  85. auto tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(lines);
  86. auto indices = AABBTreeLines::all_lines_in_radius(lines, tree, Vec2d{1.0,1.0}, 4.0);
  87. REQUIRE(std::find(indices.begin(),indices.end(), 0) != indices.end());
  88. REQUIRE(std::find(indices.begin(),indices.end(), 1) != indices.end());
  89. REQUIRE(std::find(indices.begin(),indices.end(), 4) != indices.end());
  90. REQUIRE(indices.size() == 3);
  91. }
  92. TEST_CASE("Find the closest point from ExPolys", "[ClosestPoint]") {
  93. //////////////////////////////
  94. // 0 - 3
  95. // |Ex0| 0 - 3
  96. // | |p |Ex1|
  97. // 1 - 2 | |
  98. // 1 - 2
  99. //[0,0]
  100. ///////////////////
  101. ExPolygons ex_polys{
  102. /*Ex0*/ {{0, 4}, {0, 1}, {2, 1}, {2, 4}},
  103. /*Ex1*/ {{4, 3}, {4, 0}, {6, 0}, {6, 3}}
  104. };
  105. Vec2d p{2.5, 3.5};
  106. std::vector<Linef> lines;
  107. auto add_lines = [&lines](const Polygon& poly) {
  108. for (const auto &line : poly.lines())
  109. lines.emplace_back(
  110. line.a.cast<double>(),
  111. line.b.cast<double>());
  112. };
  113. for (const ExPolygon &ex_poly : ex_polys) {
  114. add_lines(ex_poly.contour);
  115. for (const Polygon &hole : ex_poly.holes)
  116. add_lines(hole);
  117. }
  118. AABBTreeIndirect::Tree<2, double> tree =
  119. AABBTreeLines::build_aabb_tree_over_indexed_lines(lines);
  120. size_t hit_idx_out = std::numeric_limits<size_t>::max();
  121. Vec2d hit_point_out;
  122. [[maybe_unused]] double distance_sq =
  123. AABBTreeLines::squared_distance_to_indexed_lines(
  124. lines, tree, p, hit_idx_out, hit_point_out, 0.24/* < (0.5*0.5) */);
  125. CHECK(hit_idx_out == std::numeric_limits<size_t>::max());
  126. distance_sq = AABBTreeLines::squared_distance_to_indexed_lines(
  127. lines, tree, p, hit_idx_out, hit_point_out, 0.26);
  128. CHECK(hit_idx_out != std::numeric_limits<size_t>::max());
  129. //double distance = sqrt(distance_sq);
  130. //const Linef &line = lines[hit_idx_out];
  131. }
  132. #if 0
  133. #include "libslic3r/EdgeGrid.hpp"
  134. #include <iostream>
  135. #include <ctime>
  136. #include <ratio>
  137. #include <chrono>
  138. TEST_CASE("AABBTreeLines vs SignedDistanceGrid time Benchmark", "[AABBIndirect]")
  139. {
  140. std::vector<Points> lines { Points { } };
  141. std::vector<Linef> linesf { };
  142. Vec2d prevf { };
  143. // NOTE: max coord value of the lines is approx 83 mm
  144. for (int r = 1; r < 1000; ++r) {
  145. lines[0].push_back(Point::new_scale(Vec2d(exp(0.005f * r) * cos(r), exp(0.005f * r) * cos(r))));
  146. linesf.emplace_back(prevf, Vec2d(exp(0.005f * r) * cos(r), exp(0.005f * r) * cos(r)));
  147. prevf = linesf.back().b;
  148. }
  149. int build_num = 10000;
  150. using namespace std::chrono;
  151. {
  152. std::cout << "building the tree " << build_num << " times..." << std::endl;
  153. high_resolution_clock::time_point t1 = high_resolution_clock::now();
  154. for (int i = 0; i < build_num; ++i) {
  155. volatile auto tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(linesf);
  156. }
  157. high_resolution_clock::time_point t2 = high_resolution_clock::now();
  158. duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
  159. std::cout << "It took " << time_span.count() << " seconds." << std::endl << std::endl;
  160. }
  161. {
  162. std::cout << "building the grid res 1mm ONLY " << build_num/100 << " !!! times..." << std::endl;
  163. high_resolution_clock::time_point t1 = high_resolution_clock::now();
  164. for (int i = 0; i < build_num/100; ++i) {
  165. EdgeGrid::Grid grid { };
  166. grid.create(lines, scaled(1.0), true);
  167. grid.calculate_sdf();
  168. }
  169. high_resolution_clock::time_point t2 = high_resolution_clock::now();
  170. duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
  171. std::cout << "It took " << time_span.count() << " seconds." << std::endl << std::endl;
  172. }
  173. {
  174. std::cout << "building the grid res 10mm " << build_num << " times..." << std::endl;
  175. high_resolution_clock::time_point t1 = high_resolution_clock::now();
  176. for (int i = 0; i < build_num; ++i) {
  177. EdgeGrid::Grid grid { };
  178. grid.create(lines, scaled(10.0), true);
  179. grid.calculate_sdf();
  180. }
  181. high_resolution_clock::time_point t2 = high_resolution_clock::now();
  182. duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
  183. std::cout << "It took " << time_span.count() << " seconds." << std::endl << std::endl;
  184. }
  185. EdgeGrid::Grid grid10 { };
  186. grid10.create(lines, scaled(10.0), true);
  187. coord_t query10_res = scaled(10.0);
  188. grid10.calculate_sdf();
  189. EdgeGrid::Grid grid1 { };
  190. grid1.create(lines, scaled(1.0), true);
  191. coord_t query1_res = scaled(1.0);
  192. grid1.calculate_sdf();
  193. auto tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(linesf);
  194. int query_num = 10000;
  195. Points query_points { };
  196. std::vector<Vec2d> query_pointsf { };
  197. for (int x = 0; x < query_num; ++x) {
  198. Vec2d qp { rand() / (double(RAND_MAX) + 1.0f) * 200.0 - 100.0, rand() / (double(RAND_MAX) + 1.0f) * 200.0
  199. - 100.0 };
  200. query_pointsf.push_back(qp);
  201. query_points.push_back(Point::new_scale(qp));
  202. }
  203. {
  204. std::cout << "querying tree " << query_num << " times..." << std::endl;
  205. high_resolution_clock::time_point t1 = high_resolution_clock::now();
  206. for (const Vec2d &qp : query_pointsf) {
  207. size_t hit_idx_out;
  208. Vec2d hit_point_out;
  209. AABBTreeLines::squared_distance_to_indexed_lines(linesf, tree, qp, hit_idx_out, hit_point_out);
  210. }
  211. high_resolution_clock::time_point t2 = high_resolution_clock::now();
  212. duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
  213. std::cout << "It took " << time_span.count() << " seconds." << std::endl << std::endl;
  214. }
  215. {
  216. std::cout << "querying grid res 1mm " << query_num << " times..." << std::endl;
  217. high_resolution_clock::time_point t1 = high_resolution_clock::now();
  218. for (const Point &qp : query_points) {
  219. volatile auto dist = grid1.closest_point_signed_distance(qp, query1_res);
  220. }
  221. high_resolution_clock::time_point t2 = high_resolution_clock::now();
  222. duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
  223. std::cout << "It took " << time_span.count() << " seconds." << std::endl << std::endl;
  224. }
  225. {
  226. std::cout << "querying grid res 10mm " << query_num << " times..." << std::endl;
  227. high_resolution_clock::time_point t1 = high_resolution_clock::now();
  228. for (const Point &qp : query_points) {
  229. volatile auto dist = grid10.closest_point_signed_distance(qp, query10_res);
  230. }
  231. high_resolution_clock::time_point t2 = high_resolution_clock::now();
  232. duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
  233. std::cout << "It took " << time_span.count() << " seconds." << std::endl << std::endl;
  234. }
  235. std::cout << "Test build and queries together - same number of contour points and query points" << std::endl << std::endl;
  236. std::vector<int> point_counts { 100, 300, 500, 1000, 3000 };
  237. for (auto count : point_counts) {
  238. std::vector<Points> lines { Points { } };
  239. std::vector<Linef> linesf { };
  240. Vec2d prevf { };
  241. Points query_points { };
  242. std::vector<Vec2d> query_pointsf { };
  243. for (int x = 0; x < count; ++x) {
  244. Vec2d cp { rand() / (double(RAND_MAX) + 1.0f) * 200.0 - 100.0, rand() / (double(RAND_MAX) + 1.0f) * 200.0
  245. - 100.0 };
  246. lines[0].push_back(Point::new_scale(cp));
  247. linesf.emplace_back(prevf, cp);
  248. prevf = linesf.back().b;
  249. Vec2d qp { rand() / (double(RAND_MAX) + 1.0f) * 200.0 - 100.0, rand() / (double(RAND_MAX) + 1.0f) * 200.0
  250. - 100.0 };
  251. query_pointsf.push_back(qp);
  252. query_points.push_back(Point::new_scale(qp));
  253. }
  254. std::cout << "Test for point count: " << count << std::endl;
  255. {
  256. high_resolution_clock::time_point t1 = high_resolution_clock::now();
  257. auto tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(linesf);
  258. for (const Vec2d &qp : query_pointsf) {
  259. size_t hit_idx_out;
  260. Vec2d hit_point_out;
  261. AABBTreeLines::squared_distance_to_indexed_lines(linesf, tree, qp, hit_idx_out, hit_point_out);
  262. }
  263. high_resolution_clock::time_point t2 = high_resolution_clock::now();
  264. duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
  265. std::cout << " Tree took " << time_span.count() << " seconds." << std::endl;
  266. }
  267. {
  268. high_resolution_clock::time_point t1 = high_resolution_clock::now();
  269. EdgeGrid::Grid grid1 { };
  270. grid1.create(lines, scaled(1.0), true);
  271. coord_t query1_res = scaled(1.0);
  272. grid1.calculate_sdf();
  273. for (const Point &qp : query_points) {
  274. volatile auto dist = grid1.closest_point_signed_distance(qp, query1_res);
  275. }
  276. high_resolution_clock::time_point t2 = high_resolution_clock::now();
  277. duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
  278. std::cout << " Grid 1mm took " << time_span.count() << " seconds." << std::endl;
  279. }
  280. {
  281. high_resolution_clock::time_point t1 = high_resolution_clock::now();
  282. EdgeGrid::Grid grid10 { };
  283. grid10.create(lines, scaled(10.0), true);
  284. coord_t query10_res = scaled(10.0);
  285. grid10.calculate_sdf();
  286. for (const Point &qp : query_points) {
  287. volatile auto dist = grid10.closest_point_signed_distance(qp, query10_res);
  288. }
  289. high_resolution_clock::time_point t2 = high_resolution_clock::now();
  290. duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
  291. std::cout << " Grid 10mm took " << time_span.count() << " seconds." << std::endl;
  292. }
  293. }
  294. std::cout << "Test build and queries together - same number of contour points and query points" << std::endl <<
  295. "And with limited contour edge length to 4mm " << std::endl;
  296. for (auto count : point_counts) {
  297. std::vector<Points> lines { Points { } };
  298. std::vector<Linef> linesf { };
  299. Vec2d prevf { };
  300. Points query_points { };
  301. std::vector<Vec2d> query_pointsf { };
  302. for (int x = 0; x < count; ++x) {
  303. Vec2d cp { rand() / (double(RAND_MAX) + 1.0f) * 200.0 - 100.0, rand() / (double(RAND_MAX) + 1.0f) * 200.0
  304. - 100.0 };
  305. Vec2d contour = prevf + cp.normalized()*4.0; // limits the cnotour edge len to 4mm
  306. lines[0].push_back(Point::new_scale(contour));
  307. linesf.emplace_back(prevf, contour);
  308. prevf = linesf.back().b;
  309. Vec2d qp { rand() / (double(RAND_MAX) + 1.0f) * 200.0 - 100.0, rand() / (double(RAND_MAX) + 1.0f) * 200.0
  310. - 100.0 };
  311. query_pointsf.push_back(qp);
  312. query_points.push_back(Point::new_scale(qp));
  313. }
  314. std::cout << "Test for point count: " << count << std::endl;
  315. {
  316. high_resolution_clock::time_point t1 = high_resolution_clock::now();
  317. auto tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(linesf);
  318. for (const Vec2d &qp : query_pointsf) {
  319. size_t hit_idx_out;
  320. Vec2d hit_point_out;
  321. AABBTreeLines::squared_distance_to_indexed_lines(linesf, tree, qp, hit_idx_out, hit_point_out);
  322. }
  323. high_resolution_clock::time_point t2 = high_resolution_clock::now();
  324. duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
  325. std::cout << " Tree took " << time_span.count() << " seconds." << std::endl;
  326. }
  327. {
  328. high_resolution_clock::time_point t1 = high_resolution_clock::now();
  329. EdgeGrid::Grid grid1 { };
  330. grid1.create(lines, scaled(1.0), true);
  331. coord_t query1_res = scaled(1.0);
  332. grid1.calculate_sdf();
  333. for (const Point &qp : query_points) {
  334. volatile auto dist = grid1.closest_point_signed_distance(qp, query1_res);
  335. }
  336. high_resolution_clock::time_point t2 = high_resolution_clock::now();
  337. duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
  338. std::cout << " Grid 1mm took " << time_span.count() << " seconds." << std::endl;
  339. }
  340. {
  341. high_resolution_clock::time_point t1 = high_resolution_clock::now();
  342. EdgeGrid::Grid grid10 { };
  343. grid10.create(lines, scaled(10.0), true);
  344. coord_t query10_res = scaled(10.0);
  345. grid10.calculate_sdf();
  346. for (const Point &qp : query_points) {
  347. volatile auto dist = grid10.closest_point_signed_distance(qp, query10_res);
  348. }
  349. high_resolution_clock::time_point t2 = high_resolution_clock::now();
  350. duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
  351. std::cout << " Grid 10mm took " << time_span.count() << " seconds." << std::endl;
  352. }
  353. }
  354. }
  355. #endif