test_seam_random.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. #include <libslic3r/Point.hpp>
  2. #include <catch2/catch.hpp>
  3. #include <libslic3r/GCode/SeamRandom.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 RandomTest {
  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}, {0.5, 0.0}, {1.0, 0.0}};
  14. std::vector<double> angles(positions.size(), -M_PI / 2.0);
  15. std::vector<Perimeters::PointType> point_types(positions.size(), Perimeters::PointType::common);
  16. std::vector<Perimeters::PointClassification>
  17. point_classifications{positions.size(), Perimeters::PointClassification::common};
  18. std::vector<Perimeters::AngleType> angle_type(positions.size(), Perimeters::AngleType::concave);
  19. return {
  20. slice_z,
  21. layer_index,
  22. false,
  23. std::move(positions),
  24. std::move(angles),
  25. std::move(point_types),
  26. std::move(point_classifications),
  27. std::move(angle_type)};
  28. }
  29. } // namespace RandomTest
  30. double get_chi2_uniform(const std::vector<double> &data, double min, double max, const std::size_t bin_count) {
  31. std::vector<std::size_t> bins(bin_count);
  32. const double bin_size{(max - min) / bin_count};
  33. const double expected_frequncy{static_cast<double>(data.size()) / bin_count};
  34. for (const double value : data) {
  35. auto bin{static_cast<int>(std::floor((value - min) / bin_size))};
  36. bins[bin]++;
  37. }
  38. return std::accumulate(bins.begin(), bins.end(), 0.0, [&](const double total, const std::size_t count_in_bin){
  39. return total + std::pow(static_cast<double>(count_in_bin - expected_frequncy), 2.0) / expected_frequncy;
  40. });
  41. }
  42. TEST_CASE("Random is uniform", "[Seams][SeamRandom]") {
  43. const int seed{42};
  44. std::mt19937 random_engine{seed};
  45. const Random::Impl::Random random{random_engine};
  46. Perimeters::Perimeter perimeter{RandomTest::get_perimeter()};
  47. std::vector<double> x_positions;
  48. const std::size_t count{1001};
  49. x_positions.reserve(count);
  50. std::generate_n(std::back_inserter(x_positions), count, [&]() {
  51. std::optional<SeamChoice> choice{
  52. random(perimeter, Perimeters::PointType::common, Perimeters::PointClassification::common)};
  53. return choice->position.x();
  54. });
  55. const std::size_t degrees_of_freedom{10};
  56. const double critical{18.307}; // dof 10, significance 0.05
  57. CHECK(get_chi2_uniform(x_positions, 0.0, 1.0, degrees_of_freedom + 1) < critical);
  58. }
  59. TEST_CASE("Random respects point type", "[Seams][SeamRandom]") {
  60. const int seed{42};
  61. std::mt19937 random_engine{seed};
  62. const Random::Impl::Random random{random_engine};
  63. Perimeters::Perimeter perimeter{RandomTest::get_perimeter()};
  64. std::optional<SeamChoice> choice{
  65. random(perimeter, Perimeters::PointType::common, Perimeters::PointClassification::common)};
  66. REQUIRE(choice);
  67. const std::size_t picked_index{choice->previous_index};
  68. perimeter.point_types[picked_index] = Perimeters::PointType::blocker;
  69. choice = random(perimeter, Perimeters::PointType::common, Perimeters::PointClassification::common);
  70. REQUIRE(choice);
  71. CHECK(choice->previous_index != picked_index);
  72. }
  73. TEST_CASE_METHOD(Test::SeamsFixture, "Generate random seam", "[Seams][SeamRandom][Integration]") {
  74. Seams::Perimeters::LayerPerimeters perimeters{
  75. Seams::Perimeters::create_perimeters(projected, layer_infos, painting, params.perimeter)};
  76. const std::vector<std::vector<SeamPerimeterChoice>> seams{
  77. Random::get_object_seams(std::move(perimeters), params.random_seed)};
  78. if constexpr (debug_files) {
  79. std::ofstream csv{"random_seam.csv"};
  80. Test::serialize_seam(csv, seams);
  81. }
  82. }