test_cut_surface.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. #include <catch2/catch.hpp>
  2. #include <libslic3r/CutSurface.hpp>
  3. #include <libslic3r/TriangleMesh.hpp> // its_make_cube + its_merge
  4. using namespace Slic3r;
  5. TEST_CASE("Cut character from surface", "[]")
  6. {
  7. std::string font_path = std::string(TEST_DATA_DIR) +
  8. "/../../resources/fonts/NotoSans-Regular.ttf";
  9. char letter = '%';
  10. float flatness = 2.;
  11. unsigned int font_index = 0; // collection
  12. double z_depth = 50.f; // projection size
  13. auto font = Emboss::create_font_file(font_path.c_str());
  14. REQUIRE(font != nullptr);
  15. std::optional<Emboss::Glyph> glyph =
  16. Emboss::letter2glyph(*font, font_index, letter, flatness);
  17. REQUIRE(glyph.has_value());
  18. ExPolygons shapes = glyph->shape;
  19. REQUIRE(!shapes.empty());
  20. Transform3d tr = Transform3d::Identity();
  21. tr.translate(Vec3d(0., 0., -z_depth));
  22. double text_shape_scale = 0.001; // Emboss.cpp --> SHAPE_SCALE
  23. tr.scale(text_shape_scale);
  24. Emboss::OrthoProject cut_projection(tr, Vec3d(0., 0., z_depth));
  25. auto object = its_make_cube(782 - 49 + 50, 724 + 10 + 50, 5);
  26. its_translate(object, Vec3f(49 - 25, -10 - 25, -40));
  27. auto cube2 = object; // copy
  28. its_translate(cube2, Vec3f(100, -40, 7.5));
  29. its_merge(object, std::move(cube2));
  30. std::vector<indexed_triangle_set> objects{object};
  31. // Call core function for cut surface
  32. auto surfaces = cut_surface(shapes, objects, cut_projection, 0.5);
  33. CHECK(!surfaces.empty());
  34. Emboss::OrthoProject projection(Transform3d::Identity(),
  35. Vec3d(0.f, 0.f, 10.f));
  36. its_translate(surfaces, Vec3f(0.f, 0.f, 10));
  37. indexed_triangle_set its = cut2model(surfaces, projection);
  38. CHECK(!its.empty());
  39. // its_write_obj(its, "C:/data/temp/projected.obj");
  40. }
  41. //#define DEBUG_3MF
  42. #ifdef DEBUG_3MF
  43. // Test load of 3mf
  44. #include "libslic3r/Format/3mf.hpp"
  45. #include "libslic3r/Model.hpp"
  46. static std::vector<indexed_triangle_set> transform_volumes(ModelVolume *mv) {
  47. const auto &volumes = mv->get_object()->volumes;
  48. std::vector<indexed_triangle_set> results;
  49. results.reserve(volumes.size());
  50. // Improve create object from part or use gl_volume
  51. // Get first model part in object
  52. for (const ModelVolume *v : volumes) {
  53. if (v->id() == mv->id()) continue;
  54. if (!v->is_model_part()) continue;
  55. const TriangleMesh &tm = v->mesh();
  56. if (tm.empty()) continue;
  57. if (tm.its.empty()) continue;
  58. results.push_back(tm.its); // copy: indexed_triangle_set
  59. indexed_triangle_set& its = results.back();
  60. its_transform(its,v->get_matrix());
  61. }
  62. return results;
  63. }
  64. static Emboss::OrthoProject create_projection_for_cut(
  65. Transform3d tr,
  66. double shape_scale,
  67. const BoundingBox &shape_bb,
  68. const std::pair<float, float> &z_range)
  69. {
  70. // create sure that emboss object is bigger than source object
  71. const float safe_extension = 1.0f;
  72. double min_z = z_range.first - safe_extension;
  73. double max_z = z_range.second + safe_extension;
  74. assert(min_z < max_z);
  75. // range between min and max value
  76. double projection_size = max_z - min_z;
  77. Matrix3d transformation_for_vector = tr.linear();
  78. // Projection must be negative value.
  79. // System of text coordinate
  80. // X .. from left to right
  81. // Y .. from bottom to top
  82. // Z .. from text to eye
  83. Vec3d untransformed_direction(0., 0., projection_size);
  84. Vec3d project_direction = transformation_for_vector * untransformed_direction;
  85. // Projection is in direction from far plane
  86. tr.translate(Vec3d(0., 0., min_z));
  87. tr.scale(shape_scale);
  88. // Text alignemnt to center 2D
  89. Vec2d move = -(shape_bb.max + shape_bb.min).cast<double>() / 2.;
  90. // Vec2d move = -shape_bb.center().cast<double>(); // not precisse
  91. tr.translate(Vec3d(move.x(), move.y(), 0.));
  92. return Emboss::OrthoProject(tr, project_direction);
  93. }
  94. TEST_CASE("CutSurface in 3mf", "[Emboss]")
  95. {
  96. //std::string path_to_3mf = "C:/Users/Filip Sykala/Downloads/EmbossFromMultiVolumes.3mf";
  97. //int object_id = 0;
  98. //int text_volume_id = 2;
  99. //std::string path_to_3mf = "C:/Users/Filip Sykala/Downloads/treefrog.3mf";
  100. //int object_id = 0;
  101. //int text_volume_id = 1;
  102. std::string path_to_3mf = "C:/Users/Filip Sykala/Downloads/cube_test.3mf";
  103. int object_id = 1;
  104. int text_volume_id = 2;
  105. Model model;
  106. DynamicPrintConfig config;
  107. ConfigSubstitutionContext ctxt{ForwardCompatibilitySubstitutionRule::Disable};
  108. CHECK(load_3mf(path_to_3mf.c_str(), config, ctxt, &model, false));
  109. CHECK(object_id >= 0);
  110. CHECK((size_t)object_id < model.objects.size());
  111. ModelObject* mo = model.objects[object_id];
  112. CHECK(mo != nullptr);
  113. CHECK(text_volume_id >= 0);
  114. CHECK((size_t)text_volume_id < mo->volumes.size());
  115. ModelVolume *mv_text = mo->volumes[text_volume_id];
  116. CHECK(mv_text != nullptr);
  117. CHECK(mv_text->text_configuration.has_value());
  118. TextConfiguration &tc = *mv_text->text_configuration;
  119. /* // Need GUI to load font by wx
  120. std::optional<wxFont> wx_font = GUI::WxFontUtils::load_wxFont(tc.style.path);
  121. CHECK(wx_font.has_value());
  122. Emboss::FontFileWithCache ff(GUI::WxFontUtils::create_font_file(*wx_font));
  123. CHECK(ff.font_file != nullptr);
  124. /*/ // end use GUI
  125. // start use fake font
  126. std::string font_path = std::string(TEST_DATA_DIR) +
  127. "/../../resources/fonts/NotoSans-Regular.ttf";
  128. Emboss::FontFileWithCache ff(Emboss::create_font_file(font_path.c_str()));
  129. // */ // end use fake font
  130. CHECK(ff.has_value());
  131. std::vector<indexed_triangle_set> its = transform_volumes(mv_text);
  132. BoundingBoxf3 bb;
  133. for (auto &i : its) bb.merge(Slic3r::bounding_box(i));
  134. Transform3d cut_projection_tr = mv_text->get_matrix() * tc.fix_3mf_tr->inverse();
  135. Transform3d emboss_tr = cut_projection_tr.inverse();
  136. BoundingBoxf3 mesh_bb_tr = bb.transformed(emboss_tr);
  137. std::pair<float, float> z_range{mesh_bb_tr.min.z(), mesh_bb_tr.max.z()};
  138. FontProp fp = tc.style.prop;
  139. ExPolygons shapes = Emboss::text2shapes(ff, tc.text.c_str(), fp);
  140. double shape_scale = Emboss::get_text_shape_scale(fp, *ff.font_file);
  141. Emboss::OrthoProject projection = create_projection_for_cut(
  142. cut_projection_tr, shape_scale, get_extents(shapes), z_range);
  143. float projection_ratio = -z_range.first / (z_range.second - z_range.first);
  144. SurfaceCut cut = cut_surface(shapes, its, projection, projection_ratio);
  145. its_write_obj(cut, "C:/data/temp/cutSurface/result_cut.obj");
  146. }
  147. #endif // DEBUG_3MF