test_seam_aligned.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. #include <libslic3r/Point.hpp>
  2. #include <catch2/catch.hpp>
  3. #include <libslic3r/GCode/SeamAligned.hpp>
  4. #include "test_data.hpp"
  5. #include <fstream>
  6. using namespace Slic3r;
  7. using namespace Slic3r::Seams;
  8. constexpr bool debug_files{false};
  9. namespace AlignedTest {
  10. Perimeters::Perimeter get_perimeter() {
  11. const double slice_z{1.0};
  12. const std::size_t layer_index{};
  13. std::vector<Vec2d> positions{{0.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}, {0.0, 1.0}, {0.0, 0.5}};
  14. std::vector<double> angles(positions.size(), -M_PI / 2.0);
  15. angles[4] = 0.0;
  16. std::vector<Perimeters::PointType> point_types(positions.size(), Perimeters::PointType::common);
  17. std::vector<Perimeters::PointClassification>
  18. point_classifications{positions.size(), Perimeters::PointClassification::common};
  19. std::vector<Perimeters::AngleType> angle_type(positions.size(), Perimeters::AngleType::concave);
  20. angle_type[4] = Perimeters::AngleType::smooth;
  21. return {
  22. slice_z,
  23. layer_index,
  24. false,
  25. std::move(positions),
  26. std::move(angles),
  27. std::move(point_types),
  28. std::move(point_classifications),
  29. std::move(angle_type)};
  30. }
  31. } // namespace AlignedTest
  32. TEST_CASE("Snap to angle", "[Seams][SeamAligned]") {
  33. const Vec2d point{0.0, 0.4};
  34. const std::size_t search_start{4};
  35. const Perimeters::Perimeter perimeter{AlignedTest::get_perimeter()};
  36. std::optional<std::size_t> snapped_to{
  37. Aligned::Impl::snap_to_angle(point, search_start, perimeter, 0.5)};
  38. REQUIRE(snapped_to);
  39. CHECK(*snapped_to == 0);
  40. snapped_to = Aligned::Impl::snap_to_angle(point, search_start, perimeter, 0.3);
  41. REQUIRE(!snapped_to);
  42. }
  43. TEST_CASE("Get seam options", "[Seams][SeamAligned]") {
  44. Perimeters::Perimeter perimeter{AlignedTest::get_perimeter()};
  45. const Vec2d prefered_position{0.0, 0.3};
  46. Aligned::Impl::SeamOptions options{Aligned::Impl::get_seam_options(
  47. perimeter, prefered_position, *perimeter.common_points.common_points, 0.4
  48. )};
  49. CHECK(options.closest == 4);
  50. CHECK(options.adjacent == 0);
  51. CHECK((options.on_edge - Vec2d{0.0, 0.3}).norm() == Approx(0.0));
  52. REQUIRE(options.snapped);
  53. CHECK(options.snapped == 0);
  54. }
  55. struct PickSeamOptionFixture
  56. {
  57. Perimeters::Perimeter perimeter{AlignedTest::get_perimeter()};
  58. Aligned::Impl::SeamOptions options{
  59. 4, // closest
  60. 0, // adjacent
  61. true, // forward
  62. false, // snapped
  63. Vec2d{0.0, 0.3}, // on_edge
  64. };
  65. };
  66. TEST_CASE_METHOD(PickSeamOptionFixture, "Pick seam option", "[Seams][SeamAligned]") {
  67. auto [previous_index, next_index, position]{pick_seam_option(perimeter, options)};
  68. CHECK(previous_index == next_index);
  69. CHECK((position - Vec2d{0.0, 0.0}).norm() == Approx(0.0));
  70. }
  71. TEST_CASE_METHOD(PickSeamOptionFixture, "Pick seam option picks enforcer", "[Seams][SeamAligned]") {
  72. perimeter.point_types[4] = Perimeters::PointType::enforcer;
  73. auto [previous_index, next_index, position]{pick_seam_option(perimeter, options)};
  74. CHECK(previous_index == next_index);
  75. CHECK((position - Vec2d{0.0, 0.5}).norm() == Approx(0.0));
  76. }
  77. TEST_CASE_METHOD(PickSeamOptionFixture, "Nearest point", "[Seams][SeamAligned]") {
  78. const std::optional<SeamChoice> result{Aligned::Impl::Nearest{Vec2d{0.4, -0.1}, 0.2}(
  79. perimeter, Perimeters::PointType::common, Perimeters::PointClassification::common
  80. )};
  81. CHECK(result->previous_index == 0);
  82. CHECK(result->next_index == 1);
  83. CHECK((result->position - Vec2d{0.4, 0.0}).norm() == Approx(0.0));
  84. }
  85. TEST_CASE_METHOD(PickSeamOptionFixture, "Least visible point", "[Seams][SeamAligned]") {
  86. std::vector<double> precalculated_visibility{};
  87. for (std::size_t i{0}; i < perimeter.positions.size(); ++i) {
  88. precalculated_visibility.push_back(-static_cast<double>(i));
  89. }
  90. Aligned::Impl::LeastVisible least_visible{precalculated_visibility};
  91. const std::optional<SeamChoice> result{least_visible(
  92. perimeter, Perimeters::PointType::common, Perimeters::PointClassification::common
  93. )};
  94. CHECK(result->previous_index == 4);
  95. CHECK(result->next_index == 4);
  96. CHECK((result->position - Vec2d{0.0, 0.5}).norm() == Approx(0.0));
  97. }
  98. TEST_CASE_METHOD(Test::SeamsFixture, "Generate aligned seam", "[Seams][SeamAligned][Integration]") {
  99. Seams::Perimeters::LayerPerimeters perimeters{
  100. Seams::Perimeters::create_perimeters(projected, layer_infos, painting, params.perimeter)};
  101. Seams::Shells::Shells<> shells{
  102. Seams::Shells::create_shells(std::move(perimeters), params.max_distance)};
  103. const std::vector<std::vector<SeamPerimeterChoice>> seam{
  104. Aligned::get_object_seams(std::move(shells), visibility_calculator, params.aligned)};
  105. if constexpr (debug_files) {
  106. std::ofstream csv{"aligned_seam.csv"};
  107. Test::serialize_seam(csv, seam);
  108. }
  109. }
  110. TEST_CASE_METHOD(Test::SeamsFixture, "Calculate visibility", "[Seams][SeamAligned][Integration]") {
  111. if constexpr (debug_files) {
  112. std::ofstream csv{"visibility.csv"};
  113. csv << "x,y,z,visibility,total_visibility" << std::endl;
  114. Seams::Perimeters::LayerPerimeters perimeters{
  115. Seams::Perimeters::create_perimeters(projected, layer_infos, painting, params.perimeter)};
  116. Seams::Shells::Shells<> shells{
  117. Seams::Shells::create_shells(std::move(perimeters), params.max_distance)};
  118. for (const Shells::Shell<> &shell : shells) {
  119. for (const Shells::Slice<> &slice : shell) {
  120. for (std::size_t index{0}; index < slice.boundary.positions.size(); ++index) {
  121. const Vec2d &position{slice.boundary.positions[index]};
  122. const double point_visibility{visibility.calculate_point_visibility(
  123. to_3d(position.cast<float>(), slice.boundary.slice_z)
  124. )};
  125. const double total_visibility{
  126. visibility_calculator(SeamChoice{index, index, position}, slice.boundary)};
  127. // clang-format off
  128. csv <<
  129. position.x() << "," <<
  130. position.y() << "," <<
  131. slice.boundary.slice_z << "," <<
  132. point_visibility << "," <<
  133. total_visibility << std::endl;
  134. // clang-format on
  135. }
  136. }
  137. }
  138. }
  139. }