sla_supptgen_tests.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. #include <catch2/catch.hpp>
  2. #include <test_utils.hpp>
  3. #include <libslic3r/ExPolygon.hpp>
  4. #include <libslic3r/BoundingBox.hpp>
  5. #include "sla_test_utils.hpp"
  6. namespace Slic3r { namespace sla {
  7. TEST_CASE("Overhanging point should be supported", "[SupGen]") {
  8. // Pyramid with 45 deg slope
  9. TriangleMesh mesh = make_pyramid(10.f, 10.f);
  10. mesh.rotate_y(PI);
  11. mesh.require_shared_vertices();
  12. mesh.WriteOBJFile("Pyramid.obj");
  13. sla::SupportPoints pts = calc_support_pts(mesh);
  14. // The overhang, which is the upside-down pyramid's edge
  15. Vec3f overh{0., 0., -10.};
  16. REQUIRE(!pts.empty());
  17. float dist = (overh - pts.front().pos).norm();
  18. for (const auto &pt : pts)
  19. dist = std::min(dist, (overh - pt.pos).norm());
  20. // Should require exactly one support point at the overhang
  21. REQUIRE(pts.size() > 0);
  22. REQUIRE(dist < 1.f);
  23. }
  24. double min_point_distance(const sla::SupportPoints &pts)
  25. {
  26. sla::PointIndex index;
  27. for (size_t i = 0; i < pts.size(); ++i)
  28. index.insert(pts[i].pos.cast<double>(), i);
  29. auto d = std::numeric_limits<double>::max();
  30. index.foreach([&d, &index](const sla::PointIndexEl &el) {
  31. auto res = index.nearest(el.first, 2);
  32. for (const sla::PointIndexEl &r : res)
  33. if (r.second != el.second)
  34. d = std::min(d, (el.first - r.first).norm());
  35. });
  36. return d;
  37. }
  38. TEST_CASE("Overhanging horizontal surface should be supported", "[SupGen]") {
  39. double width = 10., depth = 10., height = 1.;
  40. TriangleMesh mesh = make_cube(width, depth, height);
  41. mesh.translate(0., 0., 5.); // lift up
  42. mesh.require_shared_vertices();
  43. mesh.WriteOBJFile("Cuboid.obj");
  44. sla::SupportPointGenerator::Config cfg;
  45. sla::SupportPoints pts = calc_support_pts(mesh, cfg);
  46. double mm2 = width * depth;
  47. REQUIRE(!pts.empty());
  48. REQUIRE(pts.size() * cfg.support_force() > mm2 * cfg.tear_pressure());
  49. REQUIRE(min_point_distance(pts) >= cfg.minimal_distance);
  50. }
  51. template<class M> auto&& center_around_bb(M &&mesh)
  52. {
  53. auto bb = mesh.bounding_box();
  54. mesh.translate(-bb.center().template cast<float>());
  55. return std::forward<M>(mesh);
  56. }
  57. TEST_CASE("Overhanging edge should be supported", "[SupGen]") {
  58. float width = 10.f, depth = 10.f, height = 5.f;
  59. TriangleMesh mesh = make_prism(width, depth, height);
  60. mesh.rotate_y(PI); // rotate on its back
  61. mesh.translate(0., 0., height);
  62. mesh.require_shared_vertices();
  63. mesh.WriteOBJFile("Prism.obj");
  64. sla::SupportPointGenerator::Config cfg;
  65. sla::SupportPoints pts = calc_support_pts(mesh, cfg);
  66. Linef3 overh{ {0.f, -depth / 2.f, 0.f}, {0.f, depth / 2.f, 0.f}};
  67. // Get all the points closer that 1 mm to the overhanging edge:
  68. sla::SupportPoints overh_pts; overh_pts.reserve(pts.size());
  69. std::copy_if(pts.begin(), pts.end(), std::back_inserter(overh_pts),
  70. [&overh](const sla::SupportPoint &pt){
  71. return line_alg::distance_to(overh, Vec3d{pt.pos.cast<double>()}) < 1.;
  72. });
  73. REQUIRE(overh_pts.size() * cfg.support_force() > overh.length() * cfg.tear_pressure());
  74. double ddiff = min_point_distance(pts) - cfg.minimal_distance;
  75. REQUIRE(ddiff > - 0.1 * cfg.minimal_distance);
  76. }
  77. TEST_CASE("Hollowed cube should be supported from the inside", "[SupGen][Hollowed]") {
  78. TriangleMesh mesh = make_cube(20., 20., 20.);
  79. hollow_mesh(mesh, HollowingConfig{});
  80. mesh.WriteOBJFile("cube_hollowed.obj");
  81. auto bb = mesh.bounding_box();
  82. auto h = float(bb.max.z() - bb.min.z());
  83. Vec3f mv = bb.center().cast<float>() - Vec3f{0.f, 0.f, 0.5f * h};
  84. mesh.translate(-mv);
  85. mesh.require_shared_vertices();
  86. sla::SupportPointGenerator::Config cfg;
  87. sla::SupportPoints pts = calc_support_pts(mesh, cfg);
  88. sla::remove_bottom_points(pts, mesh.bounding_box().min.z() + EPSILON);
  89. REQUIRE(!pts.empty());
  90. }
  91. TEST_CASE("Two parallel plates should be supported", "[SupGen][Hollowed]")
  92. {
  93. double width = 20., depth = 20., height = 1.;
  94. TriangleMesh mesh = center_around_bb(make_cube(width + 5., depth + 5., height));
  95. TriangleMesh mesh_high = center_around_bb(make_cube(width, depth, height));
  96. mesh_high.translate(0., 0., 10.); // lift up
  97. mesh.merge(mesh_high);
  98. mesh.require_shared_vertices();
  99. mesh.WriteOBJFile("parallel_plates.obj");
  100. sla::SupportPointGenerator::Config cfg;
  101. sla::SupportPoints pts = calc_support_pts(mesh, cfg);
  102. sla::remove_bottom_points(pts, mesh.bounding_box().min.z() + EPSILON);
  103. REQUIRE(!pts.empty());
  104. }
  105. }} // namespace Slic3r::sla