test_seam_geometry.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. #include <libslic3r/Point.hpp>
  2. #include <catch2/catch.hpp>
  3. #include <libslic3r/GCode/SeamGeometry.hpp>
  4. #include <libslic3r/Geometry.hpp>
  5. using namespace Slic3r;
  6. TEST_CASE("Lists mapping", "[Seams][SeamGeometry]") {
  7. // clang-format off
  8. std::vector<std::vector<int>> list_of_lists{
  9. {},
  10. {7, 2, 3},
  11. {9, 6, 3, 6, 7},
  12. {1, 1, 3},
  13. {1},
  14. {3},
  15. {1},
  16. {},
  17. {3}
  18. };
  19. // clang-format on
  20. std::vector<std::size_t> sizes;
  21. sizes.reserve(list_of_lists.size());
  22. for (const std::vector<int> &list : list_of_lists) {
  23. sizes.push_back(list.size());
  24. }
  25. const auto [mapping, bucket_cout]{Seams::Geometry::get_mapping(
  26. sizes,
  27. [&](const std::size_t layer_index,
  28. const std::size_t item_index) -> Seams::Geometry::MappingOperatorResult {
  29. unsigned max_diff{0};
  30. std::optional<std::size_t> index;
  31. const std::vector<int> &layer{list_of_lists[layer_index]};
  32. const std::vector<int> &next_layer{list_of_lists[layer_index + 1]};
  33. for (std::size_t i{0}; i < next_layer.size(); ++i) {
  34. const long diff{std::abs(next_layer[i] - layer[item_index])};
  35. if (diff > max_diff) {
  36. max_diff = diff;
  37. index = i;
  38. }
  39. }
  40. if (!index) {
  41. return std::nullopt;
  42. }
  43. return std::pair{*index, static_cast<double>(max_diff)};
  44. }
  45. )};
  46. // clang-format off
  47. CHECK(mapping == std::vector<std::vector<std::size_t>>{
  48. {},
  49. {0, 1, 2},
  50. {1, 3, 0, 4, 5},
  51. {1, 6, 7},
  52. {7},
  53. {7},
  54. {7},
  55. {},
  56. {8}
  57. });
  58. // clang-format on
  59. }
  60. TEST_CASE("Vertex angle calculation counterclockwise", "[Seams][SeamGeometry]") {
  61. std::vector<Vec2d> points{Vec2d{0, 0}, Vec2d{1, 0}, Vec2d{1, 1}, Vec2d{0, 1}};
  62. std::vector<double> angles{Seams::Geometry::get_vertex_angles(points, 0.1)};
  63. CHECK(angles.size() == 4);
  64. for (const double angle : angles) {
  65. CHECK(angle == Approx(-M_PI / 2));
  66. }
  67. }
  68. TEST_CASE("Vertex angle calculation clockwise", "[Seams][SeamGeometry]") {
  69. std::vector<Vec2d> points = {Vec2d{0, 0}, Vec2d{0, 1}, Vec2d{1, 1}, Vec2d{1, 0}};
  70. std::vector<double> angles = Seams::Geometry::get_vertex_angles(points, 0.1);
  71. CHECK(angles.size() == 4);
  72. for (const double angle : angles) {
  73. CHECK(angle == Approx(M_PI / 2));
  74. }
  75. }
  76. TEST_CASE("Vertex angle calculation small convex", "[Seams][SeamGeometry]") {
  77. std::vector<Vec2d> points = {Vec2d{0, 0}, Vec2d{-0.01, 1}, Vec2d{0, 2}, Vec2d{-2, 1}};
  78. std::vector<double> angles = Seams::Geometry::get_vertex_angles(points, 0.1);
  79. CHECK(angles.size() == 4);
  80. CHECK(angles[1] > 0);
  81. CHECK(angles[1] < 0.02);
  82. }
  83. TEST_CASE("Vertex angle calculation small concave", "[Seams][SeamGeometry]") {
  84. std::vector<Vec2d> points = {Vec2d{0, 0}, Vec2d{0.01, 1}, Vec2d{0, 2}, Vec2d{-2, 1}};
  85. std::vector<double> angles = Seams::Geometry::get_vertex_angles(points, 0.1);
  86. CHECK(angles.size() == 4);
  87. CHECK(angles[1] < 0);
  88. CHECK(angles[1] > -0.02);
  89. }
  90. TEST_CASE("Vertex angle is rotation agnostic", "[Seams][SeamGeometry]") {
  91. std::vector<Vec2d> points = {Vec2d{0, 0}, Vec2d{0.01, 1}, Vec2d{0, 2}, Vec2d{-2, 1}};
  92. std::vector<double> angles = Seams::Geometry::get_vertex_angles(points, 0.1);
  93. Points polygon_points;
  94. using std::transform, std::back_inserter;
  95. transform(points.begin(), points.end(), back_inserter(polygon_points), [](const Vec2d &point) {
  96. return scaled(point);
  97. });
  98. Polygon polygon{polygon_points};
  99. polygon.rotate(M_PI - Slic3r::Geometry::deg2rad(10.0));
  100. std::vector<Vec2d> rotated_points;
  101. using std::transform, std::back_inserter;
  102. transform(
  103. polygon.points.begin(), polygon.points.end(), back_inserter(rotated_points),
  104. [](const Point &point) { return unscaled(point); }
  105. );
  106. std::vector<double> rotated_angles = Seams::Geometry::get_vertex_angles(points, 0.1);
  107. CHECK(rotated_angles[1] == Approx(angles[1]));
  108. }
  109. TEST_CASE("Calculate overhangs", "[Seams][SeamGeometry]") {
  110. const ExPolygon square{
  111. scaled(Vec2d{0.0, 0.0}),
  112. scaled(Vec2d{1.0, 0.0}),
  113. scaled(Vec2d{1.0, 1.0}),
  114. scaled(Vec2d{0.0, 1.0})
  115. };
  116. const std::vector<Vec2d> points{Seams::Geometry::unscaled(square.contour.points)};
  117. ExPolygon previous_layer{square};
  118. previous_layer.translate(scaled(Vec2d{-0.5, 0}));
  119. AABBTreeLines::LinesDistancer<Linef> previous_layer_distancer{
  120. to_unscaled_linesf({previous_layer})};
  121. const std::vector<double> overhangs{
  122. Seams::Geometry::get_overhangs(points, previous_layer_distancer, 0.5)};
  123. REQUIRE(overhangs.size() == points.size());
  124. CHECK_THAT(overhangs, Catch::Matchers::Approx(std::vector<double>{
  125. 0.0, M_PI / 4.0, M_PI / 4.0, 0.0
  126. }));
  127. }