File: test_cut_surface.cpp

package info (click to toggle)
slic3r-prusa 2.9.2%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 196,524 kB
  • sloc: cpp: 534,736; ansic: 71,269; yacc: 1,311; makefile: 256; lex: 241; sh: 113
file content (172 lines) | stat: -rw-r--r-- 6,810 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#include <catch2/catch_test_macros.hpp>

#include <libslic3r/CutSurface.hpp>
#include <libslic3r/TriangleMesh.hpp> // its_make_cube + its_merge

using namespace Slic3r;
TEST_CASE("Cut character from surface", "[Emboss]")
{
    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
    double        z_depth    = 50.f; // projection size

    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());
    ExPolygons shapes = glyph->shape;
    REQUIRE(!shapes.empty());

    Transform3d tr = Transform3d::Identity();
    tr.translate(Vec3d(0., 0., -z_depth));
    double text_shape_scale = 0.001; // Emboss.cpp --> SHAPE_SCALE
    tr.scale(text_shape_scale);
    Emboss::OrthoProject cut_projection(tr, Vec3d(0., 0., z_depth));

    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));

    std::vector<indexed_triangle_set> objects{object};
    // Call core function for cut surface
    auto surfaces = cut_surface(shapes, objects, cut_projection, 0.5);
    CHECK(!surfaces.empty());

    Emboss::OrthoProject projection(Transform3d::Identity(),
                                    Vec3d(0.f, 0.f, 10.f));
    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");
}

//#define DEBUG_3MF
#ifdef DEBUG_3MF

// Test load of 3mf
#include "libslic3r/Format/3mf.hpp"
#include "libslic3r/Model.hpp"

static std::vector<indexed_triangle_set> transform_volumes(ModelVolume *mv) {
    const auto &volumes = mv->get_object()->volumes;
    std::vector<indexed_triangle_set> results;
    results.reserve(volumes.size());

    // 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;
        results.push_back(tm.its); // copy: indexed_triangle_set
        indexed_triangle_set& its = results.back();
        its_transform(its,v->get_matrix());
    }
    return results;
}

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;
    double      min_z          = z_range.first - safe_extension;
    double      max_z          = z_range.second + safe_extension;
    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);
    Vec3d project_direction = transformation_for_vector * untransformed_direction;

    // 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);
}

TEST_CASE("CutSurface in 3mf", "[Emboss]")
{
    //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;
    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);
    CHECK((size_t)object_id < model.objects.size());
    ModelObject* mo = model.objects[object_id];
    CHECK(mo != nullptr);
    CHECK(text_volume_id >= 0);
    CHECK((size_t)text_volume_id < mo->volumes.size());
    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
    std::optional<wxFont> wx_font = GUI::WxFontUtils::load_wxFont(tc.style.path);
    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());
    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);

    std::pair<float, float> z_range{mesh_bb_tr.min.z(), mesh_bb_tr.max.z()};

    FontProp fp = tc.style.prop;
    ExPolygons shapes = Emboss::text2shapes(ff, tc.text.c_str(), fp);
    double shape_scale = Emboss::get_text_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);
    SurfaceCut cut = cut_surface(shapes, its, projection, projection_ratio); 
    its_write_obj(cut, "C:/data/temp/cutSurface/result_cut.obj");
}

#endif // DEBUG_3MF