test_support_spots_generator.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. #include "libslic3r/Point.hpp"
  2. #include <catch2/catch.hpp>
  3. #include <libslic3r/SupportSpotsGenerator.hpp>
  4. using namespace Slic3r;
  5. using namespace SupportSpotsGenerator;
  6. TEST_CASE("Numerical integral calculation compared with exact solution.", "[SupportSpotsGenerator]") {
  7. const float width = 10;
  8. const float height = 20;
  9. const Polygon polygon = {
  10. scaled(Vec2f{-width / 2, -height / 2}),
  11. scaled(Vec2f{width / 2, -height / 2}),
  12. scaled(Vec2f{width / 2, height / 2}),
  13. scaled(Vec2f{-width / 2, height / 2})
  14. };
  15. const Integrals integrals{{polygon}};
  16. CHECK(integrals.area == Approx(width * height));
  17. CHECK(integrals.x_i.x() == Approx(0));
  18. CHECK(integrals.x_i.y() == Approx(0));
  19. CHECK(integrals.x_i_squared.x() == Approx(std::pow(width, 3) * height / 12));
  20. CHECK(integrals.x_i_squared.y() == Approx(width * std::pow(height, 3) / 12));
  21. }
  22. TEST_CASE("Moment values and ratio check.", "[SupportSpotsGenerator]") {
  23. const float width = 40;
  24. const float height = 2;
  25. // Moments are calculated at centroid.
  26. // Polygon centroid must not be (0, 0).
  27. const Polygon polygon = {
  28. scaled(Vec2f{0, 0}),
  29. scaled(Vec2f{width, 0}),
  30. scaled(Vec2f{width, height}),
  31. scaled(Vec2f{0, height})
  32. };
  33. const Integrals integrals{{polygon}};
  34. const Vec2f x_axis{1, 0};
  35. const float x_axis_moment = compute_second_moment(integrals, x_axis);
  36. const Vec2f y_axis{0, 1};
  37. const float y_axis_moment = compute_second_moment(integrals, y_axis);
  38. const float moment_ratio = std::pow(width / height, 2);
  39. // Ensure the object transaltion has no effect.
  40. CHECK(x_axis_moment == Approx(width * std::pow(height, 3) / 12));
  41. CHECK(y_axis_moment == Approx(std::pow(width, 3) * height / 12));
  42. // If the object is "wide" the y axis moments should be large compared to x axis moment.
  43. CHECK(y_axis_moment / x_axis_moment == Approx(moment_ratio));
  44. }
  45. TEST_CASE("Moments calculation for rotated axis.", "[SupportSpotsGenerator]") {
  46. Polygon polygon = {
  47. scaled(Vec2f{6.362284076172198, 138.9674202217155}),
  48. scaled(Vec2f{97.48779843751677, 106.08136606617076}),
  49. scaled(Vec2f{135.75221821532384, 66.84428834668765}),
  50. scaled(Vec2f{191.5308049852741, 45.77905628725614}),
  51. scaled(Vec2f{182.7525148049201, 74.01799041087513}),
  52. scaled(Vec2f{296.83210979283473, 196.80022572637228}),
  53. scaled(Vec2f{215.16434429179148, 187.45715418834143}),
  54. scaled(Vec2f{64.64574271229334, 284.293883209721}),
  55. scaled(Vec2f{110.76507036894843, 174.35633141113783}),
  56. scaled(Vec2f{77.56229640885199, 189.33057746591336})
  57. };
  58. Integrals integrals{{polygon}};
  59. // Meassured counterclockwise from (1, 0)
  60. const float angle = 1.432f;
  61. Vec2f axis{std::cos(angle), std::sin(angle)};
  62. float moment_calculated_then_rotated = compute_second_moment(
  63. integrals,
  64. axis
  65. );
  66. // We want to rotate the object clockwise by angle to align the axis with (1, 0)
  67. // Method .rotate is counterclockwise for positive angle
  68. polygon.rotate(-angle);
  69. Integrals integrals_rotated{{polygon}};
  70. float moment_rotated_polygon = compute_second_moment(
  71. integrals_rotated,
  72. Vec2f{1, 0}
  73. );
  74. // Up to 0.1% accuracy
  75. CHECK_THAT(moment_calculated_then_rotated, Catch::Matchers::WithinRel(moment_rotated_polygon, 0.001f));
  76. }
  77. struct ObjectPartFixture {
  78. const Polyline polyline{
  79. Point{scaled(Vec2f{0, 0})},
  80. Point{scaled(Vec2f{1, 0})},
  81. };
  82. const float width = 0.1f;
  83. bool connected_to_bed = true;
  84. coordf_t print_head_z = 0.2;
  85. coordf_t layer_height = 0.2;
  86. ExtrusionAttributes attributes;
  87. ExtrusionEntityCollection collection;
  88. std::vector<const ExtrusionEntityCollection*> extrusions{};
  89. Polygon expected_polygon{
  90. Point{scaled(Vec2f{0, -width / 2})},
  91. Point{scaled(Vec2f{1, -width / 2})},
  92. Point{scaled(Vec2f{1, width / 2})},
  93. Point{scaled(Vec2f{0, width / 2})}
  94. };
  95. ObjectPartFixture() {
  96. attributes.width = width;
  97. const ExtrusionPath path{polyline, attributes};
  98. collection.append(path);
  99. extrusions.push_back(&collection);
  100. }
  101. };
  102. TEST_CASE_METHOD(ObjectPartFixture, "Constructing ObjectPart using extrusion collections", "[SupportSpotsGenerator]") {
  103. ObjectPart part{
  104. extrusions,
  105. connected_to_bed,
  106. print_head_z,
  107. layer_height,
  108. std::nullopt
  109. };
  110. Integrals expected{{expected_polygon}};
  111. CHECK(part.connected_to_bed == true);
  112. Vec3f volume_centroid{part.volume_centroid_accumulator / part.volume};
  113. CHECK(volume_centroid.x() == Approx(0.5));
  114. CHECK(volume_centroid.y() == Approx(0));
  115. CHECK(volume_centroid.z() == Approx(layer_height / 2));
  116. CHECK(part.sticking_area == Approx(expected.area));
  117. CHECK(part.sticking_centroid_accumulator.x() == Approx(expected.x_i.x()));
  118. CHECK(part.sticking_centroid_accumulator.y() == Approx(expected.x_i.y()));
  119. CHECK(part.sticking_second_moment_of_area_accumulator.x() == Approx(expected.x_i_squared.x()));
  120. CHECK(part.sticking_second_moment_of_area_accumulator.y() == Approx(expected.x_i_squared.y()));
  121. CHECK(part.sticking_second_moment_of_area_covariance_accumulator == Approx(expected.xy).margin(1e-6));
  122. CHECK(part.volume == Approx(layer_height * width));
  123. }
  124. TEST_CASE_METHOD(ObjectPartFixture, "Constructing ObjectPart with brim", "[SupportSpotsGenerator]") {
  125. float brim_width = 1;
  126. Polygons brim = get_brim(ExPolygon{expected_polygon}, BrimType::btOuterOnly, brim_width);
  127. ObjectPart part{
  128. extrusions,
  129. connected_to_bed,
  130. print_head_z,
  131. layer_height,
  132. brim
  133. };
  134. CHECK(part.sticking_area == Approx((1 + 2*brim_width) * (width + 2*brim_width)));
  135. }