diff --git a/src/libslic3r/Emboss.cpp b/src/libslic3r/Emboss.cpp index f660a444cf..9f9d182d98 100644 --- a/src/libslic3r/Emboss.cpp +++ b/src/libslic3r/Emboss.cpp @@ -1918,6 +1918,73 @@ PolygonPoints Emboss::sample_slice(const TextLine &slice, const BoundingBoxes &b return samples; } +namespace { +Point get_align_offset(FontProp::Align type, const BoundingBox &bb) +{ + Point offset; + switch (type) { + // case Slic3r::FontProp::Align::start_first_line: break; + case Slic3r::FontProp::Align::center_left: + case Slic3r::FontProp::Align::center_right: + case Slic3r::FontProp::Align::center_center: offset.y() = bb.center().y(); break; + case Slic3r::FontProp::Align::top_left: + case Slic3r::FontProp::Align::top_right: + case Slic3r::FontProp::Align::top_center: offset.y() = bb.min.y(); break; + case Slic3r::FontProp::Align::bottom_left: + case Slic3r::FontProp::Align::bottom_right: + case Slic3r::FontProp::Align::bottom_center: offset.y() = bb.max.y(); break; + default: break; + } + + switch (type) { + // case Slic3r::FontProp::Align::start_first_line: break; + case Slic3r::FontProp::Align::center_center: + case Slic3r::FontProp::Align::top_center: + case Slic3r::FontProp::Align::bottom_center: offset.x() = bb.center().x(); break; + case Slic3r::FontProp::Align::center_left: + case Slic3r::FontProp::Align::top_left: + case Slic3r::FontProp::Align::bottom_left: offset.x() = bb.min.x(); break; + case Slic3r::FontProp::Align::center_right: + case Slic3r::FontProp::Align::top_right: + case Slic3r::FontProp::Align::bottom_right: offset.x() = bb.max.x(); break; + default: break; + } + return -offset; +} +} // namespace + +void Emboss::align_shape(FontProp::Align type, ExPolygons &shape, BoundingBox *bb) +{ + if (type == FontProp::Align::start_first_line) + return; // no alignement + + BoundingBox shape_bb_data; + BoundingBox &shape_bb = (bb != nullptr) ? *bb : shape_bb_data; + if (!shape_bb.defined) + shape_bb = get_extents(shape); + + Point offset = get_align_offset(type, shape_bb); + for (ExPolygon &s : shape) + s.translate(offset); +} + +void Emboss::align_shape(FontProp::Align type, std::vector &shapes, BoundingBox *bb) +{ + if (type == FontProp::Align::start_first_line) + return; // no alignement + + BoundingBox shape_bb_data; + BoundingBox &shape_bb = (bb != nullptr) ? *bb : shape_bb_data; + if (!shape_bb.defined) + for (const ExPolygons& shape: shapes) + shape_bb.merge(get_extents(shape)); + + Point offset = get_align_offset(type, shape_bb); + for (ExPolygons &shape : shapes) + for (ExPolygon &s : shape) + s.translate(offset); +} + #ifdef REMOVE_SPIKES #include void priv::remove_spikes(Polygon &polygon, const SpikeDesc &spike_desc) diff --git a/src/libslic3r/Emboss.hpp b/src/libslic3r/Emboss.hpp index 0779aee080..db864df9b4 100644 --- a/src/libslic3r/Emboss.hpp +++ b/src/libslic3r/Emboss.hpp @@ -442,6 +442,15 @@ namespace Emboss double calculate_angle(int32_t distance, PolygonPoint polygon_point, const Polygon &polygon); std::vector calculate_angles(int32_t distance, const PolygonPoints& polygon_points, const Polygon &polygon); + /// + /// Align expolygons by type + /// + /// Type of alignement + /// shapes to align + /// extents of shape + void align_shape(FontProp::Align type, ExPolygons& shape, BoundingBox* bb = nullptr); + void align_shape(FontProp::Align type, std::vector &shape, BoundingBox *bb = nullptr); + } // namespace Emboss } // namespace Slic3r #endif // slic3r_Emboss_hpp_ diff --git a/src/libslic3r/TextConfiguration.hpp b/src/libslic3r/TextConfiguration.hpp index 14a9645a07..bdc9371a3d 100644 --- a/src/libslic3r/TextConfiguration.hpp +++ b/src/libslic3r/TextConfiguration.hpp @@ -63,20 +63,21 @@ struct FontProp // Distiguish projection per glyph bool per_glyph; - //enum class Align { - // left, - // right, - // center, - // top_left, - // top_right, - // top_center, - // bottom_left, - // bottom_right, - // bottom_center - //}; - //// change pivot of text - //// When not set, center is used and is not stored - //std::optional align; + enum class Align { + start_first_line, // it depends on position of zero for first letter + center_left, + center_right, + center_center, + top_left, + top_right, + top_center, + bottom_left, + bottom_right, + bottom_center + }; + // change pivot of text + // When not set, center is used and is not stored + Align align = Align::center_center; ////// // Duplicit data to wxFontDescriptor diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index b14e84baf7..e2d22ae60e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -1059,6 +1059,9 @@ void GLGizmoEmboss::init_text_lines(){ if (ff_ptr == nullptr) return; + if (m_volume->is_the_only_one_part()) + return; + const FontProp& fp = m_style_manager.get_font_prop(); const FontFile &ff = *ff_ptr; @@ -3226,6 +3229,32 @@ void GLGizmoEmboss::draw_advanced() } } else if (!*per_glyph && m_text_lines.is_init()) m_text_lines.reset(); + + ImGui::SameLine(); + ImGui::SetNextItemWidth(100); + if (ImGui::SliderFloat("##base_line_y_offset", &m_text_lines.offset, -10.f, 10.f, "%f mm")) { + init_text_lines(); + } else if (ImGui::IsItemHovered()) + ImGui::SetTooltip("%s", _u8L("Move base line (up/down) for allign letters").c_str()); + + // order must match align enum + const char* align_names[] = { + "start_first_line", + "center_left", + "center_right", + "center_center", + "top_left", + "top_right", + "top_center", + "bottom_left", + "bottom_right", + "bottom_center" + }; + int selected_align = static_cast(font_prop.align); + if (ImGui::Combo("align", &selected_align, align_names, IM_ARRAYSIZE(align_names))) { + font_prop.align = static_cast(selected_align); + } + if (exist_change) { m_style_manager.clear_glyphs_cache(); diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp index 256dbca68b..d31c7dfd28 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.cpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp @@ -427,7 +427,12 @@ ExPolygons priv::create_shape(DataBase &input, Fnc was_canceled) { if (!font.has_value()) return {}; - return text2shapes(font, text, prop, was_canceled); + ExPolygons shapes = text2shapes(font, text, prop, was_canceled); + if (shapes.empty()) + return {}; + + align_shape(input.text_configuration.style.prop.align, shapes); + return shapes; } #define STORE_SAMPLING @@ -563,15 +568,16 @@ TriangleMesh priv::try_create_mesh(DataBase &input, Fnc was_canceled) ExPolygons shapes = priv::create_shape(input, was_canceled); if (shapes.empty()) return {}; - if (was_canceled()) 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; - auto projectZ = std::make_unique(depth); - ProjectScale project(std::move(projectZ), scale); + auto projectZ = std::make_unique(depth); + //auto scaled = std::make_unique(std::move(projectZ), scale); + ProjectTransform project(std::move(projectZ), Eigen::Translation(0., 0., -prop.emboss / 2) * Eigen::Scaling(scale)); if (was_canceled()) return {}; return TriangleMesh(polygons2model(shapes, project)); } @@ -867,12 +873,7 @@ TriangleMesh priv::cut_surface(DataBase& input1, const SurfaceVolumeData& input2 if (was_canceled()) return {}; - // Define alignment of text - left, right, center, top bottom, .... - BoundingBox bb = get_extents(shapes); - Point projection_center = bb.center(); - for (ExPolygon &shape : shapes) shape.translate(-projection_center); - bb.translate(-projection_center); - + BoundingBox bb = get_extents(shapes); const FontFile &ff = *input1.font_file.font_file; const FontProp &fp = input1.text_configuration.style.prop; double shape_scale = get_shape_scale(fp, ff); diff --git a/src/slic3r/GUI/TextLines.cpp b/src/slic3r/GUI/TextLines.cpp index 0a4652f942..50d6109c6b 100644 --- a/src/slic3r/GUI/TextLines.cpp +++ b/src/slic3r/GUI/TextLines.cpp @@ -223,7 +223,7 @@ indexed_triangle_set create_its(const TextLines &lines) if (polygon.empty()) continue; indexed_triangle_set line_its = its_create_belt(polygon, model_half_width); //indexed_triangle_set line_its = its_create_torus(polygon, model_half_width); - auto transl = Eigen::Translation3d(0., -line.y, 0.); + auto transl = Eigen::Translation3d(0., line.y, 0.); Transform3d tr = transl * get_rotation(); its_transform(line_its, tr); its_merge(its, line_its); @@ -251,7 +251,7 @@ GLModel::Geometry create_geometry(const TextLines &lines) } } // namespace -void TextLinesModel::init(const Selection &selection, double line_height, double line_offset) +void TextLinesModel::init(const Selection &selection, double line_height) { const GLVolume *gl_volume_ptr = selection.get_first_volume(); if (gl_volume_ptr == nullptr) @@ -276,7 +276,7 @@ void TextLinesModel::init(const Selection &selection, double line_height, double if (count_lines == 0) return; - double first_line_center = line_offset + (count_lines / 2) * line_height - ((count_lines % 2 == 0) ? line_height / 2. : 0.); + double first_line_center = offset + (count_lines / 2) * line_height - ((count_lines % 2 == 0) ? line_height / 2. : 0.); 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); diff --git a/src/slic3r/GUI/TextLines.hpp b/src/slic3r/GUI/TextLines.hpp index a4ed36f3e8..741577c143 100644 --- a/src/slic3r/GUI/TextLines.hpp +++ b/src/slic3r/GUI/TextLines.hpp @@ -12,13 +12,15 @@ class Selection; class TextLinesModel { public: + // line offset in y direction (up/down) + float offset = 0; /// /// Initialize model and lines /// /// Must be selected text volume /// Height of text line with spacing [in mm] /// Offset of base line from center [in mm] - void init(const Selection &selection, double line_height, double line_offset = 0.); + void init(const Selection &selection, double line_height); void render(const Transform3d &text_world); bool is_init() const { return m_model.is_initialized(); }