From 1078fe55ec023a7ecdef3bab0f0bb879e9f38103 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Tue, 1 Feb 2022 18:31:27 +0100 Subject: [PATCH] Create text on second Part(volume) of object --- src/libslic3r/TextConfiguration.hpp | 9 +++ src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 98 ++++++++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp | 7 +- src/slic3r/GUI/Jobs/EmbossJob.cpp | 26 +++---- src/slic3r/GUI/Jobs/EmbossJob.hpp | 16 ++++ src/slic3r/Utils/RaycastManager.cpp | 41 ++++++++++- src/slic3r/Utils/RaycastManager.hpp | 6 +- 7 files changed, 151 insertions(+), 52 deletions(-) diff --git a/src/libslic3r/TextConfiguration.hpp b/src/libslic3r/TextConfiguration.hpp index 0e0a2d6e36..afc0bdca52 100644 --- a/src/libslic3r/TextConfiguration.hpp +++ b/src/libslic3r/TextConfiguration.hpp @@ -103,6 +103,15 @@ struct FontItem wx_mac_font_descr // path is font descriptor generated by wxWidgets on windows }; + bool operator==(const FontItem &other) const { + return + type == other.type && + prop == other.prop && + name == other.name && + path == other.path + ; + } + // undo / redo stack recovery template void serialize(Archive &ar) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 0e9a604b8d..66b2b2d6c5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -24,6 +24,7 @@ #include "libslic3r/AppConfig.hpp" // store/load font list #include "libslic3r/MapUtils.hpp" #include "libslic3r/Format/OBJ.hpp" // load obj file for default object +#include "libslic3r/BuildVolume.hpp" #include "imgui/imgui_stdlib.h" // using std::string for inputs #include "nanosvg/nanosvg.h" // load SVG file @@ -133,15 +134,28 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mous } std::optional object_idx; + + std::optional hit_vol_tr; const Selection &selection = m_parent.get_selection(); - if (!selection.is_empty()) object_idx = selection.get_object_idx(); - auto data = - std::make_unique(m_font_manager.get_font_file(), - create_configuration(), - create_volume_name(), volume_type, - screen_coor, object_idx, - &m_raycast_manager); - auto &worker = wxGetApp().plater()->get_ui_job_worker(); + if (!selection.is_empty()) { + object_idx = selection.get_object_idx(); + int hovered_id = m_parent.get_first_hover_volume_idx(); + if (hovered_id >= 0) { + GLVolume *gl_volume = m_parent.get_volumes().volumes[hovered_id]; + hit_vol_tr = gl_volume->get_instance_transformation().get_matrix(); + } + } + Plater* plater = wxGetApp().plater(); + const Camera &camera = plater->get_camera(); + auto data = std::make_unique( + m_font_manager.get_font_file(), + create_configuration(), + create_volume_name(), volume_type, screen_coor, object_idx, + hit_vol_tr, camera, + plater->build_volume().bed_shape(), + &m_raycast_manager); + + auto &worker = plater->get_ui_job_worker(); queue_job(worker, std::make_unique(std::move(data))); } @@ -206,14 +220,15 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) // initialize raycasters // IMPROVE: move to job, for big scene it slows down ModelObject *act_model_object = act_model_volume->get_object(); - m_raycast_manager.actualize({act_model_object}, &skip); + m_raycast_manager.actualize(act_model_object, &skip); return false; } // wxCoord == int --> wx/types.h Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY()); Vec2d mouse_pos = mouse_coord.cast(); - auto hit = m_raycast_manager.unproject(mouse_pos, &skip); + const Camera &camera = wxGetApp().plater()->get_camera(); + auto hit = m_raycast_manager.unproject(mouse_pos, camera, &skip); if (!hit.has_value()) { // there is no hit // show common translation of object @@ -325,7 +340,7 @@ void GLGizmoEmboss::on_render_for_picking() { void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit) { initialize(); - check_selection(); + check_selection(); // TODO: fix width - showing scroll in first draw of advanced. const ImVec2 &min_window_size = get_minimal_window_size(); @@ -480,6 +495,12 @@ void GLGizmoEmboss::initialize() cfg.max_style_image_width = cfg.max_font_name_width - 2 * style.FramePadding.x; + // initialize default font + FontList default_font_list = create_default_font_list(); + for (const FontItem &fi : default_font_list) { + assert(cfg.default_styles.find(fi.name) == cfg.default_styles.end()); + cfg.default_styles[fi.name] = fi; // copy + } m_gui_cfg.emplace(cfg); // TODO: What to do when icon was NOT loaded? Generate them? @@ -489,39 +510,28 @@ void GLGizmoEmboss::initialize() const AppConfig *app_cfg = wxGetApp().app_config; FontList font_list = load_font_list_from_app_config(app_cfg); m_font_manager.add_fonts(font_list); + // TODO: select last session sellected font index + if (!m_font_manager.load_first_valid_font()) { - FontList font_list = create_default_font_list(); - m_font_manager.add_fonts(font_list); + m_font_manager.add_fonts(default_font_list); // TODO: What to do when default fonts are not loadable? bool success = m_font_manager.load_first_valid_font(); assert(success); } set_default_text(); + select_stored_font_item(); } FontList GLGizmoEmboss::create_default_font_list() { // https://docs.wxwidgets.org/3.0/classwx_font.html // Predefined objects/pointers: wxNullFont, wxNORMAL_FONT, wxSMALL_FONT, wxITALIC_FONT, wxSWISS_FONT - - FontItem par_fi = WxFontUtils::get_font_item(*wxNORMAL_FONT, _u8L("Parallel to bed")); - - FontItem perp_fi = WxFontUtils::get_font_item(*wxNORMAL_FONT, _u8L("Perpendicular to bed")); - - FontItem fix_fi = WxFontUtils::get_font_item(*wxNORMAL_FONT, _u8L("Fixed size")); - - FontItem negative_fi = WxFontUtils::get_font_item(*wxNORMAL_FONT, _u8L("Negative")); - return { - par_fi, - perp_fi, - fix_fi, - negative_fi, - WxFontUtils::get_font_item(*wxNORMAL_FONT), // wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) - WxFontUtils::get_font_item(*wxSMALL_FONT), // A font using the wxFONTFAMILY_SWISS family and 2 points smaller than wxNORMAL_FONT. - WxFontUtils::get_font_item(*wxITALIC_FONT), // A font using the wxFONTFAMILY_ROMAN family and wxFONTSTYLE_ITALIC style and of the same size of wxNORMAL_FONT. - WxFontUtils::get_font_item(*wxSWISS_FONT), // A font identic to wxNORMAL_FONT except for the family used which is wxFONTFAMILY_SWISS. - WxFontUtils::get_font_item(wxFont(10, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD)) + WxFontUtils::get_font_item(*wxNORMAL_FONT, _u8L("NORMAL")), // wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) + WxFontUtils::get_font_item(*wxSMALL_FONT, _u8L("SMALL")), // A font using the wxFONTFAMILY_SWISS family and 2 points smaller than wxNORMAL_FONT. + WxFontUtils::get_font_item(*wxITALIC_FONT, _u8L("ITALIC")), // A font using the wxFONTFAMILY_ROMAN family and wxFONTSTYLE_ITALIC style and of the same size of wxNORMAL_FONT. + WxFontUtils::get_font_item(*wxSWISS_FONT, _u8L("SWISS")), // A font identic to wxNORMAL_FONT except for the family used which is wxFONTFAMILY_SWISS. + WxFontUtils::get_font_item(wxFont(10, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD), _u8L("MODERN")) //, WxFontUtils::get_os_font() == wxNORMAL_FONT }; } @@ -617,6 +627,18 @@ void GLGizmoEmboss::close() m_parent.get_gizmos_manager().open_gizmo(GLGizmosManager::Emboss); } +void GLGizmoEmboss::select_stored_font_item() +{ + const std::string &name = m_font_manager.get_font_item().name; + const auto &styles = m_gui_cfg->default_styles; + const auto &it = styles.find(name); + if (it == styles.end()) { + m_stored_font_item.reset(); + return; + } + m_stored_font_item = it->second; +} + void GLGizmoEmboss::draw_window() { #ifdef ALLOW_DEBUG_MODE @@ -899,6 +921,7 @@ void GLGizmoEmboss::draw_rename_style(bool start_rename) m_font_manager.get_truncated_name() = ""; m_font_manager.free_style_images(); ImGui::CloseCurrentPopup(); + select_stored_font_item(); } ImGui::EndPopup(); } @@ -936,7 +959,10 @@ void GLGizmoEmboss::draw_style_list() { const FontManager::StyleImage &img = *item.image; ImVec2 select_size(0.f, std::max(img.tex_size.y, m_gui_cfg->min_style_image_height)); if (ImGui::Selectable("##style_select", is_selected, flags, select_size)) { - if (m_font_manager.load_font(index)) process(); + if (m_font_manager.load_font(index)) { + process(); + select_stored_font_item(); + } } else if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", actual_style_name.c_str()); @@ -991,9 +1017,10 @@ void GLGizmoEmboss::draw_style_list() { if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", _u8L("Duplicate style.").c_str()); - // TODO: Is style changed against stored one - bool is_changed = false; + bool is_stored = m_stored_font_item.has_value(); + bool is_changed = (is_stored) ? + !(*m_stored_font_item == m_font_manager.get_font_item()) : true; ImGui::SameLine(); if (draw_button(IconType::save, !is_changed)) { @@ -1025,7 +1052,10 @@ void GLGizmoEmboss::draw_style_list() { m_font_manager.add_fonts(font_list); // TODO: What to do when default fonts are not loadable? bool success = m_font_manager.load_first_valid_font(); + select_stored_font_item(); } + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("%s", _u8L("Revert all styles").c_str()); #endif // ALLOW_REVERT_ALL_STYLES } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index 2e3faf357f..3de3a156c1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp @@ -18,6 +18,7 @@ #include "libslic3r/Emboss.hpp" #include "libslic3r/Point.hpp" #include "libslic3r/Model.hpp" +#include "libslic3r/TextConfiguration.hpp" #include @@ -148,6 +149,9 @@ private: std::string depth; }; Translations translations; + + std::map default_styles; + GuiCfg() = default; }; std::optional m_gui_cfg; @@ -157,7 +161,8 @@ private: bool m_is_advanced_edit_style = false; FontManager m_font_manager; - + std::optional m_stored_font_item; + void select_stored_font_item(); //FontList m_font_list; //size_t m_font_selected;// index to m_font_list diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp index 1abbe118df..1d4f5c498c 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.cpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp @@ -2,7 +2,6 @@ #include #include // load_obj for default mesh -#include #include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/NotificationManager.hpp" @@ -102,15 +101,13 @@ void EmbossCreateJob::process(Ctl &ctl) { if (m_result.its.empty()) m_result = create_default_mesh(); if (ctl.was_canceled()) return; - Plater * plater = wxGetApp().plater(); // may be move to input - std::optional hit; if (m_input->object_idx.has_value()) { // By position of cursor create transformation to put text on surface of model - const ModelObjectPtrs &objects = wxGetApp().plater()->model().objects; - m_input->raycast_manager->actualize(objects); + ModelObject *obj = wxGetApp().plater()->model().objects[*m_input->object_idx]; + m_input->raycast_manager->actualize(obj); if (ctl.was_canceled()) return; - hit = m_input->raycast_manager->unproject(m_input->screen_coor); + hit = m_input->raycast_manager->unproject(m_input->screen_coor, m_input->camera); // context menu for add text could be open only by right click on an // object. After right click, object is selected and object_idx is set @@ -123,14 +120,12 @@ void EmbossCreateJob::process(Ctl &ctl) { // create new object // calculate X,Y offset position for lay on platter in place of // mouse click - const Camera &camera = plater->get_camera(); - Vec2d bed_coor = CameraUtils::get_z0_position(camera, m_input->screen_coor); + Vec2d bed_coor = CameraUtils::get_z0_position(m_input->camera, m_input->screen_coor); // check point is on build plate: - Pointfs bed_shape = plater->build_volume().bed_shape(); Points bed_shape_; - bed_shape_.reserve(bed_shape.size()); - for (const Vec2d &p : bed_shape) + bed_shape_.reserve(m_input->bed_shape.size()); + for (const Vec2d &p : m_input->bed_shape) bed_shape_.emplace_back(p.cast()); Polygon bed(bed_shape_); if (!bed.contains(bed_coor.cast())) @@ -143,8 +138,13 @@ void EmbossCreateJob::process(Ctl &ctl) { Transform3d::TranslationType tt(offset.x(), offset.y(), offset.z()); m_transformation = Transform3d(tt); } else { - m_transformation = Emboss::create_transformation_onto_surface( - hit->position, hit->normal); + // TODO: Disable apply common transformation after draggig + // Call after is used for apply transformation after common dragging to rewrite it + m_transformation = Emboss::create_transformation_onto_surface(hit->position, hit->normal); + if (m_input->hit_vol_tr.has_value()) { + Transform3d object_trmat = m_input->raycast_manager->get_transformation(hit->tr_key); + m_transformation = m_input->hit_vol_tr->inverse() * object_trmat * m_transformation; + } } } diff --git a/src/slic3r/GUI/Jobs/EmbossJob.hpp b/src/slic3r/GUI/Jobs/EmbossJob.hpp index 08bf3d888f..37dd757a65 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.hpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.hpp @@ -4,6 +4,7 @@ #include #include #include "slic3r/Utils/RaycastManager.hpp" +#include "slic3r/GUI/Camera.hpp" #include "Job.hpp" namespace Slic3r { @@ -110,6 +111,15 @@ struct EmbossDataCreate: public EmbossDataBase // when exist ModelObject where to create volume std::optional object_idx; + // hitted instance transformation + std::optional hit_vol_tr; + + // projection property + Camera camera; + + // shape of bed in case of create volume on bed + std::vector bed_shape; + // used to find point on surface where to create new object RaycastManager *raycast_manager; // It is inside of GLGizmoEmboss object, @@ -121,11 +131,17 @@ struct EmbossDataCreate: public EmbossDataBase ModelVolumeType volume_type, Vec2d screen_coor, std::optional object_idx, + const std::optional& hit_vol_tr, + const Camera& camera, + const std::vector & bed_shape, RaycastManager * raycast_manager) : EmbossDataBase(std::move(font_file), text_configuration, volume_name) , volume_type(volume_type) , screen_coor(screen_coor) , object_idx(object_idx) + , hit_vol_tr(hit_vol_tr) + , camera(camera) + , bed_shape(bed_shape) , raycast_manager(raycast_manager) {} }; diff --git a/src/slic3r/Utils/RaycastManager.cpp b/src/slic3r/Utils/RaycastManager.cpp index 715a8c47c6..87a53a9788 100644 --- a/src/slic3r/Utils/RaycastManager.cpp +++ b/src/slic3r/Utils/RaycastManager.cpp @@ -73,8 +73,45 @@ void RaycastManager::actualize(const ModelObjectPtrs &objects, transformations.erase(transformation_key); } +void RaycastManager::actualize(const ModelObject *object, const ISkip *skip) +{ + // actualize MeshRaycaster + for (const ModelVolume *volume : object->volumes) { + size_t oid = volume->id().id; + if (skip != nullptr && skip->skip(oid)) + continue; + auto item = raycasters.find(oid); + if (item == raycasters.end()) { + // add new raycaster + auto raycaster = std::make_unique(volume->mesh()); + raycasters.insert(std::make_pair(oid, std::move(raycaster))); + } + } + + // actualize transformation matrices + for (const ModelVolume *volume : object->volumes) { + if (skip != nullptr && skip->skip(volume->id().id)) continue; + const Transform3d &volume_tr = volume->get_matrix(); + for (const ModelInstance *instance : object->instances) { + const Transform3d &instrance_tr = instance->get_matrix(); + Transform3d transformation = instrance_tr * volume_tr; + // TODO: add SLA shift Z + // transformation.translation()(2) += m_sla_shift_z; + TrKey tr_key = std::make_pair(instance->id().id, volume->id().id); + auto item = transformations.find(tr_key); + if (item != transformations.end()) { + // actualize transformation all the time + item->second = transformation; + } else { + // add new transformation + transformations.insert(std::make_pair(tr_key, transformation)); + } + } + } +} + std::optional RaycastManager::unproject( - const Vec2d &mouse_pos, const ISkip *skip) const + const Vec2d &mouse_pos, const Camera &camera, const ISkip *skip) const { struct HitWithDistance: public Hit { @@ -87,8 +124,6 @@ std::optional RaycastManager::unproject( {} }; std::optional closest; - - const Camera &camera = wxGetApp().plater()->get_camera(); for (const auto &item : transformations) { const TrKey &key = item.first; size_t volume_id = key.second; diff --git a/src/slic3r/Utils/RaycastManager.hpp b/src/slic3r/Utils/RaycastManager.hpp index 9dc0514c7b..5edfa35aa0 100644 --- a/src/slic3r/Utils/RaycastManager.hpp +++ b/src/slic3r/Utils/RaycastManager.hpp @@ -53,6 +53,8 @@ public: void actualize(const ModelObjectPtrs &objects, const ISkip * skip = nullptr); + void actualize(const ModelObject *object, const ISkip *skip = nullptr); + // TODO: it is more general object move outside of this class struct SurfacePoint { @@ -85,9 +87,11 @@ public: /// Note: Function use current camera position from wxGetApp() /// /// Position of mouse on screen + /// Projection params /// Define which caster will be skipped, null mean no skip /// Position on surface, normal direction and transformation key, which define hitted object instance - std::optional unproject(const Vec2d &mouse_pos, + std::optional unproject(const Vec2d &mouse_pos, + const Camera &camera, const ISkip *skip = nullptr) const; ///