diff --git a/src/libslic3r/Emboss.cpp b/src/libslic3r/Emboss.cpp index 3a2bb6802e..5c584b3c76 100644 --- a/src/libslic3r/Emboss.cpp +++ b/src/libslic3r/Emboss.cpp @@ -19,6 +19,10 @@ #include "libslic3r/Line.hpp" #include "libslic3r/BoundingBox.hpp" +// Experimentaly suggested ration of font ascent by multiple fonts +// to get approx center of normal text line +const double ASCENT_CENTER = 1/3.; // 0.5 is above small letter + using namespace Slic3r; using namespace Emboss; using fontinfo_opt = std::optional; @@ -1207,17 +1211,21 @@ std::optional Emboss::letter2glyph(const FontFile &font, return priv::get_glyph(*font_info_opt, letter, flatness); } -int Emboss::get_line_height(const FontFile &font, const FontProp &prop) { +const FontFile::Info &Emboss::get_font_info(const FontFile &font, const FontProp &prop) +{ unsigned int font_index = prop.collection_number.value_or(0); assert(priv::is_valid(font, font_index)); - const FontFile::Info &info = font.infos[font_index]; + return font.infos[font_index]; +} + +int Emboss::get_line_height(const FontFile &font, const FontProp &prop) { + const FontFile::Info &info = get_font_info(font, prop); int line_height = info.ascent - info.descent + info.linegap; line_height += prop.line_gap.value_or(0); return static_cast(line_height / SHAPE_SCALE); } namespace { - ExPolygons letter2shapes( wchar_t letter, Point &cursor, FontFileWithCache &font_with_cache, const FontProp &font_prop, fontinfo_opt& font_info_cache) { @@ -1289,12 +1297,12 @@ namespace { /// /// Align shape against pivot /// -/// Horizontal and vertical alignment /// Shapes to align /// 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); +/// To detect end of lines - to be able horizontal center the line +/// Containe Horizontal and vertical alignment +/// Needed for scale and font size +void align_shape(std::vector &shapes, const std::wstring &text, const FontProp &prop, const FontFile &font); } std::vector Emboss::text2vshapes(FontFileWithCache &font_with_cache, const std::wstring& text, const FontProp &font_prop, const std::function& was_canceled){ @@ -1319,7 +1327,7 @@ std::vector Emboss::text2vshapes(FontFileWithCache &font_with_cache, result.emplace_back(letter2shapes(letter, cursor, font_with_cache, font_prop, font_info_cache)); } - align_shape(font_prop.align, result, text, get_line_height(font, font_prop)); + align_shape(result, text, font_prop, font); return result; } @@ -1453,8 +1461,7 @@ std::string Emboss::create_range_text(const std::string &text, double Emboss::get_shape_scale(const FontProp &fp, const FontFile &ff) { - size_t font_index = fp.collection_number.value_or(0); - const FontFile::Info &info = ff.infos[font_index]; + const FontFile::Info &info = get_font_info(ff, fp); double scale = fp.size_in_mm / (double) info.unit_per_em; // Shape is scaled for store point coordinate as integer return scale * SHAPE_SCALE; @@ -1929,20 +1936,22 @@ PolygonPoints Emboss::sample_slice(const TextLine &slice, const BoundingBoxes &b } namespace { -template T get_align_y_offset(FontProp::VerticalAlign align, unsigned count_lines, T line_height) +float get_align_y_offset(FontProp::VerticalAlign align, unsigned count_lines, const FontFile &ff, const FontProp &fp) { - if (count_lines == 0) - return 0; + assert(count_lines != 0); + int line_height = get_line_height(ff, fp); + int ascent = get_font_info(ff, fp).ascent / SHAPE_SCALE; + float line_center = static_cast(std::round(ascent * ASCENT_CENTER)); // direction of Y in 2d is from top to bottom // zero is on base line of first line switch (align) { - case FontProp::VerticalAlign::center: return ((count_lines - 1) / 2) * line_height + ((count_lines % 2 == 0) ? (line_height / 2) : 0); - case FontProp::VerticalAlign::bottom: return (count_lines - 1) * line_height; - case FontProp::VerticalAlign::top: // no change - default: break; + case FontProp::VerticalAlign::bottom: return line_height * (count_lines - 1); + case FontProp::VerticalAlign::top: return -ascent; + case FontProp::VerticalAlign::center: + default: + return -line_center + line_height * (count_lines - 1) / 2.; } - return 0; } int32_t get_align_x_offset(FontProp::HorizontalAlign align, const BoundingBox &shape_bb, const BoundingBox &line_bb) @@ -1956,11 +1965,10 @@ 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(std::vector &shapes, const std::wstring &text, const FontProp &prop, const FontFile &font) { - constexpr FontProp::Align no_change(FontProp::HorizontalAlign::left, FontProp::VerticalAlign::top); - if (type == no_change) - return; // no alignment + // Shapes have to match letters in text + assert(shapes.size() == text.length()); BoundingBox shape_bb; for (const ExPolygons& shape: shapes) @@ -1972,15 +1980,30 @@ void align_shape(FontProp::Align type, std::vector &shapes, const st line_bb.merge(get_extents(shapes[j])); return line_bb; }; + + int line_height = get_line_height(font, prop); + unsigned count_lines = get_count_lines(text); + int center_line = get_font_info(font, prop).ascent * ASCENT_CENTER; + int y_offset = get_align_y_offset(prop.align.second, count_lines, font, prop); + + // Speed up for left aligned text + if (prop.align.first == FontProp::HorizontalAlign::left){ + // already horizontaly aligned + for (ExPolygons shape : shapes) + for (ExPolygon &s : shape) + s.translate(Point(0, y_offset)); + return; + } + + // Align x line by line 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)); - assert(shapes.size() == text.length()); + get_align_x_offset(prop.align.first, shape_bb, get_line_bb(0)), + y_offset); for (size_t i = 0; i < shapes.size(); ++i) { wchar_t letter = text[i]; if (letter == '\n'){ - offset.x() = get_align_x_offset(type.first, shape_bb, get_line_bb(i+1)); + offset.x() = get_align_x_offset(prop.align.first, shape_bb, get_line_bb(i + 1)); continue; } ExPolygons &shape = shapes[i]; @@ -1990,8 +2013,10 @@ void align_shape(FontProp::Align type, std::vector &shapes, const st } } // namespace -double Emboss::get_align_y_offset(FontProp::VerticalAlign align, unsigned count_lines, double line_height){ - return ::get_align_y_offset(align, count_lines, line_height); +double Emboss::get_align_y_offset_in_mm(FontProp::VerticalAlign align, unsigned count_lines, const FontFile &ff, const FontProp &fp){ + float offset_in_font_point = get_align_y_offset(align, count_lines, ff, fp); + double scale = get_shape_scale(fp, ff); + return scale * offset_in_font_point; } #ifdef REMOVE_SPIKES diff --git a/src/libslic3r/Emboss.hpp b/src/libslic3r/Emboss.hpp index bef95735b1..b6cdcabc51 100644 --- a/src/libslic3r/Emboss.hpp +++ b/src/libslic3r/Emboss.hpp @@ -228,6 +228,14 @@ namespace Emboss /// Conversion to mm double get_shape_scale(const FontProp &fp, const FontFile &ff); + /// + /// getter of font info by collection defined in prop + /// + /// Contain infos about all fonts(collections) in file + /// Index of collection + /// Ascent, descent, line gap + const FontFile::Info &get_font_info(const FontFile &font, const FontProp &prop); + /// /// Read from font file and properties height of line with spacing /// @@ -239,12 +247,10 @@ namespace Emboss /// /// Calculate Vertical align /// - /// double for mm - /// type + /// Top | Center | Bottom /// - /// - /// In same unit as line height - double get_align_y_offset(FontProp::VerticalAlign align, unsigned count_lines, double line_height); + /// Return align Y offset in mm + double get_align_y_offset_in_mm(FontProp::VerticalAlign align, unsigned count_lines, const FontFile &ff, const FontProp &fp); /// /// Project spatial point diff --git a/src/libslic3r/TextConfiguration.hpp b/src/libslic3r/TextConfiguration.hpp index fc5d431df1..1eaae55770 100644 --- a/src/libslic3r/TextConfiguration.hpp +++ b/src/libslic3r/TextConfiguration.hpp @@ -69,7 +69,7 @@ struct FontProp using Align = std::pair; // change pivot of text // When not set, center is used and is not stored - Align align = Align(HorizontalAlign::center, VerticalAlign::top); + Align align = Align(HorizontalAlign::center, VerticalAlign::center); ////// // Duplicit data to wxFontDescriptor diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index e1cdd0c728..8e79a59ebe 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -1093,41 +1093,7 @@ EmbossStyles GLGizmoEmboss::create_default_styles() return styles; } -namespace { - -bool get_line_height_offset(/* const*/ StyleManager &style_manager, double &line_height_mm, double &line_offset_mm) -{ - assert(style_manager.is_active_font()); - if (!style_manager.is_active_font()) - return false; - const auto &ffc = style_manager.get_font_file_with_cache(); - assert(ffc.has_value()); - if (!ffc.has_value()) - return false; - const auto &ff_ptr = ffc.font_file; - assert(ff_ptr != nullptr); - if (ff_ptr == nullptr) - return false; - const FontProp &fp = style_manager.get_font_prop(); - const FontFile &ff = *ff_ptr; - - 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; - line_height_mm = line_height_shape_size * scale; - - if (line_height_mm < 0) - return false; - - // fix for bad filled ascent in font file - if (line_offset_mm <= 0) - line_offset_mm = line_height_mm / 3; - - return true; -} - +namespace{ void init_text_lines(TextLinesModel &text_lines, const Selection& selection, /* const*/ StyleManager &style_manager, unsigned count_lines) { const GLVolume *gl_volume_ptr = selection.get_first_volume(); @@ -1178,12 +1144,7 @@ void init_text_lines(TextLinesModel &text_lines, const Selection& selection, /* Transform3d mv_trafo = gl_volume.get_volume_transformation().get_matrix(); if (tc.fix_3mf_tr.has_value()) mv_trafo = mv_trafo * (tc.fix_3mf_tr->inverse()); - FontProp::VerticalAlign align = style_manager.get_font_prop().align.second; - double line_height_mm, line_offset_mm; - if (!get_line_height_offset(style_manager, line_height_mm, line_offset_mm)) - return; - - text_lines.init(mv_trafo, volumes, align, line_height_mm, line_offset_mm, count_lines); + text_lines.init(mv_trafo, volumes, style_manager, count_lines); } void init_new_text_line(TextLinesModel &text_lines, const Transform3d& new_text_tr, const ModelObject& mo, /* const*/ StyleManager &style_manager) @@ -1197,13 +1158,8 @@ void init_new_text_line(TextLinesModel &text_lines, const Transform3d& new_text_ continue; volumes.push_back(volume); } - - FontProp::VerticalAlign align = style_manager.get_font_prop().align.second; - double line_height_mm, line_offset_mm; - if (!get_line_height_offset(style_manager, line_height_mm, line_offset_mm)) - return; unsigned count_lines = 1; - text_lines.init(new_text_tr, volumes, align, line_height_mm, line_offset_mm, count_lines); + text_lines.init(new_text_tr, volumes, style_manager, count_lines); } } @@ -3129,10 +3085,7 @@ void GLGizmoEmboss::draw_advanced() } FontProp &font_prop = m_style_manager.get_font_prop(); - const auto &cn = m_style_manager.get_font_prop().collection_number; - unsigned int font_index = (cn.has_value()) ? *cn : 0; - const auto &font_info = ff.font_file->infos[font_index]; - + const FontFile::Info &font_info = get_font_info(*ff.font_file, font_prop); #ifdef SHOW_FONT_FILE_PROPERTY ImGui::SameLine(); int cache_size = ff.has_value()? (int)ff.cache->size() : 0; diff --git a/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp b/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp index 88babc4645..4bafd96cde 100644 --- a/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp +++ b/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp @@ -47,10 +47,8 @@ void CreateFontStyleImagesJob::process(Ctl &ctl) for (ExPolygon &shape : shapes) shape.translate(-bounding_box.min); // calculate conversion from FontPoint to screen pixels by size of font - const auto &cn = item.prop.collection_number; - unsigned int font_index = (cn.has_value()) ? *cn : 0; - double unit_per_em = item.font.font_file->infos[font_index].unit_per_em; - double scale = item.prop.size_in_mm / unit_per_em * SHAPE_SCALE * m_input.ppm; + const FontFile::Info &info = get_font_info(*item.font.font_file, item.prop); + double scale = item.prop.size_in_mm / info.unit_per_em * SHAPE_SCALE * m_input.ppm; scales[index] = scale; //double scale = font_prop.size_in_mm * SCALING_FACTOR; diff --git a/src/slic3r/GUI/TextLines.cpp b/src/slic3r/GUI/TextLines.cpp index d1a014d609..62f4bc4918 100644 --- a/src/slic3r/GUI/TextLines.cpp +++ b/src/slic3r/GUI/TextLines.cpp @@ -249,22 +249,60 @@ GLModel::Geometry create_geometry(const TextLines &lines) geometry.add_triangle(t[0], t[1], t[2]); return geometry; } + +bool get_line_height_offset(const FontProp &fp, const FontFile &ff, double &line_height_mm, double &line_offset_mm) +{ + double third_ascent_shape_size = get_font_info(ff, fp).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; + line_height_mm = line_height_shape_size * scale; + + if (line_height_mm < 0) + return false; + + // fix for bad filled ascent in font file + if (line_offset_mm <= 0) + line_offset_mm = line_height_mm / 3; + + return true; +} + } // namespace void TextLinesModel::init(const Transform3d &text_tr, const ModelVolumePtrs &volumes_to_slice, - FontProp::VerticalAlign align, - double line_height, - double offset, + /*const*/ Emboss::StyleManager &style_manager, unsigned count_lines) { + assert(style_manager.is_active_font()); + if (!style_manager.is_active_font()) + return; + const auto &ffc = style_manager.get_font_file_with_cache(); + assert(ffc.has_value()); + if (!ffc.has_value()) + return; + const auto &ff_ptr = ffc.font_file; + assert(ff_ptr != nullptr); + if (ff_ptr == nullptr) + return; + const FontFile &ff = *ff_ptr; + const FontProp &fp = style_manager.get_font_prop(); + + FontProp::VerticalAlign align = fp.align.second; + + double line_height_mm, line_offset_mm; + if (!get_line_height_offset(fp, ff, line_height_mm, line_offset_mm)) + return; + m_model.reset(); m_lines.clear(); - double first_line_center = offset + this->offset + get_align_y_offset(align, count_lines, line_height); + double first_line_center = offset + this->offset + get_align_y_offset_in_mm(align, count_lines, ff, fp); std::vector line_centers(count_lines); for (size_t i = 0; i < count_lines; ++i) - line_centers[i] = static_cast(first_line_center - i * line_height); + line_centers[i] = static_cast(first_line_center - i * line_height_mm); // contour transformation Transform3d c_trafo = text_tr * get_rotation(); @@ -357,7 +395,7 @@ 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); + int line_height = Slic3r::Emboss::get_line_height(ff, fp); // In shape size + double scale = Slic3r::Emboss::get_shape_scale(fp, ff); return line_height * scale; } diff --git a/src/slic3r/GUI/TextLines.hpp b/src/slic3r/GUI/TextLines.hpp index 2a5f8ca8fa..5d5378aa51 100644 --- a/src/slic3r/GUI/TextLines.hpp +++ b/src/slic3r/GUI/TextLines.hpp @@ -6,6 +6,7 @@ #include #include #include "slic3r/GUI/GLModel.hpp" +#include "slic3r/Utils/EmbossStyleManager.hpp" namespace Slic3r { class ModelVolume; @@ -24,11 +25,9 @@ public: /// /// Transformation of text volume inside object (aka inside of instance) /// Vector of volumes to be sliced - /// Vertical (Y) align of the text - /// Distance between lines [in mm] - /// Offset from baseline [in mm] - /// Count lines(slices over volumes) - void init(const Transform3d &text_tr, const ModelVolumePtrs& volumes_to_slice, FontProp::VerticalAlign align, double line_height, double offset, unsigned count_lines); + /// Contain Font file, size and align + /// Count lines of embossed text(for veritcal alignment) + void init(const Transform3d &text_tr, const ModelVolumePtrs &volumes_to_slice, /*const*/ Emboss::StyleManager &style_manager, unsigned count_lines); void render(const Transform3d &text_world); diff --git a/src/slic3r/Utils/EmbossStyleManager.cpp b/src/slic3r/Utils/EmbossStyleManager.cpp index 623c147176..e33484ddf7 100644 --- a/src/slic3r/Utils/EmbossStyleManager.cpp +++ b/src/slic3r/Utils/EmbossStyleManager.cpp @@ -449,12 +449,10 @@ float StyleManager::min_imgui_font_size = 18.f; float StyleManager::max_imgui_font_size = 60.f; float StyleManager::get_imgui_font_size(const FontProp &prop, const FontFile &file, double scale) { - const auto &cn = prop.collection_number; - unsigned int font_index = (cn.has_value()) ? *cn : 0; - const auto &font_info = file.infos[font_index]; + const FontFile::Info& info = get_font_info(file, prop); // coeficient for convert line height to font size - float c1 = (font_info.ascent - font_info.descent + font_info.linegap) / - (float) font_info.unit_per_em; + float c1 = (info.ascent - info.descent + info.linegap) / + (float) info.unit_per_em; // The point size is defined as 1/72 of the Anglo-Saxon inch (25.4 mm): // It is approximately 0.0139 inch or 352.8 um. @@ -490,17 +488,12 @@ ImFont *StyleManager::create_imgui_font(const std::string &text, double scale) ImFontConfig font_config; // TODO: start using merge mode //font_config.MergeMode = true; - - unsigned int font_index = font_prop.collection_number.value_or(0); - const auto &font_info = font_file.infos[font_index]; - if (font_prop.char_gap.has_value()) { - float coef = font_size / (double) font_info.unit_per_em; - font_config.GlyphExtraSpacing.x = coef * (*font_prop.char_gap); - } - if (font_prop.line_gap.has_value()) { - float coef = font_size / (double) font_info.unit_per_em; - font_config.GlyphExtraSpacing.y = coef * (*font_prop.line_gap); - } + int unit_per_em = get_font_info(font_file, font_prop).unit_per_em; + float coef = font_size / (double) unit_per_em; + if (font_prop.char_gap.has_value()) + font_config.GlyphExtraSpacing.x = coef * (*font_prop.char_gap); + if (font_prop.line_gap.has_value()) + font_config.GlyphExtraSpacing.y = coef * (*font_prop.line_gap); font_config.FontDataOwnedByAtlas = false;