2022-06-09 13:07:44 +00:00
|
|
|
#include <catch2/catch.hpp>
|
|
|
|
|
|
|
|
#include <libslic3r/CutSurface.hpp>
|
|
|
|
#include <libslic3r/TriangleMesh.hpp> // its_make_cube + its_merge
|
|
|
|
|
|
|
|
using namespace Slic3r;
|
|
|
|
TEST_CASE("Cut character from surface", "[]")
|
|
|
|
{
|
|
|
|
std::string font_path = std::string(TEST_DATA_DIR) +
|
|
|
|
"/../../resources/fonts/NotoSans-Regular.ttf";
|
|
|
|
char letter = '%';
|
|
|
|
float flatness = 2.;
|
|
|
|
unsigned int font_index = 0; // collection
|
2022-10-12 14:17:38 +00:00
|
|
|
double z_depth = 50.f; // projection size
|
2022-06-09 13:07:44 +00:00
|
|
|
|
|
|
|
auto font = Emboss::create_font_file(font_path.c_str());
|
|
|
|
REQUIRE(font != nullptr);
|
|
|
|
std::optional<Emboss::Glyph> glyph =
|
|
|
|
Emboss::letter2glyph(*font, font_index, letter, flatness);
|
|
|
|
REQUIRE(glyph.has_value());
|
2022-07-13 06:26:59 +00:00
|
|
|
ExPolygons shapes = glyph->shape;
|
|
|
|
REQUIRE(!shapes.empty());
|
2022-06-09 13:07:44 +00:00
|
|
|
|
|
|
|
Transform3d tr = Transform3d::Identity();
|
|
|
|
tr.translate(Vec3d(0., 0., -z_depth));
|
|
|
|
tr.scale(Emboss::SHAPE_SCALE);
|
2022-10-12 14:17:38 +00:00
|
|
|
Emboss::OrthoProject cut_projection(tr, Vec3d(0., 0., z_depth));
|
2022-06-09 13:07:44 +00:00
|
|
|
|
|
|
|
auto object = its_make_cube(782 - 49 + 50, 724 + 10 + 50, 5);
|
|
|
|
its_translate(object, Vec3f(49 - 25, -10 - 25, -40));
|
|
|
|
auto cube2 = object; // copy
|
|
|
|
its_translate(cube2, Vec3f(100, -40, 7.5));
|
|
|
|
its_merge(object, std::move(cube2));
|
|
|
|
|
2022-07-13 06:26:59 +00:00
|
|
|
std::vector<indexed_triangle_set> objects{object};
|
2022-06-09 13:07:44 +00:00
|
|
|
// Call core function for cut surface
|
2022-07-13 06:26:59 +00:00
|
|
|
auto surfaces = cut_surface(shapes, objects, cut_projection, 0.5);
|
2022-06-09 13:07:44 +00:00
|
|
|
CHECK(!surfaces.empty());
|
|
|
|
|
|
|
|
Emboss::OrthoProject projection(Transform3d::Identity(),
|
2022-10-12 14:17:38 +00:00
|
|
|
Vec3d(0.f, 0.f, 10.f));
|
2022-06-09 13:07:44 +00:00
|
|
|
its_translate(surfaces, Vec3f(0.f, 0.f, 10));
|
|
|
|
|
|
|
|
indexed_triangle_set its = cut2model(surfaces, projection);
|
|
|
|
CHECK(!its.empty());
|
|
|
|
// its_write_obj(its, "C:/data/temp/projected.obj");
|
|
|
|
}
|
|
|
|
|
2022-07-12 10:18:34 +00:00
|
|
|
//#define DEBUG_3MF
|
2022-06-21 14:14:40 +00:00
|
|
|
#ifdef DEBUG_3MF
|
|
|
|
|
2022-06-09 13:07:44 +00:00
|
|
|
// Test load of 3mf
|
|
|
|
#include "libslic3r/Format/3mf.hpp"
|
|
|
|
#include "libslic3r/Model.hpp"
|
|
|
|
|
2022-06-29 09:55:55 +00:00
|
|
|
static std::vector<indexed_triangle_set> transform_volumes(ModelVolume *mv) {
|
2022-06-09 13:07:44 +00:00
|
|
|
const auto &volumes = mv->get_object()->volumes;
|
2022-06-29 09:55:55 +00:00
|
|
|
std::vector<indexed_triangle_set> results;
|
|
|
|
results.reserve(volumes.size());
|
2022-06-09 13:07:44 +00:00
|
|
|
|
|
|
|
// Improve create object from part or use gl_volume
|
|
|
|
// Get first model part in object
|
|
|
|
for (const ModelVolume *v : volumes) {
|
|
|
|
if (v->id() == mv->id()) continue;
|
|
|
|
if (!v->is_model_part()) continue;
|
|
|
|
const TriangleMesh &tm = v->mesh();
|
|
|
|
if (tm.empty()) continue;
|
|
|
|
if (tm.its.empty()) continue;
|
2022-06-29 09:55:55 +00:00
|
|
|
results.push_back(tm.its); // copy: indexed_triangle_set
|
|
|
|
indexed_triangle_set& its = results.back();
|
2022-06-09 13:07:44 +00:00
|
|
|
its_transform(its,v->get_matrix());
|
|
|
|
}
|
2022-06-29 09:55:55 +00:00
|
|
|
return results;
|
2022-06-09 13:07:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static Emboss::OrthoProject create_projection_for_cut(
|
|
|
|
Transform3d tr,
|
|
|
|
double shape_scale,
|
|
|
|
const BoundingBox &shape_bb,
|
|
|
|
const std::pair<float, float> &z_range)
|
|
|
|
{
|
|
|
|
// create sure that emboss object is bigger than source object
|
|
|
|
const float safe_extension = 1.0f;
|
2022-10-12 14:17:38 +00:00
|
|
|
double min_z = z_range.first - safe_extension;
|
|
|
|
double max_z = z_range.second + safe_extension;
|
2022-06-09 13:07:44 +00:00
|
|
|
assert(min_z < max_z);
|
|
|
|
// range between min and max value
|
|
|
|
double projection_size = max_z - min_z;
|
|
|
|
Matrix3d transformation_for_vector = tr.linear();
|
|
|
|
// Projection must be negative value.
|
|
|
|
// System of text coordinate
|
|
|
|
// X .. from left to right
|
|
|
|
// Y .. from bottom to top
|
|
|
|
// Z .. from text to eye
|
|
|
|
Vec3d untransformed_direction(0., 0., projection_size);
|
2022-10-12 14:17:38 +00:00
|
|
|
Vec3d project_direction = transformation_for_vector * untransformed_direction;
|
2022-06-09 13:07:44 +00:00
|
|
|
|
|
|
|
// Projection is in direction from far plane
|
|
|
|
tr.translate(Vec3d(0., 0., min_z));
|
|
|
|
|
|
|
|
tr.scale(shape_scale);
|
|
|
|
// Text alignemnt to center 2D
|
|
|
|
Vec2d move = -(shape_bb.max + shape_bb.min).cast<double>() / 2.;
|
|
|
|
// Vec2d move = -shape_bb.center().cast<double>(); // not precisse
|
|
|
|
tr.translate(Vec3d(move.x(), move.y(), 0.));
|
|
|
|
return Emboss::OrthoProject(tr, project_direction);
|
|
|
|
}
|
|
|
|
|
2022-06-24 13:55:11 +00:00
|
|
|
TEST_CASE("CutSurface in 3mf", "[Emboss]")
|
2022-06-09 13:07:44 +00:00
|
|
|
{
|
2022-07-14 06:45:46 +00:00
|
|
|
//std::string path_to_3mf = "C:/Users/Filip Sykala/Downloads/EmbossFromMultiVolumes.3mf";
|
|
|
|
//int object_id = 0;
|
|
|
|
//int text_volume_id = 2;
|
|
|
|
|
|
|
|
//std::string path_to_3mf = "C:/Users/Filip Sykala/Downloads/treefrog.3mf";
|
|
|
|
//int object_id = 0;
|
|
|
|
//int text_volume_id = 1;
|
|
|
|
|
|
|
|
std::string path_to_3mf = "C:/Users/Filip Sykala/Downloads/cube_test.3mf";
|
|
|
|
int object_id = 1;
|
2022-06-09 13:07:44 +00:00
|
|
|
int text_volume_id = 2;
|
|
|
|
|
|
|
|
Model model;
|
|
|
|
DynamicPrintConfig config;
|
|
|
|
ConfigSubstitutionContext ctxt{ForwardCompatibilitySubstitutionRule::Disable};
|
|
|
|
CHECK(load_3mf(path_to_3mf.c_str(), config, ctxt, &model, false));
|
|
|
|
CHECK(object_id >= 0);
|
2022-06-21 14:14:40 +00:00
|
|
|
CHECK((size_t)object_id < model.objects.size());
|
2022-06-09 13:07:44 +00:00
|
|
|
ModelObject* mo = model.objects[object_id];
|
|
|
|
CHECK(mo != nullptr);
|
|
|
|
CHECK(text_volume_id >= 0);
|
2022-06-21 14:14:40 +00:00
|
|
|
CHECK((size_t)text_volume_id < mo->volumes.size());
|
2022-06-09 13:07:44 +00:00
|
|
|
ModelVolume *mv_text = mo->volumes[text_volume_id];
|
|
|
|
CHECK(mv_text != nullptr);
|
|
|
|
CHECK(mv_text->text_configuration.has_value());
|
|
|
|
TextConfiguration &tc = *mv_text->text_configuration;
|
|
|
|
/* // Need GUI to load font by wx
|
2022-08-03 08:25:22 +00:00
|
|
|
std::optional<wxFont> wx_font = GUI::WxFontUtils::load_wxFont(tc.style.path);
|
2022-06-09 13:07:44 +00:00
|
|
|
CHECK(wx_font.has_value());
|
|
|
|
Emboss::FontFileWithCache ff(GUI::WxFontUtils::create_font_file(*wx_font));
|
|
|
|
CHECK(ff.font_file != nullptr);
|
|
|
|
/*/ // end use GUI
|
|
|
|
// start use fake font
|
|
|
|
std::string font_path = std::string(TEST_DATA_DIR) +
|
|
|
|
"/../../resources/fonts/NotoSans-Regular.ttf";
|
|
|
|
Emboss::FontFileWithCache ff(Emboss::create_font_file(font_path.c_str()));
|
|
|
|
// */ // end use fake font
|
|
|
|
CHECK(ff.has_value());
|
2022-06-29 09:55:55 +00:00
|
|
|
std::vector<indexed_triangle_set> its = transform_volumes(mv_text);
|
|
|
|
BoundingBoxf3 bb;
|
|
|
|
for (auto &i : its) bb.merge(Slic3r::bounding_box(i));
|
|
|
|
|
|
|
|
Transform3d cut_projection_tr = mv_text->get_matrix() * tc.fix_3mf_tr->inverse();
|
|
|
|
Transform3d emboss_tr = cut_projection_tr.inverse();
|
|
|
|
BoundingBoxf3 mesh_bb_tr = bb.transformed(emboss_tr);
|
2022-06-09 13:07:44 +00:00
|
|
|
|
|
|
|
std::pair<float, float> z_range{mesh_bb_tr.min.z(), mesh_bb_tr.max.z()};
|
|
|
|
|
2022-08-03 08:25:22 +00:00
|
|
|
FontProp fp = tc.style.prop;
|
2022-06-09 13:07:44 +00:00
|
|
|
ExPolygons shapes = Emboss::text2shapes(ff, tc.text.c_str(), fp);
|
|
|
|
double shape_scale = Emboss::get_shape_scale(fp, *ff.font_file);
|
|
|
|
|
|
|
|
Emboss::OrthoProject projection = create_projection_for_cut(
|
|
|
|
cut_projection_tr, shape_scale, get_extents(shapes), z_range);
|
|
|
|
|
|
|
|
float projection_ratio = -z_range.first / (z_range.second - z_range.first);
|
2022-08-03 08:25:22 +00:00
|
|
|
SurfaceCut cut = cut_surface(shapes, its, projection, projection_ratio);
|
2022-06-24 13:55:11 +00:00
|
|
|
its_write_obj(cut, "C:/data/temp/cutSurface/result_cut.obj");
|
|
|
|
}
|
|
|
|
|
2022-06-21 14:14:40 +00:00
|
|
|
#endif // DEBUG_3MF
|