diff --git a/src/libslic3r/Emboss.cpp b/src/libslic3r/Emboss.cpp index 7b2e7404e8..5b352320b1 100644 --- a/src/libslic3r/Emboss.cpp +++ b/src/libslic3r/Emboss.cpp @@ -1270,20 +1270,27 @@ ExPolygons letter2shapes( const int CANCEL_CHECK = 10; } // namespace + +/// Union shape defined by glyphs +ExPolygons Slic3r::union_ex(const ExPolygonsWithIds &shapes) +{ + // unify to one expolygon + ExPolygons result; + for (const ExPolygonsWithId &shape : shapes) { + if (shape.expoly.empty()) + continue; + expolygons_append(result, shape.expoly); + } + result = union_ex(result); + heal_shape(result); + return result; +} + ExPolygons Emboss::text2shapes(FontFileWithCache &font_with_cache, const char *text, const FontProp &font_prop, const std::function& was_canceled) { std::wstring text_w = boost::nowide::widen(text); - std::vector vshapes = text2vshapes(font_with_cache, text_w, font_prop, was_canceled); - // unify to one expolygon - ExPolygons result; - for (ExPolygons &shapes : vshapes) { - if (shapes.empty()) - continue; - expolygons_append(result, std::move(shapes)); - } - result = Slic3r::union_ex(result); - heal_shape(result); - return result; + ExPolygonsWithIds vshapes = text2vshapes(font_with_cache, text_w, font_prop, was_canceled); + return union_ex(vshapes); } namespace { @@ -1295,10 +1302,10 @@ namespace { /// Prerequisities: shapes are aligned left top /// To detect end of lines /// Height of line for align[in font points] -void align_shape(FontProp::Align type, std::vector &shape, const std::wstring &text, int line_height); +void align_shape(FontProp::Align type, ExPolygonsWithIds &shape, const std::wstring &text, int line_height); } -std::vector Emboss::text2vshapes(FontFileWithCache &font_with_cache, const std::wstring& text, const FontProp &font_prop, const std::function& was_canceled){ +ExPolygonsWithIds Emboss::text2vshapes(FontFileWithCache &font_with_cache, const std::wstring& text, const FontProp &font_prop, const std::function& was_canceled){ assert(font_with_cache.has_value()); const FontFile &font = *font_with_cache.font_file; unsigned int font_index = font_prop.collection_number.value_or(0); @@ -1309,7 +1316,7 @@ std::vector Emboss::text2vshapes(FontFileWithCache &font_with_cache, Point cursor(0, 0); fontinfo_opt font_info_cache; - std::vector result; + ExPolygonsWithIds result; result.reserve(text.size()); for (wchar_t letter : text) { if (++counter == CANCEL_CHECK) { @@ -1317,7 +1324,8 @@ std::vector Emboss::text2vshapes(FontFileWithCache &font_with_cache, if (was_canceled()) return {}; } - result.emplace_back(letter2shapes(letter, cursor, font_with_cache, font_prop, font_info_cache)); + unsigned id = static_cast(letter); + result.push_back({id, letter2shapes(letter, cursor, font_with_cache, font_prop, font_info_cache)}); } align_shape(font_prop.align, result, text, get_line_height(font, font_prop)); @@ -1358,6 +1366,16 @@ unsigned Emboss::get_count_lines(const std::string &text) return get_count_lines(ws); } +unsigned Emboss::get_count_lines(const ExPolygonsWithIds &shapes) { + if (shapes.empty()) + return 0; // no glyphs + unsigned result = 1; // one line is minimum + for (const ExPolygonsWithId &shape_id : shapes) + if (shape_id.id == ENTER_UNICODE) + ++result; + return result; +} + void Emboss::apply_transformation(const FontProp &font_prop, Transform3d &transformation){ apply_transformation(font_prop.angle, font_prop.distance, transformation); } @@ -1953,26 +1971,26 @@ int32_t get_align_x_offset(FontProp::HorizontalAlign align, const BoundingBox &s return 0; } -void align_shape(FontProp::Align type, std::vector &shapes, const std::wstring &text, int line_height) +void align_shape(FontProp::Align type, ExPolygonsWithIds &shapes, const std::wstring &text, int line_height) { constexpr FontProp::Align no_change(FontProp::HorizontalAlign::left, FontProp::VerticalAlign::top); if (type == no_change) return; // no alignment BoundingBox shape_bb; - for (const ExPolygons& shape: shapes) - shape_bb.merge(get_extents(shape)); + for (const ExPolygonsWithId& shape: shapes) + shape_bb.merge(get_extents(shape.expoly)); auto get_line_bb = [&](size_t j) { BoundingBox line_bb; for (; j < text.length() && text[j] != '\n'; ++j) - line_bb.merge(get_extents(shapes[j])); + line_bb.merge(get_extents(shapes[j].expoly)); return line_bb; }; Point offset( get_align_x_offset(type.first, shape_bb, get_line_bb(0)), - get_align_y_offset(type.second, get_count_lines(text), line_height)); + get_align_y_offset(type.second, get_count_lines(shapes), line_height)); assert(shapes.size() == text.length()); for (size_t i = 0; i < shapes.size(); ++i) { wchar_t letter = text[i]; @@ -1980,7 +1998,7 @@ void align_shape(FontProp::Align type, std::vector &shapes, const st offset.x() = get_align_x_offset(type.first, shape_bb, get_line_bb(i+1)); continue; } - ExPolygons &shape = shapes[i]; + ExPolygons &shape = shapes[i].expoly; for (ExPolygon &s : shape) s.translate(offset); } diff --git a/src/libslic3r/Emboss.hpp b/src/libslic3r/Emboss.hpp index ca02966dbf..5c34b96702 100644 --- a/src/libslic3r/Emboss.hpp +++ b/src/libslic3r/Emboss.hpp @@ -8,6 +8,7 @@ #include // indexed_triangle_set #include "Polygon.hpp" #include "ExPolygon.hpp" +#include "EmbossShape.hpp" // ExPolygonsWithIds #include "BoundingBox.hpp" #include "TextConfiguration.hpp" @@ -148,12 +149,14 @@ namespace Emboss /// User defined property of the font /// Way to interupt processing /// Inner polygon cw(outer ccw) - ExPolygons text2shapes (FontFileWithCache &font, const char *text, const FontProp &font_prop, const std::function &was_canceled = []() {return false;}); - std::vector text2vshapes(FontFileWithCache &font, const std::wstring& text, const FontProp &font_prop, const std::function& was_canceled = []() {return false;}); + ExPolygons text2shapes (FontFileWithCache &font, const char *text, const FontProp &font_prop, const std::function &was_canceled = []() {return false;}); + ExPolygonsWithIds text2vshapes(FontFileWithCache &font, const std::wstring& text, const FontProp &font_prop, const std::function& was_canceled = []() {return false;}); + const unsigned ENTER_UNICODE = static_cast('\n'); /// Sum of character '\n' unsigned get_count_lines(const std::wstring &ws); unsigned get_count_lines(const std::string &text); + unsigned get_count_lines(const ExPolygonsWithIds &shape); /// /// Fix duplicit points and self intersections in polygons. @@ -448,5 +451,8 @@ namespace Emboss std::vector calculate_angles(int32_t distance, const PolygonPoints& polygon_points, const Polygon &polygon); } // namespace Emboss + + +ExPolygons union_ex(const ExPolygonsWithIds &shapes); } // namespace Slic3r #endif // slic3r_Emboss_hpp_ diff --git a/src/libslic3r/EmbossShape.hpp b/src/libslic3r/EmbossShape.hpp index 1dccb58c65..1685ae1a48 100644 --- a/src/libslic3r/EmbossShape.hpp +++ b/src/libslic3r/EmbossShape.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include "Point.hpp" // Transform3d @@ -46,13 +47,28 @@ struct EmbossProjection template void serialize(Archive &ar) { ar(depth, use_surface); } }; +// Help structure to identify expolygons grups +// e.g. emboss -> per glyph -> identify character +struct ExPolygonsWithId +{ + // Identificator for shape + // In text it separate letters and the name is unicode value of letter + // Is svg it is id of path + unsigned id; + + // shape defined by integer point contain only lines + // Curves are converted to sequence of lines + ExPolygons expoly; +}; +using ExPolygonsWithIds = std::vector; + /// /// Contain plane shape information to be able emboss it and edit it /// struct EmbossShape { - // shape defined by integer point consist only by lines not curves - ExPolygons shapes; + // shapes to to emboss separately over surface + ExPolygonsWithIds shapes_with_ids; // scale of shape, multiplier to get 3d point in mm from integer shape double scale = 1.; @@ -74,16 +90,21 @@ struct EmbossShape // undo / redo stack recovery template void save(Archive &ar) const { - ar(shapes, scale, projection, svg_file_path); + ar(shapes_with_ids, scale, projection, svg_file_path); cereal::save(ar, fix_3mf_tr); } template void load(Archive &ar) { - ar(shapes, scale, projection, svg_file_path); + ar(shapes_with_ids, scale, projection, svg_file_path); cereal::load(ar, fix_3mf_tr); } }; } // namespace Slic3r +// Serialization through the Cereal library +namespace cereal { +template void serialize(Archive &ar, Slic3r::ExPolygonsWithId &o) { ar(o.id, o.expoly); } +}; // namespace cereal + #endif // slic3r_EmbossShape_hpp_ diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 133e307c41..43fa9f93e9 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -3681,7 +3681,9 @@ Transform3d create_fix(const std::optional &prev, const ModelVolume return *prev * fix_trmat; } -std::string to_string(const ExPolygons& expolygons){ +std::string to_string(const ExPolygonsWithIds &shapes) +{ + // TODO: Need to implement return {}; } @@ -3692,7 +3694,7 @@ void to_xml(std::stringstream &stream, const EmbossShape &es, const ModelVolume stream << SVG_FILE_PATH_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(es.svg_file_path) << "\" "; stream << SHAPE_SCALE_ATTR << "=\"" << es.scale << "\" "; - std::string expolygons_str = to_string(es.shapes); // cereal serialize expolygons + std::string expolygons_str = to_string(es.shapes_with_ids); // cereal serialize expolygons stream << SHAPE_EXPOLYS_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(expolygons_str) << "\" "; // projection @@ -3710,7 +3712,7 @@ void to_xml(std::stringstream &stream, const EmbossShape &es, const ModelVolume } std::optional read_emboss_shape(const char **attributes, unsigned int num_attributes) { - ExPolygons shapes; + double scale = get_attribute_value_float(attributes, num_attributes, SHAPE_SCALE_ATTR); EmbossProjection projection; @@ -3725,7 +3727,8 @@ std::optional read_emboss_shape(const char **attributes, unsigned i fix_tr_mat = get_transform_from_3mf_specs_string(fix_tr_mat_str); } std::string file_path = get_attribute_value_string(attributes, num_attributes, SVG_FILE_PATH_ATTR); - return EmbossShape{std::move(shapes), scale, std::move(projection), std::move(fix_tr_mat), std::move(file_path)}; + ExPolygonsWithIds shapes; // TODO: need to implement + return EmbossShape{shapes, scale, std::move(projection), std::move(fix_tr_mat), std::move(file_path)}; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 318079ab37..2f0d3508c9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -345,7 +345,7 @@ bool GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mous return false; // NOTE: change style manager - be carefull with order changes - DataBasePtr base = create_emboss_data_base(m_text, m_style_manager, m_job_cancel); + DataBasePtr base = create_emboss_data_base(m_text, m_style_manager, m_text_lines, m_parent.get_selection(), volume_type, m_job_cancel); CreateVolumeParams input = create_input(m_parent, m_style_manager.get_style(), m_raycast_manager, volume_type); return start_create_volume(input, std::move(base), mouse_pos); } @@ -357,7 +357,7 @@ bool GLGizmoEmboss::create_volume(ModelVolumeType volume_type) return false; // NOTE: change style manager - be carefull with order changes - DataBasePtr base = create_emboss_data_base(m_text, m_style_manager, m_job_cancel); + DataBasePtr base = create_emboss_data_base(m_text, m_style_manager, m_text_lines, m_parent.get_selection(), volume_type, m_job_cancel); CreateVolumeParams input = create_input(m_parent, m_style_manager.get_style(), m_raycast_manager, volume_type); return start_create_volume_without_position(input, std::move(base)); } @@ -1043,9 +1043,6 @@ std::optional get_installed_face_name(const std::optional } return {}; // not installed } -} // namespace - -namespace { bool get_line_height_offset(/* const*/ StyleManager &style_manager, double &line_height_mm, double &line_offset_mm) { @@ -1066,8 +1063,8 @@ bool get_line_height_offset(/* const*/ StyleManager &style_manager, double &line double third_ascent_shape_size = ff.infos[fp.collection_number.value_or(0)].ascent / 3.; int line_height_shape_size = get_line_height(ff, fp); // In shape size - double scale = get_shape_scale(fp, ff); - line_offset_mm = third_ascent_shape_size * scale / SHAPE_SCALE; + double scale = get_text_shape_scale(fp, ff); + line_offset_mm = third_ascent_shape_size * scale / 0.001; // TODO:fix constatnt SHAPE_SCALE line_height_mm = line_height_shape_size * scale; if (line_height_mm < 0) @@ -1279,7 +1276,7 @@ void GLGizmoEmboss::set_volume_by_selection() // Calculate current angle of up vector assert(m_style_manager.is_active_font()); if (m_style_manager.is_active_font()) - m_style_manager.get_font_prop().angle = calc_up(gl_volume->world_matrix(), priv::up_limit); + m_style_manager.get_font_prop().angle = calc_up(gl_volume->world_matrix(), up_limit); // calculate scale for height and depth inside of scaled object instance calculate_scale(); @@ -1322,6 +1319,10 @@ void GLGizmoEmboss::calculate_scale() { m_style_manager.clear_imgui_font(); } +namespace { +bool is_text_empty(std::string_view text) { return text.empty() || text.find_first_not_of(" \n\t\r") == std::string::npos; } +} // namespace + bool GLGizmoEmboss::process() { // no volume is selected -> selection from right panel @@ -1329,27 +1330,26 @@ bool GLGizmoEmboss::process() if (m_volume == nullptr) return false; // without text there is nothing to emboss - if (priv::is_text_empty(m_text)) return false; + if (is_text_empty(m_text)) return false; // exist loaded font file? if (!m_style_manager.is_active_font()) return false; - DataUpdate data{priv::create_emboss_data_base(m_text, m_style_manager, m_text_lines, m_parent.get_selection(), m_volume->type(), m_job_cancel), + DataUpdate data{create_emboss_data_base(m_text, m_style_manager, m_text_lines, m_parent.get_selection(), m_volume->type(), m_job_cancel), m_volume->id()}; std::unique_ptr job = nullptr; // check cutting from source mesh - bool &use_surface = data.text_configuration.style.prop.use_surface; - bool is_object = m_volume->get_object()->volumes.size() == 1; - if (use_surface && is_object) + bool &use_surface = data.base->shape.projection.use_surface; + if (use_surface && m_volume->is_the_only_one_part()) use_surface = false; - assert(!data.text_configuration.style.prop.per_glyph || - get_count_lines(m_text) == m_text_lines.get_lines().size()); + assert(data.base->text_lines.empty() || + data.base->text_lines.size() == get_count_lines(m_text)); if (use_surface) { // Model to cut surface from. - SurfaceVolumeData::ModelSources sources = create_volume_sources(m_volume); + SurfaceVolumeData::ModelSources sources = create_volume_sources(*m_volume); if (sources.empty()) return false; @@ -1382,7 +1382,7 @@ bool GLGizmoEmboss::process() queue_job(worker, std::move(job)); #else // Run Job on main thread (blocking) - ONLY DEBUG - priv::execute_job(std::move(job)); + execute_job(std::move(job)); #endif // EXECUTE_PROCESS_ON_MAIN_THREAD // notification is removed befor object is changed by job @@ -1390,10 +1390,6 @@ bool GLGizmoEmboss::process() return true; } -namespace { -bool is_text_empty(std::string_view text) { return text.empty() || text.find_first_not_of(" \n\t\r") == std::string::npos; } -} - void GLGizmoEmboss::close() { // remove volume when text is empty @@ -1506,7 +1502,7 @@ void GLGizmoEmboss::draw_window() ImGui::SameLine(); if (ImGui::Checkbox("##ALLOW_OPEN_NEAR_VOLUME", &m_allow_open_near_volume)) { if (m_allow_open_near_volume) - m_set_window_offset = priv::calc_fine_position(m_parent.get_selection(), get_minimal_window_size(), m_parent.get_canvas_size()); + m_set_window_offset = calc_fine_position(m_parent.get_selection(), get_minimal_window_size(), m_parent.get_canvas_size()); } else if (ImGui::IsItemHovered()) { ImGui::SetTooltip("%s", ((m_allow_open_near_volume) ? "Fix settings position": @@ -2598,17 +2594,6 @@ void GLGizmoEmboss::draw_height(bool use_inch) process(); } -bool GLGizmoEmboss::set_depth() -{ - float &value = m_style_manager.get_font_prop().emboss; - - // size can't be zero or negative - priv::Limits::apply(value, priv::limits.emboss); - - // only different value need process - return !is_approx(value, m_volume->text_configuration->style.prop.emboss); -} - void GLGizmoEmboss::draw_depth(bool use_inch) { double &value = m_style_manager.get_style().projection.depth; @@ -2745,6 +2730,7 @@ void GLGizmoEmboss::draw_advanced() } m_imgui->disabled_end(); // !can_use_surface + FontProp& font_prop = m_style_manager.get_font_prop(); bool &per_glyph = font_prop.per_glyph; bool can_use_per_glyph = (per_glyph) ? true : // already used surface must have option to uncheck !is_the_only_one_part; @@ -2777,9 +2763,9 @@ void GLGizmoEmboss::draw_advanced() ImGui::SetTooltip("TEST PURPOSE ONLY\nMove base line (up/down) for allign letters"); m_imgui->disabled_end(); // !per_glyph - auto draw_align = [&align = font_prop.align, gui_cfg = m_gui_cfg, &icons = m_icons]() { + auto draw_align = [&align = font_prop.align, input_offset = m_gui_cfg->advanced_input_offset, &icons = m_icons]() { bool is_change = false; - ImGui::SameLine(gui_cfg->advanced_input_offset); + ImGui::SameLine(input_offset); if (align.first==FontProp::HorizontalAlign::left) draw(get_icon(icons, IconType::align_horizontal_left, IconState::hovered)); else if (draw_button(icons, IconType::align_horizontal_left)) { align.first=FontProp::HorizontalAlign::left; is_change = true; } else if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", _u8L("Set left alignment").c_str()); @@ -3013,7 +2999,7 @@ void GLGizmoEmboss::draw_advanced() assert(get_selected_volume(m_parent.get_selection()) == m_volume); const Camera &cam = wxGetApp().plater()->get_camera(); if (face_selected_volume_to_camera(cam, m_parent) && - (use_surface || prop.per_glyph)) + (use_surface || m_style_manager.get_font_prop().per_glyph)) process(); } else if (ImGui::IsItemHovered()) { ImGui::SetTooltip("%s", _u8L("Orient the text towards the camera.").c_str()); @@ -3149,7 +3135,7 @@ bool GLGizmoEmboss::choose_true_type_file() // use first valid font for (auto &input_file : input_files) { std::string path = std::string(input_file.c_str()); - std::string name = priv::get_file_name(path); + std::string name = get_file_name(path); //make_unique_name(name, m_font_list); const FontProp& prop = m_style_manager.get_font_prop(); EmbossStyle style{ name, path, EmbossStyle::Type::file_path, prop }; @@ -3306,14 +3292,16 @@ TextDataBase::TextDataBase(DataBase &&parent, EmbossShape &TextDataBase::create_shape() { - if (!shape.shapes.empty()) + if (!shape.shapes_with_ids.empty()) return shape; // create shape by configuration const char *text = m_text_configuration.text.c_str(); + std::wstring text_w = boost::nowide::widen(text); const FontProp &fp = m_text_configuration.style.prop; auto was_canceled = [&c = cancel](){ return c->load(); }; - shape.shapes = text2shapes(m_font_file, text, fp, was_canceled); + + shape.shapes_with_ids = text2vshapes(m_font_file, text_w, fp, was_canceled); return shape; } @@ -3370,7 +3358,7 @@ std::unique_ptr create_emboss_data_base(const std::string assert(style_manager.get_wx_font().IsOk()); assert(style.path.compare(WxFontUtils::store_wxFont(style_manager.get_wx_font())) == 0); - if (es.prop.per_glyph) { + if (style.prop.per_glyph) { if (!text_lines.is_init()) init_text_lines(text_lines, selection, style_manager); } else @@ -3386,9 +3374,12 @@ std::unique_ptr create_emboss_data_base(const std::string // create new shared ptr to cancel new job cancel = std::make_shared>(false); DataBase base(volume_name, cancel); + base.is_outside = is_outside; + base.text_lines = text_lines.get_lines(); + FontFileWithCache &font = style_manager.get_font_file_with_cache(); TextConfiguration tc{static_cast(style), text}; - return std::make_unique(std::move(base), font, std::move(tc), style.projection, is_outside, text_lines.get_lines()); + return std::make_unique(std::move(base), font, std::move(tc), style.projection); } CreateVolumeParams create_input(GLCanvas3D &canvas, const StyleManager::Style &style, RaycastManager& raycaster, ModelVolumeType volume_type) @@ -3696,6 +3687,8 @@ GuiCfg create_gui_configuration() cfg.input_offset = style.WindowPadding.x + cfg.indent + max_text_width + space; tr.use_surface = _u8L("Use surface"); + tr.per_glyph = _u8L("Per glyph orientation"); + tr.alignment = _u8L("Alignment"); tr.char_gap = _u8L("Char gap"); tr.line_gap = _u8L("Line gap"); tr.boldness = _u8L("Boldness"); @@ -3707,6 +3700,8 @@ GuiCfg create_gui_configuration() float max_advanced_text_width = std::max({ ImGui::CalcTextSize(tr.use_surface.c_str()).x, + ImGui::CalcTextSize(tr.per_glyph.c_str()).x, + ImGui::CalcTextSize(tr.alignment.c_str()).x, ImGui::CalcTextSize(tr.char_gap.c_str()).x, ImGui::CalcTextSize(tr.line_gap.c_str()).x, ImGui::CalcTextSize(tr.boldness.c_str()).x, @@ -3742,7 +3737,7 @@ GuiCfg create_gui_configuration() // 9 = useSurface, charGap, lineGap, bold, italic, surfDist, rotation, keepUp, textFaceToCamera // 4 = 1px for fix each edit image of drag float - float advance_height = input_height * 8 + 8; + float advance_height = input_height * 10 + 9; cfg.minimal_window_size_with_advance = ImVec2(cfg.minimal_window_size.x, cfg.minimal_window_size.y + advance_height); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp index 3091b822f8..b96ea0ac39 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp @@ -483,7 +483,7 @@ void GLGizmoSVG::reset_volume() m_volume = nullptr; m_volume_id.id = 0; - m_volume_shape.shapes.clear(); + m_volume_shape.shapes_with_ids.clear(); } void GLGizmoSVG::calculate_scale() { @@ -562,7 +562,7 @@ void GLGizmoSVG::draw_window() ImGui::Unindent(m_gui_cfg->icon_width); if (ImGui::Button("change file")) { - m_volume_shape.shapes = select_shape().shapes; + m_volume_shape.shapes_with_ids = select_shape().shapes_with_ids; // TODO: use setted scale process(); } @@ -597,6 +597,16 @@ void GLGizmoSVG::draw_depth() ImGui::SetTooltip("%s", _u8L("Size in emboss direction.").c_str()); } +namespace Slic3r { +BoundingBox get_extents(const ExPolygonsWithIds &expoly_ids) +{ + BoundingBox result; + for (const ExPolygonsWithId &expoly_id : expoly_ids) + result.merge(get_extents(expoly_id.expoly)); + return result; +} +} // namespace Slic3r + void GLGizmoSVG::draw_size() { ImGuiWrapper::text(m_gui_cfg->translations.size); @@ -610,7 +620,7 @@ void GLGizmoSVG::draw_size() ImGui::SetNextItemWidth(input_width); // TODO: cache it - BoundingBox bb = get_extents(m_volume_shape.shapes); + BoundingBox bb = get_extents(m_volume_shape.shapes_with_ids); Point size = bb.size(); const char *size_format = (use_inch) ? "%.2f in" : "%.1f mm"; @@ -992,6 +1002,7 @@ ExPolygons default_shape() std::string file = Slic3r::resources_dir() + "/icons/question.svg"; NSVGimage *image = nsvgParseFromFile(file.c_str(), "px", 96.0f); ExPolygons shape = to_expolygons(image); + assert(!shape.empty()); nsvgDelete(image); return shape; } @@ -1018,11 +1029,14 @@ EmbossShape select_shape() int max_level = 10; float scale = static_cast(1 / shape.scale); bool is_y_negative = true; - shape.shapes = to_expolygons(image, tesselation_tolerance, max_level, scale, is_y_negative); + ExPolygons expoly = to_expolygons(image, tesselation_tolerance, max_level, scale, is_y_negative); // Must contain some shapes !!! - if (shape.shapes.empty()) - shape.shapes = default_shape(); + if (expoly.empty()) + expoly = default_shape(); + + unsigned id = 0; + shape.shapes_with_ids = {{id, expoly}}; return shape; } @@ -1031,7 +1045,7 @@ DataBasePtr create_emboss_data_base(std::shared_ptr> &cancel) { EmbossShape shape = select_shape(); - if (shape.shapes.empty()) + if (shape.shapes_with_ids.empty()) // canceled selection of SVG file return nullptr; diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp index a5d4542de0..28df15a5bc 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.cpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp @@ -160,7 +160,6 @@ bool check(const CreateSurfaceVolumeData &input, bool is_main_thread = false); bool check(const UpdateSurfaceVolumeData &input, bool is_main_thread = false); template static ExPolygons create_shape(DataBase &input, Fnc was_canceled); -template static std::vector create_shapes(DataBase &input, Fnc was_canceled); // create sure that emboss object is bigger than source object [in mm] constexpr float safe_extension = 1.0f; @@ -273,10 +272,9 @@ void Slic3r::GUI::Emboss::DataBase::write(ModelVolume &volume) const{ CreateVolumeJob::CreateVolumeJob(DataCreateVolume &&input): m_input(std::move(input)){ assert(check(m_input, true)); } void CreateVolumeJob::process(Ctl &ctl) { - if (!priv::check(m_input)) throw std::runtime_error("Bad input data for EmbossCreateVolumeJob."); - auto was_canceled = [&ctl]()->bool { return ctl.was_canceled(); }; - m_result = priv::create_mesh(m_input, was_canceled, ctl); - //m_result = create_mesh(*m_input.base, was_canceled(ctl, *m_input.base), ctl); // svg + if (!check(m_input)) + throw std::runtime_error("Bad input data for EmbossCreateVolumeJob."); + m_result = create_mesh(*m_input.base, was_canceled(ctl, *m_input.base), ctl); } void CreateVolumeJob::finalize(bool canceled, std::exception_ptr &eptr) { if (!::finalize(canceled, eptr, *m_input.base)) @@ -393,7 +391,7 @@ void UpdateJob::process(Ctl &ctl) m_result = ::try_create_mesh(*m_input.base, was_canceled); if (was_canceled()) return; if (m_result.its.empty()) - throw priv::JobException("Created text volume is empty. Change text or font."); + throw JobException("Created text volume is empty. Change text or font."); } void UpdateJob::finalize(bool canceled, std::exception_ptr &eptr) @@ -658,10 +656,7 @@ bool start_update_volume(DataUpdate &&data, const ModelVolume &volume, const Sel volume_tr *= Eigen::Translation(*offset); } - bool is_outside = volume.is_model_part(); - // check that there is not unexpected volume type - assert(is_outside || volume.is_negative_volume() || volume.is_modifier()); - UpdateSurfaceVolumeData surface_data{std::move(data), {volume_tr, is_outside, std::move(sources)}}; + UpdateSurfaceVolumeData surface_data{std::move(data), {volume_tr, std::move(sources)}}; job = std::make_unique(std::move(surface_data)); } else { job = std::make_unique(std::move(data)); @@ -694,13 +689,13 @@ bool check(const DataBase &input, bool check_fontfile, bool use_surface) // res &= !input.text_configuration.text.empty(); assert(!input.volume_name.empty()); res &= !input.volume_name.empty(); - const FontProp& prop = input.text_configuration.style.prop; - assert(prop.per_glyph == !input.text_lines.empty()); - res &= prop.per_glyph == !input.text_lines.empty(); - if (prop.per_glyph) { - assert(get_count_lines(input.text_configuration.text) == input.text_lines.size()); - res &= get_count_lines(input.text_configuration.text) == input.text_lines.size(); - } + //const FontProp& prop = input.text_configuration.style.prop; + //assert(prop.per_glyph == !input.text_lines.empty()); + //res &= prop.per_glyph == !input.text_lines.empty(); + //if (prop.per_glyph) { + // assert(get_count_lines(input.text_configuration.text) == input.text_lines.size()); + // res &= get_count_lines(input.text_configuration.text) == input.text_lines.size(); + //} return res; } @@ -791,70 +786,34 @@ bool check(const UpdateSurfaceVolumeData &input, bool is_main_thread) } template -ExPolygons priv::create_shape(DataBase &input, Fnc was_canceled) { - FontFileWithCache &font = input.font_file; - const TextConfiguration &tc = input.text_configuration; - const char *text = tc.text.c_str(); - const FontProp &prop = tc.style.prop; - assert(!prop.per_glyph); - assert(font.has_value()); - if (!font.has_value()) - return {}; - - ExPolygons shapes = text2shapes(font, text, prop, was_canceled); - if (shapes.empty()) - return {}; - - return shapes; -} - -template -std::vector priv::create_shapes(DataBase &input, Fnc was_canceled) { - FontFileWithCache &font = input.font_file; - const TextConfiguration &tc = input.text_configuration; - const char *text = tc.text.c_str(); - const FontProp &prop = tc.style.prop; - assert(prop.per_glyph); - assert(font.has_value()); - if (!font.has_value()) - return {}; - - std::wstring ws = boost::nowide::widen(text); - std::vector shapes = text2vshapes(font, ws, prop, was_canceled); - if (shapes.empty()) - return {}; - - if (was_canceled()) - return {}; - - return shapes; +ExPolygons create_shape(DataBase &input, Fnc was_canceled) { + const EmbossShape &es = input.create_shape(); + return union_ex(es.shapes_with_ids); } //#define STORE_SAMPLING #ifdef STORE_SAMPLING #include "libslic3r/SVG.hpp" #endif // STORE_SAMPLING -namespace { -std::vector create_line_bounds(const std::vector &shapes, const std::wstring& text, size_t count_lines = 0) +std::vector create_line_bounds(const ExPolygonsWithIds &shapes, size_t count_lines = 0) { - assert(text.size() == shapes.size()); if (count_lines == 0) - count_lines = get_count_lines(text); - assert(count_lines == get_count_lines(text)); + count_lines = get_count_lines(shapes); + assert(count_lines == get_count_lines(shapes)); std::vector result(count_lines); size_t text_line_index = 0; // s_i .. shape index - for (size_t s_i = 0; s_i < shapes.size(); ++s_i) { - const ExPolygons &shape = shapes[s_i]; + for (const ExPolygonsWithId &shape_id: shapes) { + const ExPolygons &shape = shape_id.expoly; BoundingBox bb; if (!shape.empty()) { bb = get_extents(shape); } BoundingBoxes &line_bbs = result[text_line_index]; line_bbs.push_back(bb); - if (text[s_i] == '\n'){ + if (shape_id.id == ENTER_UNICODE) { // skip enters on beginig and tail ++text_line_index; } @@ -866,28 +825,23 @@ template TriangleMesh create_mesh_per_glyph(DataBase &input, Fnc w { // method use square of coord stored into int64_t static_assert(std::is_same()); - - std::vector shapes = priv::create_shapes(input, was_canceled); - if (shapes.empty()) + const EmbossShape &shape = input.create_shape(); + if (shape.shapes_with_ids.empty()) return {}; - + // Precalculate bounding boxes of glyphs // Separate lines of text to vector of Bounds - const TextConfiguration &tc = input.text_configuration; - std::wstring ws = boost::nowide::widen(tc.text.c_str()); - assert(get_count_lines(ws) == input.text_lines.size()); + assert(get_count_lines(shape.shapes_with_ids) == input.text_lines.size()); size_t count_lines = input.text_lines.size(); - std::vector bbs = create_line_bounds(shapes, ws, count_lines); - - const FontProp &prop = tc.style.prop; - FontFileWithCache &font = input.font_file; - double shape_scale = get_shape_scale(prop, *font.font_file); - double projec_scale = shape_scale / SHAPE_SCALE; - double depth = prop.emboss / projec_scale; + std::vector bbs = create_line_bounds(shape.shapes_with_ids, count_lines); + + double projec_scale = shape.scale / 0.001; // SHAPE_SCALE; + double depth = shape.projection.depth / projec_scale; auto scale_tr = Eigen::Scaling(projec_scale); // half of font em size for direction of letter emboss - double em_2_mm = prop.size_in_mm / 2.; + // double em_2_mm = prop.size_in_mm / 2.; // TODO: fix it + double em_2_mm = 5.; int32_t em_2_polygon = static_cast(std::round(scale_(em_2_mm))); size_t s_i_offset = 0; // shape index offset(for next lines) @@ -895,7 +849,7 @@ template TriangleMesh create_mesh_per_glyph(DataBase &input, Fnc w for (size_t text_line_index = 0; text_line_index < input.text_lines.size(); ++text_line_index) { const BoundingBoxes &line_bbs = bbs[text_line_index]; const TextLine &line = input.text_lines[text_line_index]; - PolygonPoints samples = sample_slice(line, line_bbs, shape_scale); + PolygonPoints samples = sample_slice(line, line_bbs, shape.scale); std::vector angles = calculate_angles(em_2_polygon, samples, line.polygon); for (size_t i = 0; i < line_bbs.size(); ++i) { @@ -903,10 +857,12 @@ template TriangleMesh create_mesh_per_glyph(DataBase &input, Fnc w if (!letter_bb.defined) continue; - Vec2d to_zero_vec = letter_bb.center().cast() * shape_scale; // [in mm] - float surface_offset = input.is_outside ? -priv::SAFE_SURFACE_OFFSET : (-prop.emboss + priv::SAFE_SURFACE_OFFSET); - if (prop.distance.has_value()) - surface_offset += *prop.distance; + Vec2d to_zero_vec = letter_bb.center().cast() * shape.scale; // [in mm] + float surface_offset = input.is_outside ? -SAFE_SURFACE_OFFSET : (-shape.projection.depth + SAFE_SURFACE_OFFSET); + + // TODO: fix it + //if (prop.distance.has_value()) + // surface_offset += *prop.distance; Eigen::Translation to_zero(-to_zero_vec.x(), 0., static_cast(surface_offset)); @@ -918,7 +874,7 @@ template TriangleMesh create_mesh_per_glyph(DataBase &input, Fnc w Eigen::Translation offset_tr(offset_vec.x(), 0., -offset_vec.y()); Transform3d tr = offset_tr * rotate * to_zero * scale_tr; - const ExPolygons &letter_shape = shapes[s_i_offset + i]; + const ExPolygons &letter_shape = shape.shapes_with_ids[s_i_offset + i].expoly; assert(get_extents(letter_shape) == letter_bb); auto projectZ = std::make_unique(depth); ProjectTransform project(std::move(projectZ), tr); @@ -958,24 +914,8 @@ template TriangleMesh create_mesh_per_glyph(DataBase &input, Fnc w return TriangleMesh(std::move(result)); } -// svg -template TriangleMesh try_create_mesh(DataBase& base, const Fnc& was_canceled) -{ - const EmbossShape& shape = base.create_shape(); - if (shape.shapes.empty()) - return {}; - double depth = shape.projection.depth / shape.scale; - auto projectZ = std::make_unique(depth); - ProjectScale project(std::move(projectZ), shape.scale); - if (was_canceled()) - return {}; - return TriangleMesh(polygons2model(shape.shapes, project)); -} -} // namespace - - template -TriangleMesh priv::try_create_mesh(DataBase &input, Fnc was_canceled) +TriangleMesh try_create_mesh(DataBase &input, const Fnc& was_canceled) { if (!input.text_lines.empty()) { TriangleMesh tm = create_mesh_per_glyph(input, was_canceled); @@ -983,17 +923,15 @@ TriangleMesh priv::try_create_mesh(DataBase &input, Fnc was_canceled) if (!tm.empty()) return tm; } - ExPolygons shapes = priv::create_shape(input, was_canceled); + ExPolygons shapes = create_shape(input, was_canceled); if (shapes.empty()) return {}; if (was_canceled()) return {}; - const FontProp &prop = input.text_configuration.style.prop; - const FontFile &ff = *input.font_file.font_file; // NOTE: SHAPE_SCALE is applied in ProjectZ - double scale = get_shape_scale(prop, ff) / SHAPE_SCALE; - double depth = prop.emboss / scale; + double scale = input.shape.scale; + double depth = input.shape.projection.depth / scale; auto projectZ = std::make_unique(depth); - float offset = input.is_outside ? -SAFE_SURFACE_OFFSET : (SAFE_SURFACE_OFFSET - prop.emboss); + float offset = input.is_outside ? -SAFE_SURFACE_OFFSET : (SAFE_SURFACE_OFFSET - input.shape.projection.depth); Transform3d tr = Eigen::Translation(0., 0.,static_cast(offset)) * Eigen::Scaling(scale); ProjectTransform project(std::move(projectZ), tr); if (was_canceled()) return {}; @@ -1001,7 +939,7 @@ TriangleMesh priv::try_create_mesh(DataBase &input, Fnc was_canceled) } template -TriangleMesh priv::create_mesh(DataBase &input, Fnc was_canceled, Job::Ctl& ctl) +TriangleMesh create_mesh(DataBase &input, const Fnc& was_canceled, Job::Ctl& ctl) { // It is neccessary to create some shape // Emboss text window is opened by creation new emboss text object @@ -1015,8 +953,7 @@ TriangleMesh priv::create_mesh(DataBase &input, Fnc was_canceled, Job::Ctl& ctl) return {}; // only info ctl.call_on_main_thread([]() { - create_message("It is used default volume for embossed " - "text, try to change text or font to fix it."); + create_message("It is used default volume for embossed text, try to change text or font to fix it."); }); } @@ -1036,7 +973,6 @@ TriangleMesh create_default_mesh() return triangle_mesh; } -namespace{ void update_volume_name(const ModelVolume &volume, const ObjectList *obj_list) { if (obj_list == nullptr) @@ -1070,7 +1006,7 @@ void update_volume_name(const ModelVolume &volume, const ObjectList *obj_list) } obj_list->update_name_in_list(object_idx, volume_idx); } -} + void update_name_in_list(const ObjectList& object_list, const ModelVolume& volume) { const ModelObjectPtrs *objects_ptr = object_list.objects(); @@ -1275,14 +1211,10 @@ OrthoProject3d create_emboss_projection(bool is_outside, float emboss, Transform return OrthoProject3d(from_front_to_back); } -namespace { - indexed_triangle_set cut_surface_to_its(const ExPolygons &shapes, const Transform3d& tr,const SurfaceVolumeData::ModelSources &sources, DataBase& input, std::function was_canceled) { assert(!sources.empty()); BoundingBox bb = get_extents(shapes); - const FontFile &ff = *input.font_file.font_file; - const FontProp &fp = input.text_configuration.style.prop; - double shape_scale = get_shape_scale(fp, ff); + double shape_scale = input.shape.scale; const SurfaceVolumeData::ModelSource *biggest = &sources.front(); @@ -1295,7 +1227,7 @@ indexed_triangle_set cut_surface_to_its(const ExPolygons &shapes, const Transfor Transform3d mesh_tr_inv = s.tr.inverse(); Transform3d cut_projection_tr = mesh_tr_inv * tr; std::pair z_range{0., 1.}; - OrthoProject cut_projection = priv::create_projection_for_cut(cut_projection_tr, shape_scale, z_range); + OrthoProject cut_projection = create_projection_for_cut(cut_projection_tr, shape_scale, z_range); // copy only part of source model indexed_triangle_set its = its_cut_AoI(s.mesh->its, bb, cut_projection); if (its.indices.empty()) @@ -1336,9 +1268,9 @@ indexed_triangle_set cut_surface_to_its(const ExPolygons &shapes, const Transfor Transform3d emboss_tr = cut_projection_tr.inverse(); BoundingBoxf3 mesh_bb_tr = mesh_bb.transformed(emboss_tr); std::pair z_range{mesh_bb_tr.min.z(), mesh_bb_tr.max.z()}; - OrthoProject cut_projection = priv::create_projection_for_cut(cut_projection_tr, shape_scale, z_range); - float projection_ratio = (-z_range.first + priv::safe_extension) / - (z_range.second - z_range.first + 2 * priv::safe_extension); + OrthoProject cut_projection = create_projection_for_cut(cut_projection_tr, shape_scale, z_range); + float projection_ratio = (-z_range.first + safe_extension) / + (z_range.second - z_range.first + 2 * safe_extension); ExPolygons shapes_data; // is used only when text is reflected to reverse polygon points order const ExPolygons *shapes_ptr = &shapes; @@ -1369,31 +1301,25 @@ indexed_triangle_set cut_surface_to_its(const ExPolygons &shapes, const Transfor if (was_canceled()) return {}; // !! Projection needs to transform cut - OrthoProject3d projection = priv::create_emboss_projection(input.is_outside, fp.emboss, emboss_tr, cut); + OrthoProject3d projection = create_emboss_projection(input.is_outside, input.shape.projection.depth, emboss_tr, cut); return cut2model(cut, projection); } TriangleMesh cut_per_glyph_surface(DataBase &input1, const SurfaceVolumeData &input2, std::function was_canceled) { - std::vector shapes = priv::create_shapes(input1, was_canceled); - if (was_canceled()) return {}; - if (shapes.empty()) - throw priv::JobException(_u8L("Font doesn't have any shape for given text.").c_str()); - // Precalculate bounding boxes of glyphs // Separate lines of text to vector of Bounds - const TextConfiguration &tc = input1.text_configuration; - std::wstring ws = boost::nowide::widen(tc.text.c_str()); - assert(get_count_lines(ws) == input1.text_lines.size()); - size_t count_lines = input1.text_lines.size(); - std::vector bbs = create_line_bounds(shapes, ws, count_lines); + const EmbossShape &es = input1.create_shape(); + if (was_canceled()) return {}; + if (es.shapes_with_ids.empty()) + throw JobException(_u8L("Font doesn't have any shape for given text.").c_str()); - const FontProp &prop = tc.style.prop; - FontFileWithCache &font = input1.font_file; - double shape_scale = get_shape_scale(prop, *font.font_file); - + assert(get_count_lines(es.shapes_with_ids) == input1.text_lines.size()); + size_t count_lines = input1.text_lines.size(); + std::vector bbs = create_line_bounds(es.shapes_with_ids, count_lines); + // half of font em size for direction of letter emboss - double em_2_mm = prop.size_in_mm / 2.; + double em_2_mm = 5.; // TODO: fix it int32_t em_2_polygon = static_cast(std::round(scale_(em_2_mm))); size_t s_i_offset = 0; // shape index offset(for next lines) @@ -1401,7 +1327,7 @@ TriangleMesh cut_per_glyph_surface(DataBase &input1, const SurfaceVolumeData &in for (size_t text_line_index = 0; text_line_index < input1.text_lines.size(); ++text_line_index) { const BoundingBoxes &line_bbs = bbs[text_line_index]; const TextLine &line = input1.text_lines[text_line_index]; - PolygonPoints samples = sample_slice(line, line_bbs, shape_scale); + PolygonPoints samples = sample_slice(line, line_bbs, es.scale); std::vector angles = calculate_angles(em_2_polygon, samples, line.polygon); for (size_t i = 0; i < line_bbs.size(); ++i) { @@ -1416,7 +1342,7 @@ TriangleMesh cut_per_glyph_surface(DataBase &input1, const SurfaceVolumeData &in Vec2d offset_vec = unscale(sample.point); // [in mm] auto offset_tr = Eigen::Translation(offset_vec.x(), 0., -offset_vec.y()); - ExPolygons &glyph_shape = shapes[s_i_offset + i]; + ExPolygons glyph_shape = es.shapes_with_ids[s_i_offset + i].expoly; assert(get_extents(glyph_shape) == glyph_bb); Point offset(-glyph_bb.center().x(), 0); @@ -1424,7 +1350,7 @@ TriangleMesh cut_per_glyph_surface(DataBase &input1, const SurfaceVolumeData &in s.translate(offset); Transform3d modify = offset_tr * rotate; - Transform3d tr = input2.text_tr * modify; + Transform3d tr = input2.transform * modify; indexed_triangle_set glyph_its = cut_surface_to_its(glyph_shape, tr, input2.sources, input1, was_canceled); // move letter in volume on the right position its_transform(glyph_its, modify); @@ -1440,17 +1366,15 @@ TriangleMesh cut_per_glyph_surface(DataBase &input1, const SurfaceVolumeData &in if (was_canceled()) return {}; if (result.empty()) - throw priv::JobException(_u8L("There is no valid surface for text projection.").c_str()); + throw JobException(_u8L("There is no valid surface for text projection.").c_str()); return TriangleMesh(std::move(result)); } -} // namespace - // input can't be const - cache of font -TriangleMesh priv::cut_surface(DataBase& input1, const SurfaceVolumeData& input2, std::function was_canceled) +template +TriangleMesh cut_surface(DataBase& input1, const SurfaceVolumeData& input2, const Fnc& was_canceled) { - const FontProp &fp = input1.text_configuration.style.prop; - if (fp.per_glyph) + if (!input1.text_lines.empty()) return cut_per_glyph_surface(input1, input2, was_canceled); ExPolygons shapes = create_shape(input1, was_canceled); @@ -1458,7 +1382,7 @@ TriangleMesh priv::cut_surface(DataBase& input1, const SurfaceVolumeData& input2 if (shapes.empty()) throw JobException(_u8L("Font doesn't have any shape for given text.").c_str()); - indexed_triangle_set its = cut_surface_to_its(shapes, input2.text_tr, input2.sources, input1, was_canceled); + indexed_triangle_set its = cut_surface_to_its(shapes, input2.transform, input2.sources, input1, was_canceled); if (was_canceled()) return {}; if (its.empty()) throw JobException(_u8L("There is no valid surface for text projection.").c_str()); @@ -1537,7 +1461,7 @@ bool start_create_volume_job(Worker &worker, bool is_outside = volume_type == ModelVolumeType::MODEL_PART; // check that there is not unexpected volume type assert(is_outside || volume_type == ModelVolumeType::NEGATIVE_VOLUME || volume_type == ModelVolumeType::PARAMETER_MODIFIER); - SurfaceVolumeData sfvd{*volume_tr, is_outside, std::move(sources)}; + SurfaceVolumeData sfvd{*volume_tr, std::move(sources)}; CreateSurfaceVolumeData surface_data{std::move(sfvd), std::move(data), volume_type, object.id(), gizmo}; job = std::make_unique(std::move(surface_data)); } @@ -1667,4 +1591,5 @@ bool start_create_volume_on_surface_job(CreateVolumeParams &input, DataBasePtr d void create_message(const std::string &message) { show_error(nullptr, message.c_str()); } + } // namespace diff --git a/src/slic3r/GUI/Jobs/EmbossJob.hpp b/src/slic3r/GUI/Jobs/EmbossJob.hpp index b25ccb25f5..1d5b2e65c2 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.hpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.hpp @@ -4,14 +4,14 @@ #include #include #include -#include "libslic3r/Emboss.hpp" -#include "libslic3r/EmbossShape.hpp" +#include +#include // ExPolygonsWithIds #include "libslic3r/Point.hpp" // Transform3d #include "libslic3r/ObjectID.hpp" -#include "slic3r/GUI/Jobs/EmbossJob.hpp" // Emboss::DataBase #include "slic3r/GUI/Camera.hpp" #include "slic3r/GUI/TextLines.hpp" + #include "Job.hpp" // forward declarations @@ -36,31 +36,44 @@ namespace Slic3r::GUI::Emboss { class DataBase { public: - DataBase(const std::string& volume_name, std::shared_ptr> cancel) : volume_name(volume_name), cancel(std::move(cancel)) {} + DataBase(const std::string& volume_name, std::shared_ptr> cancel) + : volume_name(volume_name), cancel(std::move(cancel)) {} DataBase(const std::string& volume_name, std::shared_ptr> cancel, EmbossShape&& shape) : volume_name(volume_name), cancel(std::move(cancel)), shape(std::move(shape)){} DataBase(DataBase &&) = default; virtual ~DataBase() = default; - // Define projection move - // True (raised) .. move outside from surface - // False (engraved).. move into object - bool is_outside; - - // flag that job is canceled - // for time after process. - std::shared_ptr> cancel; - - // Define per letter projection on one text line - // [optional] It is not used when empty - Slic3r::Emboss::TextLines text_lines; - /// /// Create shape /// e.g. Text extract glyphs from font /// Not 'const' function because it could modify shape /// virtual EmbossShape& create_shape() { return shape; }; + + /// + /// Write data how to reconstruct shape to volume + /// + /// Data object for store emboss params + virtual void write(ModelVolume &volume) const; + + // Define projection move + // True (raised) .. move outside from surface + // False (engraved).. move into object + bool is_outside; + + // Define per letter projection on one text line + // [optional] It is not used when empty + Slic3r::Emboss::TextLines text_lines; + + // new volume name + std::string volume_name; + + // flag that job is canceled + // for time after process. + std::shared_ptr> cancel; + + // shape to emboss + EmbossShape shape; }; /// @@ -78,22 +91,6 @@ struct DataCreateVolume : public DataBase // new created volume transformation Transform3d trmat; -}; - /// - /// Write data how to reconstruct shape to volume - /// - /// Data object for store emboss params - virtual void write(ModelVolume &volume) const; - - // new volume name - std::string volume_name; - - // flag that job is canceled - // for time after process. - std::shared_ptr> cancel; - - // shape to emboss - EmbossShape shape; }; using DataBasePtr = std::unique_ptr; diff --git a/src/slic3r/GUI/TextLines.cpp b/src/slic3r/GUI/TextLines.cpp index 55002fcf63..9a6512d140 100644 --- a/src/slic3r/GUI/TextLines.cpp +++ b/src/slic3r/GUI/TextLines.cpp @@ -340,6 +340,6 @@ void TextLinesModel::render(const Transform3d &text_world) double TextLinesModel::calc_line_height(const Slic3r::Emboss::FontFile &ff, const FontProp &fp) { int line_height = Emboss::get_line_height(ff, fp); // In shape size - double scale = Emboss::get_shape_scale(fp, ff); + double scale = Emboss::get_text_shape_scale(fp, ff); return line_height * scale; } diff --git a/tests/libslic3r/test_emboss.cpp b/tests/libslic3r/test_emboss.cpp index cd287776e8..22566fe8ef 100644 --- a/tests/libslic3r/test_emboss.cpp +++ b/tests/libslic3r/test_emboss.cpp @@ -531,7 +531,7 @@ TEST_CASE("UndoRedo TextConfiguration serialization", "[Emboss]") TEST_CASE("UndoRedo EmbossShape serialization", "[Emboss]") { EmbossShape emboss; - emboss.shapes = {{{0, 0}, {10, 0}, {10, 10}, {0, 10}}, {{5, 5}, {6, 5}, {6, 6}, {5, 6}}}; + emboss.shapes_with_ids = {{0, {{{0, 0}, {10, 0}, {10, 10}, {0, 10}}, {{5, 5}, {6, 5}, {6, 6}, {5, 6}}}}}; emboss.scale = 2.; emboss.projection.depth = 5.; emboss.projection.use_surface = true; @@ -551,7 +551,7 @@ TEST_CASE("UndoRedo EmbossShape serialization", "[Emboss]") cereal::BinaryInputArchive iarchive(ss); // Create an input archive iarchive(emboss_loaded); } - CHECK(emboss.shapes == emboss_loaded.shapes); + CHECK(emboss.shapes_with_ids.front().expoly == emboss_loaded.shapes_with_ids.front().expoly); CHECK(emboss.scale == emboss_loaded.scale); CHECK(emboss.projection.depth == emboss_loaded.projection.depth); CHECK(emboss.projection.use_surface == emboss_loaded.projection.use_surface);