From 4091f3e04256b45ec94946df741e4c70e0015a5b Mon Sep 17 00:00:00 2001 From: "zhou.xu" Date: Wed, 7 Aug 2024 11:22:42 +0800 Subject: [PATCH] ENH:fix text coordinate system calculation jira: STUDIO-6449 Change-Id: I36214c14c348e8f52b96501cd027205819b0dabc (cherry picked from commit 44287812a0cb212f1bf6fe70e32e1075f532886d) --- src/libslic3r/Geometry.cpp | 11 + src/libslic3r/Geometry.hpp | 1 + src/libslic3r/Model.cpp | 16 +- src/libslic3r/Model.hpp | 5 +- src/slic3r/GUI/GLCanvas3D.cpp | 60 -- src/slic3r/GUI/GLCanvas3D.hpp | 2 - src/slic3r/GUI/GUI_ObjectList.cpp | 49 ++ src/slic3r/GUI/GUI_ObjectList.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 18 +- src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp | 3 +- src/slic3r/GUI/Gizmos/GLGizmoText.cpp | 513 ++++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoText.hpp | 35 +- .../GUI/Gizmos/GizmoObjectManipulation.cpp | 43 +- .../GUI/Gizmos/GizmoObjectManipulation.hpp | 4 + src/slic3r/GUI/Selection.cpp | 22 +- src/slic3r/GUI/Selection.hpp | 8 +- 16 files changed, 466 insertions(+), 325 deletions(-) diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index 7238ce8e4..9fba666b6 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -808,5 +808,16 @@ Geometry::TransformationSVD::TransformationSVD(const Transform3d &trafo) return curMat; } +Transformation generate_transform(const Vec3d& x_dir, const Vec3d& y_dir, const Vec3d& z_dir, const Vec3d& origin) { + Matrix3d m; + m.col(0) = x_dir.normalized(); + m.col(1) = y_dir.normalized(); + m.col(2) = z_dir.normalized(); + Transform3d mm(m); + Transformation tran(mm); + tran.set_offset(origin); + return tran; +} + } // namespace Geometry } // namespace Slic3r diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 2e52a2be2..d18b7ea53 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -494,6 +494,7 @@ inline bool is_rotation_ninety_degrees(const Vec3d &rotation) } Transformation mat_around_a_point_rotate(const Transformation& innMat, const Vec3d &pt, const Vec3d &axis, float rotate_theta_radian); +Transformation generate_transform(const Vec3d &x_dir, const Vec3d &y_dir, const Vec3d &z_dir, const Vec3d &origin); } } // namespace Slicer::Geometry #endif diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index ace8321c4..1b718183f 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1193,23 +1193,27 @@ bool ModelObject::make_boolean(ModelObject *cut_object, const std::string &boole return true; } -ModelVolume* ModelObject::add_volume(const TriangleMesh &mesh) +ModelVolume *ModelObject::add_volume(const TriangleMesh &mesh, bool modify_to_center_geometry) { ModelVolume* v = new ModelVolume(this, mesh); this->volumes.push_back(v); - v->center_geometry_after_creation(); - this->invalidate_bounding_box(); + if (modify_to_center_geometry) { + v->center_geometry_after_creation(); + this->invalidate_bounding_box(); + } // BBS: backup Slic3r::save_object_mesh(*this); return v; } -ModelVolume* ModelObject::add_volume(TriangleMesh &&mesh, ModelVolumeType type /*= ModelVolumeType::MODEL_PART*/) +ModelVolume *ModelObject::add_volume(TriangleMesh &&mesh, ModelVolumeType type /*= ModelVolumeType::MODEL_PART*/, bool modify_to_center_geometry) { ModelVolume* v = new ModelVolume(this, std::move(mesh), type); this->volumes.push_back(v); - v->center_geometry_after_creation(); - this->invalidate_bounding_box(); + if (modify_to_center_geometry) { + v->center_geometry_after_creation(); + this->invalidate_bounding_box(); + } // BBS: backup Slic3r::save_object_mesh(*this); return v; diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index d6d7fc2c7..d9c5f07a4 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -399,8 +399,8 @@ public: return global_config.option(config_option); } - ModelVolume* add_volume(const TriangleMesh &mesh); - ModelVolume* add_volume(TriangleMesh &&mesh, ModelVolumeType type = ModelVolumeType::MODEL_PART); + ModelVolume* add_volume(const TriangleMesh &mesh, bool modify_to_center_geometry = true); + ModelVolume* add_volume(TriangleMesh &&mesh, ModelVolumeType type = ModelVolumeType::MODEL_PART, bool modify_to_center_geometry = true); ModelVolume* add_volume(const ModelVolume &volume, ModelVolumeType type = ModelVolumeType::INVALID); ModelVolume* add_volume(const ModelVolume &volume, TriangleMesh &&mesh); ModelVolume* add_volume_with_shared_mesh(const ModelVolume &other, ModelVolumeType type = ModelVolumeType::MODEL_PART); @@ -828,7 +828,6 @@ struct TextInfo std::string m_text; RaycastResult m_rr; - Vec3d m_hit_in_text; // for load use template void serialize(Archive &ar) { ar(m_font_name, m_font_size, m_curr_font_idx, m_bold, m_italic, m_thickness, m_embeded_depth, m_rotate_angle, m_text_gap, m_is_surface_text, m_keep_horizontal, m_text, m_rr); } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 67e2c846d..7c524ce32 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4616,30 +4616,6 @@ void GLCanvas3D::set_tooltip(const std::string& tooltip) m_tooltip.set_text(tooltip); } -void GLCanvas3D::generate_new_hit_in_text_info(ModelVolume * cur_mv, - ModelObject * model_object, - ModelInstance * mi, - const Transform3d &old_text_world_tran, - const Transform3d &cur_text_world_tran, - TextInfo * text_info, - int type) -{ - Geometry::Transformation old_text_tran_(old_text_world_tran); - Geometry::Transformation cur_text_tran_(cur_text_world_tran); - bool is_changed = (type == 0 && old_text_tran_.get_offset() != cur_text_tran_.get_offset()) ||//move - (type == 1 && old_text_tran_.get_rotation() != cur_text_tran_.get_rotation()) ||// rotate - (type == 2 && old_text_tran_.get_scaling_factor() != cur_text_tran_.get_scaling_factor()); - if (is_changed) { - std::vector trafo_matrices; - for (const ModelVolume *mv : model_object->volumes) { - if (mv->is_model_part()) { trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix()); } - } - if (text_info->m_rr.mesh_id < trafo_matrices.size()) { - text_info->m_rr.hit = (trafo_matrices[text_info->m_rr.mesh_id].inverse() * (cur_text_world_tran * text_info->m_hit_in_text)).cast(); - } - } -} - void GLCanvas3D::do_move(const std::string &snapshot_type) { if (m_model == nullptr) @@ -4682,18 +4658,7 @@ void GLCanvas3D::do_move(const std::string &snapshot_type) else if (selection_mode == Selection::Volume) { auto cur_mv = model_object->volumes[volume_idx]; if (cur_mv->get_offset() != v->get_volume_offset()) { - auto text_info = const_cast(&cur_mv->get_text_info()); - auto mi = model_object->instances[instance_idx]; - Transform3d old_text_world_tran; - bool is_text_mv = text_info && !text_info->m_text.empty() && text_info->m_rr.mesh_id >= 0; - if (is_text_mv) { // deal text_info - old_text_world_tran = mi->get_transformation().get_matrix() * cur_mv->get_matrix(); - } cur_mv->set_offset(v->get_volume_offset()); - if (is_text_mv) { // deal text_info - auto cur_text_world_tran = mi->get_transformation().get_matrix() * cur_mv->get_matrix(); - generate_new_hit_in_text_info(cur_mv, model_object, mi, old_text_world_tran, cur_text_world_tran, text_info, 0); - } // BBS: backup Slic3r::save_object_mesh(*model_object); } @@ -4806,19 +4771,7 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type) else if (selection_mode == Selection::Volume) { auto cur_mv = model_object->volumes[volume_idx]; if (cur_mv->get_rotation() != v->get_volume_rotation()) { - auto text_info = const_cast(&cur_mv->get_text_info()); - auto mi = model_object->instances[instance_idx]; - Transform3d old_text_world_tran; - bool is_text_mv = text_info && !text_info->m_text.empty() && text_info->m_rr.mesh_id >= 0; - if (is_text_mv) { // deal text_info - old_text_world_tran = mi->get_transformation().get_matrix() * cur_mv->get_matrix(); - } - cur_mv->set_transformation(v->get_volume_transformation()); - if (is_text_mv) { // deal text_info - auto cur_text_world_tran = mi->get_transformation().get_matrix() * cur_mv->get_matrix(); - generate_new_hit_in_text_info(cur_mv, model_object, mi, old_text_world_tran, cur_text_world_tran, text_info, 1); - } // BBS: backup Slic3r::save_object_mesh(*model_object); } @@ -4899,21 +4852,8 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type) else if (selection_mode == Selection::Volume) { auto cur_mv = model_object->volumes[volume_idx]; if (cur_mv->get_scaling_factor() != v->get_volume_scaling_factor()) { - auto text_info = const_cast(&cur_mv->get_text_info()); - auto mi = model_object->instances[instance_idx]; - Transform3d old_text_world_tran; - bool is_text_mv = text_info && !text_info->m_text.empty() && text_info->m_rr.mesh_id >= 0; - if (is_text_mv) { // deal text_info - old_text_world_tran = mi->get_transformation().get_matrix() * cur_mv->get_matrix(); - } - model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation()); cur_mv->set_transformation(v->get_volume_transformation()); - - if (is_text_mv) { // deal text_info - auto cur_text_world_tran = mi->get_transformation().get_matrix() * cur_mv->get_matrix(); - generate_new_hit_in_text_info(cur_mv, model_object, mi, old_text_world_tran, cur_text_world_tran, text_info, 2); - } // BBS: backup Slic3r::save_object_mesh(*model_object); } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 706744d66..93ba2424f 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -952,8 +952,6 @@ public: void set_tooltip(const std::string& tooltip); // the following methods add a snapshot to the undo/redo stack, unless the given string is empty - void generate_new_hit_in_text_info(ModelVolume *cur_mv, ModelObject *model_object,ModelInstance *mi, - const Transform3d &old_text_world_tran, const Transform3d &cur_text_world_tran, TextInfo *text_info,int type); void do_move(const std::string& snapshot_type); void do_rotate(const std::string& snapshot_type); void do_scale(const std::string& snapshot_type); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 39cb79464..9ed79d6cc 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -2361,6 +2361,55 @@ int ObjectList::load_mesh_part(const TriangleMesh &mesh, const wxString &name, c return mo->volumes.size() - 1; } +int GUI::ObjectList::add_text_part(const TriangleMesh &mesh, const wxString &name, const TextInfo &text_info, const Transform3d &text_in_object_tran, bool is_temp) +{ + wxDataViewItem item = GetSelection(); + // we can add volumes for Object or Instance + if (!item || !(m_objects_model->GetItemType(item) & (itObject | itInstance))) + return -1; + const int obj_idx = m_objects_model->GetObjectIdByItem(item); + + if (obj_idx < 0) + return -1; + + // Get object item, if Instance is selected + if (m_objects_model->GetItemType(item) & itInstance) + item = m_objects_model->GetItemById(obj_idx); + + ModelObject *mo = (*m_objects)[obj_idx]; + + Geometry::Transformation instance_transformation = mo->instances[0]->get_transformation(); + + ModelVolume *mv = mo->add_volume(mesh,false); + mv->set_transformation(text_in_object_tran); + mo->invalidate_bounding_box(); + mv->name = name.ToStdString(); + if (!text_info.m_text.empty()) + mv->set_text_info(text_info); + + if (!is_temp) { + std::vector volumes; + volumes.push_back(mv); + wxDataViewItemArray items = reorder_volumes_and_get_selection(obj_idx, [volumes](const ModelVolume *volume) { + return std::find(volumes.begin(), volumes.end(), volume) != volumes.end(); + }); + + wxGetApp().plater()->get_view3D_canvas3D()->update_instance_printable_state_for_object((size_t) obj_idx); + + if (items.size() > 1) { + m_selection_mode = smVolume; + m_last_selected_item = wxDataViewItem(nullptr); + } + select_items(items); + + selection_changed(); + } + + // BBS: notify partplate the modify + notify_instance_updated(obj_idx); + return mo->volumes.size() - 1; +} + //BBS bool ObjectList::del_object(const int obj_idx, bool refresh_immediately) { diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index b888e1bde..4462b9bd0 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -291,6 +291,7 @@ public: // BBS void switch_to_object_process(); int load_mesh_part(const TriangleMesh &mesh, const wxString &name, const TextInfo &text_info, bool is_temp); + int add_text_part(const TriangleMesh &mesh, const wxString &name, const TextInfo &text_info,const Transform3d& text_in_object_tran, bool is_temp); bool del_object(const int obj_idx, bool refresh_immediately = true); void del_subobject_item(wxDataViewItem& item); void del_settings_from_config(const wxDataViewItem& parent_item); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index 4b8490a81..3fe13f865 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -81,7 +81,7 @@ bool GLGizmoRotate::on_init() } void GLGizmoRotate::on_start_dragging() -{ +{ init_data_from_selection(m_parent.get_selection()); } @@ -489,6 +489,22 @@ void GLGizmoRotate3D::on_set_state() g.set_state(m_state); if (get_state() == On && m_object_manipulation) { m_object_manipulation->set_coordinates_type(ECoordinatesType::World); + m_last_volume = nullptr; + } +} + +void GLGizmoRotate3D::data_changed(bool is_serializing) { + const Selection &selection = m_parent.get_selection(); + const GLVolume * volume = selection.get_first_volume(); + if (m_last_volume != volume) { + m_last_volume = volume; + Geometry::Transformation tran; + if (selection.is_single_full_instance()) { + tran = volume->get_instance_transformation(); + } else { + tran = volume->get_volume_transformation(); + } + m_object_manipulation->set_init_rotation(tran); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index 911a3765d..138a345e3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -137,6 +137,7 @@ protected: if (id < 3) m_gizmos[id].disable_grabber(0); } + void data_changed(bool is_serializing) override; bool on_is_activable() const override; void on_start_dragging() override; void on_stop_dragging() override; @@ -157,7 +158,7 @@ protected: void on_render_input_window(float x, float y, float bottom_limit) override; private: - + const GLVolume *m_last_volume; class RotoptimzeWindow { ImGuiWrapper *m_imgui = nullptr; public: diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp index 00424e4eb..bdde0a803 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp @@ -38,7 +38,16 @@ static const int FONT_SIZE = 12; static const float SELECTABLE_INNER_OFFSET = 8.0f; static const wxFontEncoding font_encoding = wxFontEncoding::wxFONTENCODING_SYSTEM; - +const std::array TEXT_GRABBER_COLOR = {1.0, 1.0, 0.0, 1.0}; +const std::array TEXT_GRABBER_HOVER_COLOR = {0.7, 0.7, 0.0, 1.0}; +#ifdef DEBUG_TEXT +std::string formatFloat(float val) +{ + std::stringstream ss; + ss << std::fixed << std::setprecision(2) << val; + return ss.str(); +} +#endif std::vector init_face_names() { std::vector valid_font_names; @@ -72,7 +81,7 @@ std::vector init_face_names() return false; return true; - }; + }; std::sort(facenames.begin(), facenames.end()); for (const wxString &name : facenames) { @@ -216,7 +225,6 @@ bool GLGizmoText::on_init() m_desc["rotate_text_caption"] = _L("Shift + Mouse move up or down"); m_desc["rotate_text"] = _L("Rotate text"); - m_grabbers.push_back(Grabber()); return true; } @@ -285,15 +293,12 @@ bool GLGizmoText::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_posit if (text.empty()) return true; - const ModelObject * mo = m_c->selection_info()->model_object(); - if (m_is_modify) { - const Selection &selection = m_parent.get_selection(); - mo = selection.get_model()->objects[m_object_idx]; - } + + const Selection &selection = m_parent.get_selection(); + auto mo = selection.get_model()->objects[m_object_idx]; if (mo == nullptr) return true; - const Selection & selection = m_parent.get_selection(); const ModelInstance *mi = mo->instances[selection.get_instance_idx()]; const Camera & camera = wxGetApp().plater()->get_camera(); @@ -376,10 +381,10 @@ bool GLGizmoText::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_posit if (closest_hit == Vec3f::Zero() && closest_normal == Vec3f::Zero()) return true; - m_rr = {mouse_position, closest_hit_mesh_id, closest_hit, closest_normal}; + m_rr = {mouse_position, closest_hit_mesh_id, closest_hit, closest_normal};//left down - m_is_modify = true; generate_text_volume(false); + m_is_modify = true; plater->update(); } @@ -389,18 +394,13 @@ bool GLGizmoText::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_posit void GLGizmoText::on_set_state() { if (m_state == EState::On) { - if (m_parent.get_selection().is_single_volume() || m_parent.get_selection().is_single_modifier()) { - ModelVolume *model_volume = m_parent.get_selection().get_selected_single_volume(m_object_idx, m_volume_idx); - if (model_volume) { - TextInfo text_info = model_volume->get_text_info(); - if (!text_info.m_text.empty()) { - load_from_text_info(text_info); - m_is_modify = true; - } - } - } + m_last_text_mv = nullptr; + m_need_fix = false; + load_init_text(); } else if (m_state == EState::Off) { + m_show_warning = false; + m_edit_text_again = false; reset_text_info(); delete_temp_preview_text_volume(); m_parent.use_slope(false); @@ -408,6 +408,59 @@ void GLGizmoText::on_set_state() } } +void GLGizmoText::load_init_text() +{ + Plater *plater = wxGetApp().plater(); + if (m_parent.get_selection().is_single_volume() || m_parent.get_selection().is_single_modifier()) { + ModelVolume *model_volume = m_parent.get_selection().get_selected_single_volume(m_object_idx, m_volume_idx); + if (model_volume) { + TextInfo text_info = model_volume->get_text_info(); + if (!text_info.m_text.empty()) { + if (m_last_text_mv == model_volume) { + m_last_text_mv = model_volume; + return; + } + m_need_fix = false; + if (plater) { + plater->take_snapshot("enter Text"); + } + m_last_text_mv = model_volume; + load_from_text_info(text_info); + m_edit_text_again = true; + m_text_volume_tran = model_volume->get_matrix(); + m_text_tran_in_object.set_matrix(m_text_volume_tran); + int temp_object_idx; + auto mo = m_parent.get_selection().get_selected_single_object(temp_object_idx); + const ModelInstance *mi = mo->instances[m_parent.get_selection().get_instance_idx()]; + auto world_tran = mi->get_transformation().get_matrix() * m_text_volume_tran; + m_text_tran_in_world.set_matrix(world_tran); + m_text_position_in_world = m_text_tran_in_world.get_offset(); + m_text_normal_in_world = -m_text_tran_in_world.get_matrix().linear().col(1).cast(); + { + TriangleMesh text_attach_mesh(mo->volumes[m_rr.mesh_id]->mesh()); + text_attach_mesh.transform(mo->volumes[m_rr.mesh_id]->get_matrix()); + MeshRaycaster temp_ray_caster(text_attach_mesh); + Vec3f local_center = m_text_tran_in_object.get_offset().cast(); + Vec3f temp_normal; + Vec3f closest_pt = temp_ray_caster.get_closest_point(local_center, &temp_normal); + m_fix_text_position_in_world = mi->get_transformation().get_matrix() * closest_pt.cast(); + m_fix_text_normal_in_world = (mi->get_transformation().get_matrix_no_offset().cast() * temp_normal).normalized(); + if ((m_fix_text_position_in_world - m_text_position_in_world).norm() > 0.1) { + m_need_fix = true; + } + } + // m_rr.mesh_id + m_need_update_text = false; + m_is_modify = true; + } + } + } +} + +void GLGizmoText::data_changed(bool is_serializing) { + load_init_text(); + m_rr.normal = Vec3f::Zero(); +} CommonGizmosDataID GLGizmoText::on_get_requirements() const { return CommonGizmosDataID( @@ -453,31 +506,54 @@ void GLGizmoText::on_render() } ModelObject *mo = nullptr; - mo = m_c->selection_info()->model_object(); - - if (mo == nullptr) { - const Selection &selection = m_parent.get_selection(); - mo = selection.get_model()->objects[m_object_idx]; - } + const Selection &selection = m_parent.get_selection(); + mo = selection.get_model()->objects[m_object_idx]; if (mo == nullptr) { BOOST_LOG_TRIVIAL(info) << boost::format("Text: selected object is null"); return; } - // First check that the mouse pointer is on an object. - const Selection & selection = m_parent.get_selection(); - const ModelInstance *mi = mo->instances[0]; + const ModelInstance *mi = mo->instances[selection.get_instance_idx()]; Plater *plater = wxGetApp().plater(); if (!plater) return; +#ifdef DEBUG_TEXT + if (m_text_normal_in_world.norm() > 0.1) { // debug + Geometry::Transformation tran(m_text_volume_tran); + if (tran.get_offset().norm() > 1) { + auto text_volume_tran_world = mi->get_transformation().get_matrix() * m_text_volume_tran; + glsafe(::glPushMatrix()); + glsafe(::glMultMatrixd(text_volume_tran_world.data())); + render_cross_mark(Vec3f::Zero(), true); + glsafe(::glPopMatrix()); + } - if (!m_is_modify || m_shift_down) { + glsafe(::glPushMatrix()); + glsafe(::glMultMatrixd(m_text_tran_in_world.get_matrix().data())); + render_cross_mark(Vec3f::Zero(), true); + glsafe(::glPopMatrix()); + + glsafe(::glLineWidth(2.0f)); + ::glBegin(GL_LINES); + glsafe(::glColor3f(1.0f, 0.0f, 0.0f)); + + for (size_t i = 1; i < m_cut_points_in_world.size(); i++) {//draw points + auto target0 = m_cut_points_in_world[i - 1].cast(); + auto target1 = m_cut_points_in_world[i].cast(); + glsafe(::glVertex3f(target0(0), target0(1), target0(2))); + glsafe(::glVertex3f(target1(0), target1(1), target1(2))); + } + glsafe(::glEnd()); + } +#endif + if (!m_is_modify || m_shift_down) {//for temp text const Camera &camera = wxGetApp().plater()->get_camera(); // Precalculate transformations of individual meshes. std::vector trafo_matrices; for (const ModelVolume *mv : mo->volumes) { - if (mv->is_model_part()) trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix()); + if (mv->is_model_part()) + trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix()); } // Raycast and return if there's no hit. Vec2d mouse_pos; @@ -500,27 +576,34 @@ void GLGizmoText::on_render() if (!position_changed && !m_need_update_text && !m_shift_down) return; + update_text_pos_normal(); } - if (m_is_modify && m_grabbers.size() == 1) { - std::vector trafo_matrices; - for (const ModelVolume *mv : mo->volumes) { - if (mv->is_model_part()) { - trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix()); - } + if (m_is_modify) { + update_text_pos_normal(); + Geometry::Transformation tran;//= m_text_tran_in_world; + { + double phi; + Vec3d rotation_axis; + Matrix3d rotation_matrix; + Geometry::rotation_from_two_vectors(Vec3d::UnitZ(), m_text_normal_in_world.cast(), rotation_axis, phi, &rotation_matrix); + tran.set_matrix((Transform3d) rotation_matrix); } - - m_mouse_position_world = trafo_matrices[m_rr.mesh_id] * Vec3d(m_rr.hit(0), m_rr.hit(1), m_rr.hit(2)); - - float mean_size = (float) (GLGizmoBase::Grabber::FixedGrabberSize); - - m_grabbers[0].center = m_mouse_position_world; - m_grabbers[0].enabled = true; - std::array color = picking_color_component(0); - m_grabbers[0].color = color; - m_grabbers[0].render_for_picking(mean_size); + tran.set_offset(m_text_position_in_world); + bool hover = (m_hover_id == m_move_cube_id); + std::array render_color; + if (hover) { + render_color = TEXT_GRABBER_HOVER_COLOR; + } else + render_color = TEXT_GRABBER_COLOR; + float fullsize = 8.0f; + if (GLGizmoBase::INV_ZOOM > 0) { fullsize = m_move_grabber.FixedGrabberSize * GLGizmoBase::INV_ZOOM; } + m_move_grabber.center = tran.get_offset(); + Transform3d rotate_matrix = tran.get_rotation_matrix(); + Transform3d cube_mat = Geometry::translation_transform(m_move_grabber.center) * rotate_matrix * Geometry::scale_transform(fullsize); + render_glmodel(m_move_grabber.get_cube(), render_color, cube_mat); } - + delete_temp_preview_text_volume(); if (m_is_modify && !m_need_update_text) @@ -537,48 +620,37 @@ void GLGizmoText::on_render_for_picking() int obejct_idx, volume_idx; ModelVolume *model_volume = m_parent.get_selection().get_selected_single_volume(obejct_idx, volume_idx); if (model_volume && !model_volume->get_text_info().m_text.empty()) { - if (m_grabbers.size() == 1) { - ModelObject *mo = m_c->selection_info()->model_object(); - if (m_is_modify) { - const Selection &selection = m_parent.get_selection(); - mo = selection.get_model()->objects[m_object_idx]; - } - if (mo == nullptr) return; - - const Selection & selection = m_parent.get_selection(); - const ModelInstance *mi = mo->instances[selection.get_instance_idx()]; - - // Precalculate transformations of individual meshes. - std::vector trafo_matrices; - for (const ModelVolume *mv : mo->volumes) { - if (mv->is_model_part()) { - trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix()); - } - } - - m_mouse_position_world = trafo_matrices[m_rr.mesh_id] * Vec3d(m_rr.hit(0), m_rr.hit(1), m_rr.hit(2)); - - float mean_size = (float) (GLGizmoBase::Grabber::FixedGrabberSize); - m_grabbers[0].center = m_mouse_position_world; - m_grabbers[0].enabled = true; - std::array color = picking_color_component(0); - m_grabbers[0].color = color; - m_grabbers[0].render_for_picking(mean_size); - } + const Selection &selection = m_parent.get_selection(); + auto mo = selection.get_model()->objects[m_object_idx]; + if (mo == nullptr) + return; + auto color = picking_color_component(m_move_cube_id); + m_move_grabber.color[0] = color[0]; + m_move_grabber.color[1] = color[1]; + m_move_grabber.color[2] = color[2]; + m_move_grabber.color[3] = color[3]; + float mean_size = (float) (GLGizmoBase::Grabber::FixedGrabberSize); + m_move_grabber.render_for_picking(mean_size); } } +void GLGizmoText::on_start_dragging() +{ +} + +void GLGizmoText::on_stop_dragging() +{ +} + void GLGizmoText::on_update(const UpdateData &data) { Vec2d mouse_pos = Vec2d(data.mouse_pos.x(), data.mouse_pos.y()); - const ModelObject *mo = m_c->selection_info()->model_object(); - if (m_is_modify) { - const Selection &selection = m_parent.get_selection(); - mo = selection.get_model()->objects[m_object_idx]; - } - if (mo == nullptr) return; - const Selection & selection = m_parent.get_selection(); + const Selection &selection = m_parent.get_selection(); + auto mo = selection.get_model()->objects[m_object_idx]; + if (mo == nullptr) + return; + const ModelInstance *mi = mo->instances[selection.get_instance_idx()]; const Camera & camera = wxGetApp().plater()->get_camera(); @@ -621,7 +693,7 @@ void GLGizmoText::on_update(const UpdateData &data) if (closest_hit == Vec3f::Zero() && closest_normal == Vec3f::Zero()) return; if (closest_hit_mesh_id != -1) { - m_rr = {mouse_pos, closest_hit_mesh_id, closest_hit, closest_normal}; + m_rr = {mouse_pos, closest_hit_mesh_id, closest_hit, closest_normal};//on drag m_need_update_text = true; } } @@ -654,7 +726,7 @@ void GLGizmoText::push_button_style(bool pressed) { ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(238 / 255.f, 238 / 255.f, 238 / 255.f, 1.f)); ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(1.f, 1.f, 1.f, 1.f)); } - + } } @@ -724,9 +796,9 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) ModelVolume *model_volume = m_parent.get_selection().get_selected_single_volume(object_idx, volume_idx); if ((object_idx != m_object_idx || (object_idx == m_object_idx && volume_idx != m_volume_idx)) && model_volume) { - m_hit_in_text = Vec3d::Zero(); + m_last_text_mv = model_volume; TextInfo text_info = model_volume->get_text_info(); - load_from_text_info(text_info); + load_from_text_info(text_info);//mouse click down m_is_modify = true; m_volume_idx = volume_idx; m_object_idx = object_idx; @@ -745,7 +817,14 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4.0,5.0) * currt_scale); ImGui::PushStyleVar(ImGuiStyleVar_ScrollbarSize, 4.0f * currt_scale); GizmoImguiBegin("Text", ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar); - +#ifdef DEBUG_TEXT + std::string hit = "hit x:" + formatFloat(m_rr.hit[0]) + " y:" + formatFloat(m_rr.hit[1]) + " z:" + formatFloat(m_rr.hit[2]); + std::string normal = "normal x:" + formatFloat(m_rr.normal[0]) + " y:" + formatFloat(m_rr.normal[1]) + " z:" + formatFloat(m_rr.normal[2]); + auto cut_dir = "cut_dir x:" + formatFloat(m_cut_plane_dir_in_world[0]) + " y:" + formatFloat(m_cut_plane_dir_in_world[1]) + " z:" + formatFloat(m_cut_plane_dir_in_world[2]); + m_imgui->text(hit); + m_imgui->text(normal); + m_imgui->text(cut_dir); +#endif float space_size = m_imgui->get_style_scaling() * 8; float font_cap = m_imgui->calc_text_size(_L("Font")).x; float size_cap = m_imgui->calc_text_size(_L("Size")).x; @@ -899,7 +978,13 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) if(ImGui::InputText("", m_text, sizeof(m_text))) m_need_update_text = true; - + std::string text = std::string(m_text); + if (text.empty() && m_is_modify) { + m_imgui->warning_text(_L("Warning:Input cannot be empty!")); + } + if (m_show_warning) { + m_imgui->warning_text(_L("Warning:create text fail.")); + } ImGui::Separator(); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f)); @@ -908,7 +993,7 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) float f_scale = m_parent.get_gizmos_manager().get_layout_scale(); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale)); - + ImGui::SameLine(caption_size); ImGui::AlignTextToFramePadding(); if (m_imgui->bbl_checkbox(_L("Surface"), m_is_surface_text)) @@ -987,11 +1072,39 @@ void GLGizmoText::reset_text_info() m_text_gap = 0.f; m_is_surface_text = true; m_keep_horizontal = false; - + m_rr = RaycastResult(); m_is_modify = false; } -void GLGizmoText::update_font_status() { +void GLGizmoText::update_text_pos_normal() { + if (m_rr.mesh_id < 0) { return; } + if (m_rr.normal.norm() < 0.1) { return; } + const Selection &selection = m_parent.get_selection(); + auto mo = selection.get_model()->objects[m_object_idx]; + if (mo == nullptr) { + BOOST_LOG_TRIVIAL(info) << boost::format("Text: selected object is null"); + return; + } + const ModelInstance *mi = mo->instances[selection.get_instance_idx()]; + + std::vector w_matrices; + std::vector mv_trans; + for (const ModelVolume *mv : mo->volumes) { + if (mv->is_model_part()) { + w_matrices.emplace_back(Geometry::Transformation(mi->get_transformation().get_matrix() * mv->get_matrix())); + mv_trans.emplace_back(Geometry::Transformation(mv->get_matrix())); + } + } +#ifdef DEBUG_TEXT_VALUE + m_rr.hit = Vec3f(-0.58, -1.70, -12.8); + m_rr.normal = Vec3f(0,0,-1);//just rotate cube +#endif + m_text_position_in_world = w_matrices[m_rr.mesh_id].get_matrix() * m_rr.hit.cast(); + m_text_normal_in_world = (w_matrices[m_rr.mesh_id].get_matrix_no_offset().cast() * m_rr.normal).normalized(); +} + +void GLGizmoText::update_font_status() +{ std::unique_lock lock(m_mutex); m_font_status.reserve(m_avail_font_names.size()); for (std::string font_name : m_avail_font_names) { @@ -1023,17 +1136,13 @@ bool GLGizmoText::update_text_positions(const std::vector& texts) int text_num = texts.size(); m_position_points.clear(); m_normal_points.clear(); - ModelObject *mo = m_c->selection_info()->model_object(); - if (m_is_modify) { - const Selection &selection = m_parent.get_selection(); - mo = selection.get_model()->objects[m_object_idx]; - } + + const Selection &selection = m_parent.get_selection(); + auto mo = selection.get_model()->objects[m_object_idx]; if (mo == nullptr) return false; - - const Selection & selection = m_parent.get_selection(); const ModelInstance *mi = mo->instances[selection.get_instance_idx()]; - + m_model_object_in_world_tran = mi->get_transformation(); // Precalculate transformations of individual meshes. std::vector trafo_matrices; std::vector rotate_trafo_matrices; @@ -1048,9 +1157,18 @@ bool GLGizmoText::update_text_positions(const std::vector& texts) BOOST_LOG_TRIVIAL(info) << boost::format("Text: mrr_mesh_id is -1"); return false; } - - m_mouse_position_world = trafo_matrices[m_rr.mesh_id] * Vec3d(m_rr.hit(0), m_rr.hit(1), m_rr.hit(2)); - m_mouse_normal_world = rotate_trafo_matrices[m_rr.mesh_id] * Vec3d(m_rr.normal(0), m_rr.normal(1), m_rr.normal(2)); + if (m_text_normal_in_world.norm() < 0.1) { + BOOST_LOG_TRIVIAL(info) << "m_text_normal_in_object is error"; + return false; + } + // mouse_position_world may is error after user modified + if (m_need_fix) { + m_need_fix = false; + m_text_position_in_world = m_fix_text_position_in_world; + m_text_normal_in_world = m_fix_text_normal_in_world; + } + auto mouse_position_world = m_text_position_in_world.cast(); + auto mouse_normal_world = m_text_normal_in_world.cast(); TriangleMesh slice_meshs; int mesh_index = 0; @@ -1074,34 +1192,27 @@ bool GLGizmoText::update_text_positions(const std::vector& texts) ModelVolume* volume = mo->volumes[volume_index]; - Vec3d temp_position = m_mouse_position_world; - Vec3d temp_normal = m_mouse_normal_world; - - Vec3d cut_plane = Vec3d::UnitY(); + Vec3d temp_normal = m_text_normal_in_world.cast(); + Vec3d cut_plane_in_world = Vec3d::UnitY(); double epson = 1e-6; if (!(abs(temp_normal.x()) <= epson && abs(temp_normal.y()) <= epson && abs(temp_normal.z()) > epson)) { // temp_normal != Vec3d::UnitZ() Vec3d v_plane = temp_normal.cross(Vec3d::UnitZ()); - cut_plane = v_plane.cross(temp_normal); + cut_plane_in_world = v_plane.cross(temp_normal); } - Transform3d rotate_trans; - rotate_trans.setIdentity(); - rotate_trans.rotate(Eigen::AngleAxisd(Geometry::deg2rad(m_rotate_angle), temp_normal)); - cut_plane = rotate_trans * cut_plane; + m_cut_plane_dir_in_world = cut_plane_in_world; - m_cut_plane_dir = cut_plane; - - if (m_keep_horizontal && m_mouse_normal_world != Vec3d::UnitZ()) - m_cut_plane_dir = Vec3d::UnitZ(); + if (m_keep_horizontal && mouse_normal_world != Vec3d::UnitZ()) + m_cut_plane_dir_in_world = Vec3d::UnitZ(); if (!m_is_surface_text) { m_position_points.resize(text_num); m_normal_points.resize(text_num); - Vec3d pos_dir = m_cut_plane_dir.cross(m_mouse_normal_world); + Vec3d pos_dir = m_cut_plane_dir_in_world.cross(mouse_normal_world); pos_dir.normalize(); if (text_num % 2 == 1) { - m_position_points[text_num / 2] = m_mouse_position_world; + m_position_points[text_num / 2] = mouse_position_world; for (int i = 0; i < text_num / 2; ++i) { double left_gap = text_lengths[text_num / 2 - i - 1] + m_text_gap + text_lengths[text_num / 2 - i]; if (left_gap < 0) @@ -1127,8 +1238,8 @@ bool GLGizmoText::update_text_positions(const std::vector& texts) right_gap = 0; if (i == 0) { - m_position_points[text_num / 2 - 1 - i] = m_mouse_position_world - left_gap * pos_dir; - m_position_points[text_num / 2 + i] = m_mouse_position_world + right_gap * pos_dir; + m_position_points[text_num / 2 - 1 - i] = mouse_position_world - left_gap * pos_dir; + m_position_points[text_num / 2 + i] = mouse_position_world + right_gap * pos_dir; continue; } @@ -1138,51 +1249,36 @@ bool GLGizmoText::update_text_positions(const std::vector& texts) } for (int i = 0; i < text_num; ++i) { - m_normal_points[i] = m_mouse_normal_world; + m_normal_points[i] = mouse_normal_world; } return true; } + auto y_dir = -m_text_normal_in_world.cast(); + Vec3d x_dir_world = y_dir.cross(m_cut_plane_dir_in_world); + m_text_tran_in_world = Geometry::generate_transform(x_dir_world, y_dir, m_cut_plane_dir_in_world.cast(), m_text_position_in_world); + Geometry::Transformation rotate_trans; + rotate_trans.set_rotation(Vec3d(0, Geometry::deg2rad(m_rotate_angle), 0)); //m_rotate_angle + m_text_tran_in_world.set_matrix(m_text_tran_in_world.get_matrix() * rotate_trans.get_matrix()); + m_cut_plane_dir_in_world = m_text_tran_in_world.get_matrix().linear().col(2); - double phi; - Vec3d rotation_axis; - Matrix3d rotation_matrix; - Geometry::rotation_from_two_vectors(m_cut_plane_dir, Vec3d::UnitZ(), rotation_axis, phi, &rotation_matrix); - if (abs(phi - PI) < 1e-6) { - Transform3d transform = Transform3d::Identity(); - transform.rotate(Eigen::AngleAxisd(phi, m_mouse_normal_world)); - rotation_matrix = transform.matrix().block<3, 3>(0, 0); - } + // generate clip cs at click pos + auto text_position_in_object = mi->get_transformation().get_matrix().inverse() * m_text_position_in_world.cast(); + auto rotate_mat_inv = mi->get_transformation().get_matrix_no_offset().inverse(); - Transform3d transfo1; - transfo1.setIdentity(); - transfo1.translate(-(mi->get_transformation().get_offset() + volume->get_transformation().get_offset())); - transfo1 = rotation_matrix * transfo1; - - Transform3d transfo2; - transfo2.setIdentity(); - transfo2.translate(mi->get_transformation().get_offset() + volume->get_transformation().get_offset()); - Transform3d transfo = transfo2 * transfo1; - - Vec3d click_point = transfo * temp_position; + auto text_tran_in_object = mi->get_transformation().get_matrix().inverse() * m_text_tran_in_world.get_matrix(); // Geometry::generate_transform(cs_x_dir, cs_y_dir, cs_z_dir, text_position_in_object); // todo modify by m_text_tran_in_world + m_text_tran_in_object.set_matrix(text_tran_in_object); + m_text_cs_to_world_tran = mi->get_transformation().get_matrix() * m_text_tran_in_object.get_matrix(); MeshSlicingParams slicing_params; - slicing_params.trafo = transfo * mi->get_transformation().get_matrix() /** volume->get_transformation().get_matrix()*/; + slicing_params.trafo = m_text_tran_in_object.get_matrix().inverse(); // for debug // its_write_obj(slice_meshs.its, "D:/debug_files/mesh.obj"); - // generate polygons - const Polygons temp_polys = slice_mesh(slice_meshs.its, click_point.z(), slicing_params); - - m_mouse_position_world = click_point; - m_mouse_normal_world = transfo * temp_normal; - - m_mouse_position_world.x() *= 1e6; - m_mouse_position_world.y() *= 1e6; - + const Polygons temp_polys = slice_mesh(slice_meshs.its, 0, slicing_params); + Vec3d scale_click_pt(scale_(0), scale_(0), 0); // for debug - //export_regions_to_svg(Point(m_mouse_position_world.x(), m_mouse_position_world.y()), temp_polys); - + // export_regions_to_svg(Point(scale_pt.x(), scale_pt.y()), temp_polys); Polygons polys = union_(temp_polys); auto point_in_line_rectange = [](const Line &line, const Point &point, double& distance) { @@ -1201,7 +1297,7 @@ bool GLGizmoText::update_text_positions(const std::vector& texts) for (int i = 0; i < lines.size(); ++i) { Line line = lines[i]; double distance = min_distance; - if (point_in_line_rectange(line, Point(m_mouse_position_world.x(), m_mouse_position_world.y()), distance)) { + if (point_in_line_rectange(line, Point(scale_click_pt.x(), scale_click_pt.y()), distance)) { if (distance < min_distance) { min_distance = distance; index = i; @@ -1216,30 +1312,22 @@ bool GLGizmoText::update_text_positions(const std::vector& texts) return false; } - auto make_trafo_for_slicing = [](const Transform3d &trafo) -> Transform3d { - auto t = trafo; - static constexpr const double s = 1. / SCALING_FACTOR; - t.prescale(Vec3d(s, s, 1.)); - return t.cast(); - }; - transfo = make_trafo_for_slicing(transfo); - Transform3d transfo_inv = transfo.inverse(); - std::vector new_points; + m_cut_points_in_world.clear(); + m_cut_points_in_world.reserve(hit_ploy.points.size()); for (int i = 0; i < hit_ploy.points.size(); ++i) { - new_points.emplace_back(transfo_inv * Vec3d(hit_ploy.points[i].x(), hit_ploy.points[i].y(), click_point.z())); + m_cut_points_in_world.emplace_back(m_text_cs_to_world_tran * Vec3d(unscale_(hit_ploy.points[i].x()), unscale_(hit_ploy.points[i].y()), 0)); } - m_mouse_position_world = transfo_inv * m_mouse_position_world; - Polygon_3D new_polygon(new_points); + Polygon_3D new_polygon(m_cut_points_in_world); m_position_points.resize(text_num); if (text_num % 2 == 1) { - m_position_points[text_num / 2] = Vec3d(m_mouse_position_world.x(), m_mouse_position_world.y(), m_mouse_position_world.z()); + m_position_points[text_num / 2] = Vec3d(mouse_position_world.x(), mouse_position_world.y(), mouse_position_world.z()); std::vector lines = new_polygon.get_lines(); Line_3D line = lines[index]; { int index1 = index; - double left_length = (m_mouse_position_world - line.a).cast().norm(); + double left_length = (mouse_position_world - line.a).cast().norm(); int left_num = text_num / 2; while (left_num > 0) { double gap_length = (text_lengths[left_num] + m_text_gap + text_lengths[left_num - 1]); @@ -1273,7 +1361,7 @@ bool GLGizmoText::update_text_positions(const std::vector& texts) { int index2 = index; - double right_length = (line.b - m_mouse_position_world).cast().norm(); + double right_length = (line.b - mouse_position_world).cast().norm(); int right_num = text_num / 2; while (right_num > 0) { double gap_length = (text_lengths[text_num - right_num] + m_text_gap + text_lengths[text_num - right_num - 1]); @@ -1313,7 +1401,7 @@ bool GLGizmoText::update_text_positions(const std::vector& texts) Line_3D line = lines[index]; { int index1 = index; - double left_length = (m_mouse_position_world - line.a).cast().norm(); + double left_length = (mouse_position_world - line.a).cast().norm(); int left_num = text_num / 2; for (int i = 0; i < text_num / 2; ++i) { double gap_length = 0; @@ -1353,7 +1441,7 @@ bool GLGizmoText::update_text_positions(const std::vector& texts) { int index2 = index; - double right_length = (line.b - m_mouse_position_world).cast().norm(); + double right_length = (line.b - mouse_position_world).cast().norm(); int right_num = text_num / 2; double gap_length = 0; for (int i = 0; i < text_num / 2; ++i) { @@ -1412,6 +1500,7 @@ bool GLGizmoText::update_text_positions(const std::vector& texts) return abs(s0 + s1 + s2 - s); }; + bool is_mirrored =m_model_object_in_world_tran.is_left_handed(); for (int i = 0; i < m_position_points.size(); ++i) { for (auto indice : mesh.its.indices) { stl_vertex stl_point0 = mesh.its.vertices[indice[0]]; @@ -1434,6 +1523,9 @@ bool GLGizmoText::update_text_positions(const std::vector& texts) Vec3d s2 = point2 - point0; m_normal_points[i] = s1.cross(s2); m_normal_points[i].normalize(); + if(is_mirrored){ + m_normal_points[i] = -m_normal_points[i]; + } } } } @@ -1446,9 +1538,8 @@ TriangleMesh GLGizmoText::get_text_mesh(const char* text_str, const Vec3d &posit load_text_shape(text_str, m_font_name.c_str(), m_font_size, m_thickness + m_embeded_depth, m_bold, m_italic, text_result); TriangleMesh mesh = text_result.text_mesh; - auto center = mesh.bounding_box().center(); - double mesh_offset = center.z(); - mesh.translate(-text_result.text_width / 2, -m_font_size / 4, -center.z()); + + mesh.translate(-text_result.text_width / 2, -m_font_size / 4, 0); double phi; Vec3d rotation_axis; @@ -1471,15 +1562,11 @@ TriangleMesh GLGizmoText::get_text_mesh(const char* text_str, const Vec3d &posit mesh.rotate(phi, rotation_axis); - const Selection & selection = m_parent.get_selection(); - ModelObject * model_object = selection.get_model()->objects[m_object_idx]; - Geometry::Transformation instance_transformation = model_object->instances[0]->get_transformation(); - Vec3d offset = position - instance_transformation.get_offset(); - offset = offset + mesh_offset * normal; - offset = offset - m_embeded_depth * normal; + + Vec3d offset = position - m_embeded_depth * normal; mesh.translate(offset.x(), offset.y(), offset.z()); - return mesh; + return mesh;//mesh in object cs } bool GLGizmoText::update_raycast_cache(const Vec2d &mouse_position, const Camera &camera, const std::vector &trafo_matrices) @@ -1519,8 +1606,8 @@ bool GLGizmoText::update_raycast_cache(const Vec2d &mouse_position, const Camera } } } - - m_rr = {mouse_position, closest_hit_mesh_id, closest_hit, closest_nromal}; + + m_rr = {mouse_position, closest_hit_mesh_id, closest_hit, closest_nromal};//update_raycast_cache berfor click down return true; } @@ -1537,20 +1624,22 @@ void GLGizmoText::generate_text_volume(bool is_temp) alphas.push_back(str_cnv.to_bytes(w)); } - update_text_positions(alphas); + update_text_positions(alphas);//update m_model_object_in_world_tran if (m_position_points.size() == 0) return; - + auto inv_text_cs_in_object = (m_model_object_in_world_tran.get_matrix() * m_text_tran_in_object.get_matrix()).inverse(); + auto inv_text_cs_in_object_no_offset = (m_model_object_in_world_tran.get_matrix_no_offset() * m_text_tran_in_object.get_matrix_no_offset()).inverse(); TriangleMesh mesh; for (int i = 0; i < alphas.size(); ++i) { - TriangleMesh sub_mesh = get_text_mesh(alphas[i].c_str(), m_position_points[i], m_normal_points[i], m_cut_plane_dir); + auto position = inv_text_cs_in_object * m_position_points[i]; + auto normal = inv_text_cs_in_object_no_offset * m_normal_points[i]; + auto cut_plane_dir = inv_text_cs_in_object_no_offset * m_cut_plane_dir_in_world; + TriangleMesh sub_mesh = get_text_mesh(alphas[i].c_str(), position, normal, cut_plane_dir); mesh.merge(sub_mesh); } - if (mesh.empty()) return; - Plater *plater = wxGetApp().plater(); if (!plater) return; @@ -1558,36 +1647,41 @@ void GLGizmoText::generate_text_volume(bool is_temp) TextInfo text_info = get_text_info(); const Selection &selection = m_parent.get_selection(); ModelObject * model_object = selection.get_model()->objects[m_object_idx]; + int cur_volume_id; if (m_is_modify && m_need_update_text) { if (m_object_idx == -1 || m_volume_idx == -1) { BOOST_LOG_TRIVIAL(error) << boost::format("Text: selected object_idx = %1%, volume_idx = %2%") % m_object_idx % m_volume_idx; return; } - plater->take_snapshot("Modify Text"); + if (!is_temp) { + plater->take_snapshot("Modify Text"); + } ModelVolume * model_volume = model_object->volumes[m_volume_idx]; - ModelVolume * new_model_volume = model_object->add_volume(std::move(mesh)); + ModelVolume * new_model_volume = model_object->add_volume(std::move(mesh),false); + new_model_volume->set_transformation(m_text_tran_in_object.get_matrix()); new_model_volume->set_text_info(text_info); new_model_volume->name = model_volume->name; new_model_volume->set_type(model_volume->type()); new_model_volume->config.apply(model_volume->config); std::swap(model_object->volumes[m_volume_idx], model_object->volumes.back()); model_object->delete_volume(model_object->volumes.size() - 1); + model_object->invalidate_bounding_box(); plater->update(); - auto cur_text_info = const_cast (&new_model_volume->get_text_info()); m_text_volume_tran = new_model_volume->get_matrix(); - update_hit_in_text(); - cur_text_info->m_hit_in_text = m_hit_in_text; } else { - if (m_need_update_text) + if (!is_temp && m_need_update_text) plater->take_snapshot("Add Text"); ObjectList *obj_list = wxGetApp().obj_list(); - int volume_id = obj_list->load_mesh_part(mesh, "text_shape", text_info, is_temp); - m_preview_text_volume_id = is_temp ? volume_id : -1; - ModelVolume *text_model_volume = model_object->volumes[volume_id]; - m_text_volume_tran = text_model_volume->get_matrix(); - auto cur_text_info = const_cast(&text_model_volume->get_text_info()); - update_hit_in_text(); - cur_text_info->m_hit_in_text = m_hit_in_text; + cur_volume_id = obj_list->add_text_part(mesh, "text_shape", text_info, m_text_tran_in_object.get_matrix(), is_temp); + m_preview_text_volume_id = is_temp ? cur_volume_id : -1; + if (cur_volume_id >= 0) { + m_show_warning = false; + ModelVolume *text_model_volume = model_object->volumes[cur_volume_id]; + m_text_volume_tran = text_model_volume->get_matrix(); + } + else { + m_show_warning = true; + } } m_need_update_text = false; } @@ -1620,8 +1714,7 @@ TextInfo GLGizmoText::get_text_info() text_info.m_italic = m_italic; text_info.m_thickness = m_thickness; text_info.m_text = m_text; - text_info.m_rr = m_rr; - text_info.m_hit_in_text = m_hit_in_text; + text_info.m_rr.mesh_id = m_rr.mesh_id; text_info.m_embeded_depth = m_embeded_depth; text_info.m_rotate_angle = m_rotate_angle; text_info.m_text_gap = m_text_gap; @@ -1630,16 +1723,6 @@ TextInfo GLGizmoText::get_text_info() return text_info; } -void GLGizmoText::update_hit_in_text() { - { - const std::vector &trafo_matrices = m_parent.get_selection().get_all_tran_of_selected_volumes(); - auto mi = m_parent.get_selection().get_selected_single_intance(); - if (mi && trafo_matrices.size() > 0) { - auto text_world_tran = mi->get_transformation().get_matrix() * m_text_volume_tran; - m_hit_in_text = text_world_tran.inverse() * (trafo_matrices[m_rr.mesh_id] * m_rr.hit.cast()); - } - } -} void GLGizmoText::load_from_text_info(const TextInfo &text_info) { m_font_name = text_info.m_font_name; @@ -1655,7 +1738,7 @@ void GLGizmoText::load_from_text_info(const TextInfo &text_info) m_italic = text_info.m_italic; m_thickness = text_info.m_thickness; strcpy(m_text, text_info.m_text.c_str()); - m_rr = text_info.m_rr; + m_rr.mesh_id = text_info.m_rr.mesh_id; m_embeded_depth = text_info.m_embeded_depth; m_rotate_angle = text_info.m_rotate_angle; m_text_gap = text_info.m_text_gap; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.hpp b/src/slic3r/GUI/Gizmos/GLGizmoText.hpp index e06ae8c1c..4072bc75d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.hpp @@ -13,7 +13,8 @@ enum class ModelVolumeType : int; class ModelVolume; namespace GUI { - +//#define DEBUG_TEXT +//#define DEBUG_TEXT_VALUE enum class SLAGizmoEventType : unsigned char; class GLGizmoText : public GLGizmoBase { @@ -34,7 +35,6 @@ private: bool m_is_surface_text = false; bool m_keep_horizontal = false; mutable RaycastResult m_rr; - mutable Vec3d m_hit_in_text; float m_combo_height = 0.0f; float m_combo_width = 0.0f; @@ -63,26 +63,41 @@ private: std::mutex m_mutex; std::thread m_thread; + bool m_edit_text_again = false; bool m_is_modify = false; bool m_need_update_text = false; + bool m_show_warning = false; int m_object_idx = -1; int m_volume_idx = -1; int m_preview_text_volume_id = -1; + Vec3d m_fix_text_position_in_world = Vec3d::Zero(); + Vec3f m_fix_text_normal_in_world = Vec3f::Zero(); + bool m_need_fix; + Vec3d m_text_position_in_world = Vec3d::Zero(); + Vec3f m_text_normal_in_world = Vec3f::Zero(); + Geometry::Transformation m_text_tran_in_object; + Geometry::Transformation m_text_tran_in_world; + Geometry::Transformation m_model_object_in_world_tran; + Transform3d m_text_cs_to_world_tran; - Vec3d m_mouse_position_world = Vec3d::Zero(); - Vec3d m_mouse_normal_world = Vec3d::Zero(); - - Vec3d m_cut_plane_dir = Vec3d::UnitZ(); + Vec3d m_cut_plane_dir_in_world = Vec3d::UnitZ(); std::vector m_position_points; std::vector m_normal_points; - + std::vector m_cut_points_in_world; // This map holds all translated description texts, so they can be easily referenced during layout calculations // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. std::map m_desc; Transform3d m_text_volume_tran; + ModelVolume * m_last_text_mv; + // move gizmo + Grabber m_move_grabber; + const int m_move_cube_id = 1; + + // TRN - Title in Undo/Redo stack after move with SVG along emboss axe - From surface + const std::string move_snapshot_name = "Text move"; public: GLGizmoText(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); @@ -102,18 +117,23 @@ protected: virtual bool on_is_activable() const override; virtual void on_render() override; virtual void on_render_for_picking() override; + virtual void on_start_dragging() override; + virtual void on_stop_dragging() override; virtual void on_update(const UpdateData &data) override; void push_combo_style(const float scale); void pop_combo_style(); void push_button_style(bool pressed); void pop_button_style(); virtual void on_set_state() override; + virtual void data_changed(bool is_serializing) override; virtual CommonGizmosDataID on_get_requirements() const override; virtual void on_render_input_window(float x, float y, float bottom_limit); void show_tooltip_information(float x, float y); private: + void load_init_text(); + void update_text_pos_normal(); void update_font_status(); void reset_text_info(); bool update_text_positions(const std::vector& texts); @@ -124,7 +144,6 @@ private: void delete_temp_preview_text_volume(); TextInfo get_text_info(); - void update_hit_in_text(); void load_from_text_info(const TextInfo &text_info); }; diff --git a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp index b7674e695..aa2f0d5cb 100644 --- a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp +++ b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp @@ -263,7 +263,7 @@ void GizmoObjectManipulation::update_reset_buttons_visibility() scale = volume->get_volume_scaling_factor(); min_z = get_volume_min_z(volume); } - m_show_clear_rotation = !rotation.isApprox(Vec3d::Zero()); + m_show_clear_rotation = !rotation.isApprox(m_init_rotation); m_show_clear_scale = (m_cache.scale / 100.0f - Vec3d::Ones()).norm() > 0.001; m_show_drop_to_bed = (std::abs(min_z) > EPSILON); } @@ -488,27 +488,33 @@ void GizmoObjectManipulation::reset_position_value() void GizmoObjectManipulation::reset_rotation_value() { - Selection& selection = m_glcanvas.get_selection(); - - if (selection.is_single_volume() || selection.is_single_modifier()) { - GLVolume* volume = const_cast(selection.get_volume(*selection.get_volume_idxs().begin())); - volume->set_volume_rotation(Vec3d::Zero()); - } - else if (selection.is_single_full_instance()) { + Selection &selection = m_glcanvas.get_selection(); + selection.setup_cache(); + if (selection.is_single_volume_or_modifier()) { + GLVolume * vol = const_cast(selection.get_first_volume()); + Geometry::Transformation trafo = vol->get_volume_transformation(); + auto offset = trafo.get_offset(); + trafo.set_from_transform(m_init_rotation_scale_tran); + trafo.set_offset(offset); + vol->set_volume_transformation(trafo); + } else if (selection.is_single_full_instance()) { + Geometry::Transformation trafo = selection.get_first_volume()->get_instance_transformation(); + auto offset = trafo.get_offset(); + trafo.set_from_transform(m_init_rotation_scale_tran); + trafo.set_offset(offset); for (unsigned int idx : selection.get_volume_idxs()) { - GLVolume* volume = const_cast(selection.get_volume(idx)); - volume->set_instance_rotation(Vec3d::Zero()); + const_cast(selection.get_volume(idx))->set_instance_transformation(trafo); } - } - else + } else return; - // Update rotation at the GLVolumes. - selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL); + // Synchronize instances/volumes. + + selection.synchronize_unselected_instances(Selection::SyncRotationType::RESET); selection.synchronize_unselected_volumes(); + // Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing. - wxGetApp().plater()->take_snapshot(_u8L("Reset Rotation"), UndoRedo::SnapshotType::GizmoAction); - m_glcanvas.do_rotate(""); + m_glcanvas.do_rotate(L("Reset Rotation")); UpdateAndShow(true); } @@ -699,6 +705,11 @@ void GizmoObjectManipulation::show_scale_tooltip_information(ImGuiWrapper *imgui ImGui::PopStyleVar(2); } +void GizmoObjectManipulation::set_init_rotation(const Geometry::Transformation &value) { + m_init_rotation_scale_tran = value.get_matrix_no_offset(); + m_init_rotation = value.get_rotation(); +} + void GizmoObjectManipulation::do_render_move_window(ImGuiWrapper *imgui_wrapper, std::string window_name, float x, float y, float bottom_limit) { // BBS: GUI refactor: move gizmo to the right diff --git a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp index af3c5d3f8..5249c1bf3 100644 --- a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp +++ b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp @@ -133,6 +133,8 @@ public: void show_move_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y); void show_rotate_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y); void show_scale_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y); + void set_init_rotation(const Geometry::Transformation &value); + private: void reset_settings_value(); void update_settings_value(const Selection& selection); @@ -158,6 +160,8 @@ private: std::map m_desc_move; std::map m_desc_rotate; std::map m_desc_scale; + Vec3d m_init_rotation; + Transform3d m_init_rotation_scale_tran; }; }} diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index c9951f334..72fbe83f3 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -422,7 +422,7 @@ ModelVolume *Selection::get_selected_single_volume(int &out_object_idx, int &out ModelObject *Selection::get_selected_single_object(int &out_object_idx) { - if (is_single_volume() || is_single_modifier()) { + if (is_single_volume() || is_single_modifier() || is_single_full_object()) { const GLVolume *gl_volume = get_volume(*get_volume_idxs().begin()); out_object_idx = gl_volume->object_idx(); return get_model()->objects[out_object_idx]; @@ -1222,7 +1222,7 @@ void Selection::translate(const Vec3d &displacement, bool local) #if !DISABLE_INSTANCES_SYNCH if (translation_type == Instance) - synchronize_unselected_instances(SYNC_ROTATION_NONE); + synchronize_unselected_instances(SyncRotationType::NONE); else if (translation_type == Volume) synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH @@ -1292,7 +1292,7 @@ void Selection::translate(const Vec3d &displacement, TransformationType transfor #if !DISABLE_INSTANCES_SYNCH if (m_mode == Instance) - synchronize_unselected_instances(SYNC_ROTATION_NONE); + synchronize_unselected_instances(SyncRotationType::NONE); else if (m_mode == Volume) synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH @@ -1425,7 +1425,7 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ #if !DISABLE_INSTANCES_SYNCH if (m_mode == Instance) - synchronize_unselected_instances((rot_axis_max == 2) ? SYNC_ROTATION_NONE : SYNC_ROTATION_GENERAL); + synchronize_unselected_instances((rot_axis_max == 2) ? SyncRotationType::NONE : SyncRotationType::GENERAL); else if (m_mode == Volume) synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH @@ -1483,7 +1483,7 @@ void Selection::flattening_rotate(const Vec3d& normal) // Apply the same transformation also to other instances, // but respect their possibly diffrent z-rotation. if (m_mode == Instance) - synchronize_unselected_instances(SYNC_ROTATION_GENERAL); + synchronize_unselected_instances(SyncRotationType::GENERAL); #endif // !DISABLE_INSTANCES_SYNCH this->set_bounding_boxes_dirty(); @@ -1669,7 +1669,11 @@ void Selection::scale_and_translate(const Vec3d &scale, const Vec3d &world_trans } else transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(world_translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center); - std::cout << ""; + // update the instance assemble transform + ModelObject * object = m_model->objects[v.object_idx()]; + Geometry::Transformation assemble_transform = object->instances[v.instance_idx()]->get_assemble_transformation(); + assemble_transform.set_scaling_factor(v.get_instance_scaling_factor()); + object->instances[v.instance_idx()]->set_assemble_transformation(assemble_transform); } else { if (!is_single_volume_or_modifier()) { assert(transformation_type.world()); @@ -1695,7 +1699,7 @@ void Selection::scale_and_translate(const Vec3d &scale, const Vec3d &world_trans if (m_mode == Instance) // even if there is no rotation, we pass SyncRotationType::GENERAL to force // synchronize_unselected_instances() to apply the scale to the other instances - synchronize_unselected_instances(SyncRotationType::SYNC_ROTATION_GENERAL); + synchronize_unselected_instances(SyncRotationType::GENERAL); else if (m_mode == Volume) synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH @@ -2910,7 +2914,7 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_ assert(is_rotation_xy_synchronized(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation())); switch (sync_rotation_type) { - case SYNC_ROTATION_NONE: { + case SyncRotationType::NONE: { // z only rotation -> synch instance z // The X,Y rotations should be synchronized from start to end of the rotation. assert(is_rotation_xy_synchronized(rotation, v->get_instance_rotation())); @@ -2918,7 +2922,7 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_ v->set_instance_offset(Z, volume->get_instance_offset().z()); break; } - case SYNC_ROTATION_GENERAL: + case SyncRotationType::GENERAL: // generic rotation -> update instance z with the delta of the rotation. const double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation()); v->set_instance_rotation({ rotation.x(), rotation.y(), rotation.z() + z_diff }); diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index c7f366884..d21bf0469 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -502,13 +502,13 @@ private: void render_sidebar_layers_hints(const std::string& sidebar_field) const; public: - enum SyncRotationType { + enum class SyncRotationType { // Do not synchronize rotation. Either not rotating at all, or rotating by world Z axis. - SYNC_ROTATION_NONE = 0, + NONE = 0, // Synchronize after rotation by an axis not parallel with Z. - SYNC_ROTATION_GENERAL = 1, + GENERAL = 1, // Synchronize after rotation reset. - SYNC_ROTATION_RESET = 2 + RESET = 2 }; void synchronize_unselected_instances(SyncRotationType sync_rotation_type); void synchronize_unselected_volumes();