From 5869f86d975c9d0f6c73153415d6aebb2bb2fee4 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Tue, 4 Jan 2022 13:21:31 +0100 Subject: [PATCH] Initial shape for emboss is not cached any more --- src/libslic3r/Emboss.cpp | 51 ++++++++++ src/libslic3r/Emboss.hpp | 10 ++ src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 123 +++++++++--------------- src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp | 30 +++++- 4 files changed, 133 insertions(+), 81 deletions(-) diff --git a/src/libslic3r/Emboss.cpp b/src/libslic3r/Emboss.cpp index 1b510921b..3e88a7036 100644 --- a/src/libslic3r/Emboss.cpp +++ b/src/libslic3r/Emboss.cpp @@ -642,3 +642,54 @@ std::pair Emboss::ProjectZ::project(const Point &p) const back.z() = m_depth; return std::make_pair(front, back); } + +Transform3d Emboss::create_transformation_onto_surface(const Vec3f &position, + const Vec3f &normal, + float up_limit) +{ + // up and emboss direction for generated model + Vec3d text_up_dir = Vec3d::UnitY(); + Vec3d text_emboss_dir = Vec3d::UnitZ(); + + // wanted up direction of result + Vec3d wanted_up_side = Vec3d::UnitZ(); + if (std::fabs(normal.z()) > up_limit) wanted_up_side = Vec3d::UnitY(); + + Vec3d wanted_emboss_dir = normal.cast(); + // after cast from float it needs to be normalized again + wanted_emboss_dir.normalize(); + + // create perpendicular unit vector to surface triangle normal vector + // lay on surface of triangle and define up vector for text + Vec3d wanted_up_dir = wanted_emboss_dir + .cross(wanted_up_side) + .cross(wanted_emboss_dir); + // normal3d is NOT perpendicular to normal_up_dir + wanted_up_dir.normalize(); + + // perpendicular to emboss vector of text and normal + Vec3d axis_view = text_emboss_dir.cross(wanted_emboss_dir); + double angle_view = std::acos(text_emboss_dir.dot(wanted_emboss_dir)); // in rad + axis_view.normalize(); + + Eigen::AngleAxis view_rot(angle_view, axis_view); + Vec3d wanterd_up_rotated = view_rot.matrix().inverse() * wanted_up_dir; + wanterd_up_rotated.normalize(); + double angle_up = std::acos(text_up_dir.dot(wanterd_up_rotated)); + + // text_view and text_view2 should have same direction + Vec3d text_view2 = text_up_dir.cross(wanterd_up_rotated); + Vec3d diff_view = text_emboss_dir - text_view2; + if (std::fabs(diff_view.x()) > 1. || + std::fabs(diff_view.y()) > 1. || + std::fabs(diff_view.z()) > 1.) // oposit direction + angle_up *= -1.; + + Eigen::AngleAxis up_rot(angle_up, text_emboss_dir); + + Transform3d transform = Transform3d::Identity(); + transform.translate(position.cast()); + transform.rotate(view_rot); + transform.rotate(up_rot); + return transform; +} diff --git a/src/libslic3r/Emboss.hpp b/src/libslic3r/Emboss.hpp index 17ec67574..9c63210c6 100644 --- a/src/libslic3r/Emboss.hpp +++ b/src/libslic3r/Emboss.hpp @@ -128,6 +128,16 @@ public: /// Define transformation from 2d to 3d(orientation, position, scale, ...) /// Projected shape into space static indexed_triangle_set polygons2model(const ExPolygons &shape2d, const IProject& projection); + + /// + /// Create transformation for emboss text object to lay on surface point + /// + /// Position of surface point + /// Normal of surface point + /// Is compared with normal.z to suggest up direction + /// Transformation onto surface point + static Transform3d create_transformation_onto_surface( + const Vec3f &position, const Vec3f &normal, float up_limit = 0.9f); class ProjectZ : public IProject { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index c9681bcad..ab5230e3d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -110,16 +110,19 @@ static void draw_fine_position(const Selection &selection) void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mouse_pos) { + assert(volume_type == ModelVolumeType::MODEL_PART || + volume_type == ModelVolumeType::NEGATIVE_VOLUME || + volume_type == ModelVolumeType::PARAMETER_MODIFIER); + if (!m_is_initialized) initialize(); const Selection &selection = m_parent.get_selection(); if(selection.is_empty()) return; set_default_configuration(); - TriangleMesh tm = m_default_mesh; // copy // By position of cursor create transformation to put text on surface of model Transform3d transformation = Transform3d::Identity(); - + // TODO: calculate X,Y offset position for lay on platter by mouse position CommonGizmosDataObjects::Raycaster *raycaster = m_c->raycaster(); if (raycaster == nullptr) return; @@ -141,9 +144,9 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mous raycasters_tr.emplace_back(instance_trafo * mv->get_matrix()); std::optional tr = transform_on_surface(mouse_pos, raycasters, raycasters_tr); - if (tr.has_value()) transformation = *tr; + if (tr.has_value()) transformation = *tr; - create_emboss_volume(std::move(tm), transformation, create_volume_name(), + create_emboss_volume(create_mesh(), transformation, create_volume_name(), create_configuration(), volume_type, selection.get_object_idx()); } @@ -211,7 +214,7 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) } Transform3d object_trmat = m_raycast_manager.get_transformation(hit->tr_key); - Transform3d trmat = get_emboss_transformation(hit->position, hit->normal); + Transform3d trmat = Emboss::create_transformation_onto_surface(hit->position, hit->normal); if (mouse_event.Dragging()) { // hide common dragging of object m_parent.toggle_model_objects_visibility(false, m_volume->get_object(), gl_volume->instance_idx(), m_volume); @@ -367,8 +370,7 @@ void GLGizmoEmboss::on_set_state() // When add Text on empty plate, Create new object with volume if (create_new_object) { set_default_configuration(); - TriangleMesh tm = m_default_mesh; // copy - create_emboss_object(std::move(tm), create_volume_name(), create_configuration()); + create_emboss_object(create_mesh(), create_volume_name(), create_configuration()); // gizmo will open when successfuly create new object GLGizmoBase::m_state = GLGizmoBase::Off; @@ -449,7 +451,6 @@ void GLGizmoEmboss::initialize() assert(success); load_font_list(); - // try to load valid font m_font_selected = 0; bool is_font_loaded = load_font(); @@ -458,28 +459,7 @@ void GLGizmoEmboss::initialize() m_font_list.erase(m_font_list.begin()); is_font_loaded = load_font(); } - set_default_configuration(); - - // create default mesh to faster add new volume - // solve state when no font loaded - if (is_font_loaded) { - // create default - ExPolygons shapes = Emboss::text2shapes(*m_font, m_text.c_str(), m_font_prop); - float scale = m_font_prop.size_in_mm / m_font->ascent; - float depth = m_font_prop.emboss / scale; - auto projectZ = std::make_unique(depth); - Emboss::ProjectScale project(std::move(projectZ), scale); - m_default_mesh = TriangleMesh(Emboss::polygons2model(shapes, project)); - } else { - // When cant load any font use default object loaded from file - std::string path = Slic3r::resources_dir() + - "/data/embossed_text.stl"; - if (!load_obj(path.c_str(), &m_default_mesh)) { - // when can't load mesh use cube - m_default_mesh = TriangleMesh(its_make_cube(36., 4., 2.5)); - } - } } FontList GLGizmoEmboss::create_default_font_list() { @@ -497,6 +477,41 @@ void GLGizmoEmboss::set_default_configuration() load_font(); // reload actual font - because of font size } +Slic3r::TriangleMesh GLGizmoEmboss::create_default_mesh() +{ + // When cant load any font use default object loaded from file + std::string path = Slic3r::resources_dir() + "/data/embossed_text.stl"; + TriangleMesh triangle_mesh; + if (!load_obj(path.c_str(), &triangle_mesh)) { + // when can't load mesh use cube + return TriangleMesh(its_make_cube(36., 4., 2.5)); + } + return triangle_mesh; +} + +Slic3r::TriangleMesh GLGizmoEmboss::create_mesh() +{ + // It is neccessary to create some shape + // Emboss text window is opened by creation new embosstext object + if (m_font == nullptr) return create_default_mesh(); + + TriangleMesh result = create_mesh(m_text.c_str(), *m_font, m_font_prop); + if (result.its.empty()) return create_default_mesh(); + return result; +} + +Slic3r::TriangleMesh GLGizmoEmboss::create_mesh(const char * text, + Emboss::Font &font, + const FontProp& font_prop) +{ + ExPolygons shapes = Emboss::text2shapes(font, text, font_prop); + float scale = font_prop.size_in_mm / font.ascent; + float depth = font_prop.emboss / scale; + auto projectZ = std::make_unique(depth); + Emboss::ProjectScale project(std::move(projectZ), scale); + return TriangleMesh(Emboss::polygons2model(shapes, project)); +} + #include "imgui/imgui_internal.h" // to unfocus input --> ClearActiveID void GLGizmoEmboss::check_selection() { @@ -618,9 +633,8 @@ void GLGizmoEmboss::draw_window() if (ImGui::Button(_u8L("Generate preview").c_str())) { const Selection &s = m_parent.get_selection(); auto selected_indices = s.get_instance_idxs(); - TriangleMesh mesh = m_default_mesh; // copy if (selected_indices.empty()) { - create_emboss_object(std::move(mesh), create_volume_name(), create_configuration()); + create_emboss_object(create_mesh(), create_volume_name(), create_configuration()); } else { create_volume(ModelVolumeType::MODEL_PART); } @@ -629,51 +643,6 @@ void GLGizmoEmboss::draw_window() m_imgui->disabled_end(); } -Transform3d GLGizmoEmboss::get_emboss_transformation(const Vec3f &position, - const Vec3f &emboss_dir) -{ - // up and emboss direction for generated model - Vec3d text_up_dir = Vec3d::UnitY(); - Vec3d text_emboss_dir = Vec3d::UnitZ(); - - // wanted up direction of result - Vec3d wanted_up_side = Vec3d::UnitZ(); - if (std::fabs(emboss_dir.z()) > 0.9) wanted_up_side = Vec3d::UnitY(); - - Vec3d wanted_emboss_dir = emboss_dir.cast(); - wanted_emboss_dir.normalize(); // after cast from float it needs to be normalized again - - // create perpendicular unit vector to surface triangle normal vector - // lay on surface of triangle and define up vector for text - Vec3d wanted_up_dir = wanted_emboss_dir.cross(wanted_up_side).cross(wanted_emboss_dir); - wanted_up_dir.normalize(); // normal3d is NOT perpendicular to normal_up_dir - - // perpendicular to emboss vector of text and normal - Vec3d axis_view = text_emboss_dir.cross(wanted_emboss_dir); - double angle_view = std::acos(text_emboss_dir.dot(wanted_emboss_dir)); // in rad - axis_view.normalize(); - - Eigen::AngleAxis view_rot(angle_view, axis_view); - Vec3d wanterd_up_rotated = view_rot.matrix().inverse() * wanted_up_dir; - wanterd_up_rotated.normalize(); - double angle_up = std::acos(text_up_dir.dot(wanterd_up_rotated)); - - // text_view and text_view2 should have same direction - Vec3d text_view2 = text_up_dir.cross(wanterd_up_rotated); - Vec3d diff_view = text_emboss_dir - text_view2; - if (std::fabs(diff_view.x()) > 1. || std::fabs(diff_view.y()) > 1. || - std::fabs(diff_view.z()) > 1.) // oposit direction - angle_up *= -1.; - - Eigen::AngleAxis up_rot(angle_up, text_emboss_dir); - - Transform3d transform = Transform3d::Identity(); - transform.translate(position.cast()); - transform.rotate(view_rot); - transform.rotate(up_rot); - return transform; -} - std::optional GLGizmoEmboss::transform_on_surface( const Vec2d &mouse_pos, const std::vector &raycasters, @@ -712,7 +681,7 @@ std::optional GLGizmoEmboss::transform_on_surface( // check exist hit if (!closest.has_value()) return {}; - return get_emboss_transformation(closest->position, closest->normal); + return Emboss::create_transformation_onto_surface(closest->position, closest->normal); } void GLGizmoEmboss::draw_font_list() diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index 3b72f09d1..5b1430f90 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp @@ -36,7 +36,17 @@ class GLGizmoEmboss : public GLGizmoBase public: GLGizmoEmboss(GLCanvas3D& parent); + /// + /// Create new embossed text volume by type on position of mouse + /// + /// Object part / Negative volume / Modifier + /// Define position of new volume void create_volume(ModelVolumeType volume_type, const Vec2d &mouse_pos = Vec2d(-1,-1)); + + /// + /// Move window for edit emboss text near to embossed object + /// NOTE: embossed object must be selected + /// void set_fine_position(); /// @@ -67,6 +77,21 @@ private: void initialize(); static FontList create_default_font_list(); void set_default_configuration(); + TriangleMesh create_default_mesh(); + TriangleMesh create_mesh(); + + /// + /// Create mesh from text + /// + /// Text to convert on mesh + /// Define shape of characters. + /// NOTE: Can't be const cache glyphs + /// Property of font + /// Triangle mesh model + static TriangleMesh create_mesh(const char * text, + Emboss::Font & font, + const FontProp &font_prop); + void check_selection(); // more general function --> move to select ModelVolume *get_selected_volume(); @@ -79,7 +104,7 @@ private: void draw_font_list(); void draw_text_input(); void draw_advanced(); - + // process mouse event bool on_mouse_for_rotation(const wxMouseEvent &mouse_event); bool on_mouse_for_translate(const wxMouseEvent &mouse_event); @@ -105,8 +130,6 @@ private: std::string create_volume_name(); - static Transform3d get_emboss_transformation(const Vec3f &position, - const Vec3f &emboss_dir); std::optional transform_on_surface(const Vec2d &mouse_pos, const std::vector &raycasters, const std::vector & raycasters_tr @@ -151,7 +174,6 @@ private: std::shared_ptr m_font; std::string m_text; FontProp m_font_prop; - TriangleMesh m_default_mesh; // when add new text this shape is used // actual volume ModelVolume *m_volume;