From d6eea1de429d59b77553d0e5a30ec5e9ad708ad4 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Mon, 6 Feb 2023 10:26:00 +0100 Subject: [PATCH 01/12] Relative move over surface - Not Work --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 123 ++++++++++++++++++++---- src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp | 13 +++ 2 files changed, 116 insertions(+), 20 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index f1bffa8c3a..b88705ad36 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -465,7 +465,9 @@ Vec2d priv::calc_mouse_to_center_text_offset(const Vec2d& mouse, const ModelVolu bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) { - auto do_move = [&]() { + // Fix when leave window during dragging + // Fix when click right button + if (m_surface_drag.has_value() && !mouse_event.Dragging()) { // write transformation from UI into model m_parent.do_move(L("Surface move")); @@ -479,15 +481,15 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) // allow moving with object again m_parent.enable_moving(true); m_surface_drag.reset(); - }; - if (mouse_event.Moving()) { - // Fix when leave window during dragging and move cursor back - if (m_surface_drag.has_value()) - do_move(); - return false; + // only left up is correct + // otherwise it is fix state and return false + return mouse_event.LeftUp(); } + if (mouse_event.Moving()) + return false; + // detect start text dragging if (mouse_event.LeftDown()) { // exist selected volume? @@ -536,7 +538,8 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) Vec2d mouse_pos = mouse_coord.cast(); Vec2d mouse_offset = priv::calc_mouse_to_center_text_offset(mouse_pos, *m_volume); Transform3d instance_inv = gl_volume->get_instance_transformation().get_matrix().inverse(); - m_surface_drag = SurfaceDrag{mouse_offset, instance_inv, gl_volume, condition}; + Transform3d volume_tr = gl_volume->get_volume_transformation().get_matrix(); + m_surface_drag = SurfaceDrag{mouse_offset, instance_inv, volume_tr, gl_volume, condition}; // Cancel job to prevent interuption of dragging (duplicit result) if (m_job_cancel != nullptr) @@ -568,19 +571,85 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) Transform3d object_trmat = m_raycast_manager.get_transformation(hit->tr_key); Transform3d trmat = create_transformation_onto_surface(hit->position, hit->normal); - TextConfiguration &tc = *m_volume->text_configuration; - const FontProp& font_prop = tc.style.prop; - apply_transformation(font_prop, trmat); + // !!!!!!!!!!!!!!!! USE DIRECT hit position and normal - // fix baked transformation from .3mf store process - if (tc.fix_3mf_tr.has_value()) - trmat = trmat * (*tc.fix_3mf_tr); + //TextConfiguration &tc = *m_volume->text_configuration; + //const FontProp& font_prop = tc.style.prop; + //apply_transformation(font_prop, trmat); + + //// fix baked transformation from .3mf store process + //if (tc.fix_3mf_tr.has_value()) + // trmat = trmat * (*tc.fix_3mf_tr); // volume transfomration in world coor - Transform3d world = object_trmat * trmat; - Transform3d volume_tr = m_surface_drag->instance_inv * world; + Transform3d wanted_world = object_trmat * trmat; + Transform3d wanted_volume = m_surface_drag->instance_inv * wanted_world; - // Update transformation inside of instances + // Calculate offset inside instance: + // transformation from curret to wanted position + Vec3d from_position = m_surface_drag->volume_tr * Vec3d::Zero(); + Vec3d to_position = wanted_volume * Vec3d::Zero(); + + Transform3d hit_to_instance = object_trmat * m_surface_drag->instance_inv; + Vec3d to_position2 = hit_to_instance * hit->position.cast(); + Vec3d z_t2 = hit_to_instance.linear() * hit->normal.cast(); + + Vec3d offset_instance = to_position - from_position; + Transform3d trnsl{Eigen::Translation(offset_instance)}; + + // current transformation from volume to world + Transform3d current_world = m_surface_drag->instance_inv.inverse() * m_surface_drag->volume_tr; + + auto current_world_linear = current_world.linear(); + auto wanted_world_linear = wanted_world.linear(); + + // Calculate rotation of Z-vectors from current to wanted position + Transform3d rot = Transform3d::Identity(); + // Transformed unit vector Z direction (f)rom, (t)o + Vec3d z_f = m_surface_drag->volume_tr.linear() * Vec3d::UnitZ(); + Vec3d z_t = wanted_volume.linear() * Vec3d::UnitZ(); + z_f.normalize(); + z_t.normalize(); + double cos_angle = z_t.dot(z_f); + + // Calculate only when angle is not zero + if (cos_angle < 1. && cos_angle > -1.) { + m_surface_drag->from = from_position; + m_surface_drag->to = to_position; + m_surface_drag->from_dir = z_f; + m_surface_drag->to_dir = z_t; + + m_surface_drag->f_tr = current_world; + m_surface_drag->t_tr = wanted_world; + + // TODO: solve opposit direction of z_t and z_f (a.k.a. angle 180 DEG) + // if (cos_angle == 0.) {} + + // Calculate rotation axe from current to wanted inside instance + Vec3d axe = z_t.cross(z_f); + axe.normalize(); + double angle = acos(cos_angle); + rot = Eigen::AngleAxis(-angle, axe); + } + + // Calculate scale in world + auto calc_scale = [¤t_world_linear, wanted_world_linear](const Vec3d &dir) -> double { + Vec3d current = current_world_linear * dir; + Vec3d wanted = wanted_world_linear * dir; + double current_sq = current.squaredNorm(); + double wanted_sq = wanted.squaredNorm(); + return sqrt(wanted_sq / current_sq); + }; + double y_scale = calc_scale(Vec3d::UnitY()); + double z_scale = calc_scale(Vec3d::UnitZ()); + Transform3d scale(Eigen::Scaling(1., y_scale, z_scale)); + + Transform3d volume_tr = trnsl * m_surface_drag->volume_tr * rot; + + assert(volume_tr.matrix()(0,0) == volume_tr.matrix()(0,0)); // Check valid transformation not a NAN + Transform3d volume_tr2 = m_surface_drag->instance_inv * wanted_world; + + // Update transformation inside of instances for (GLVolume *vol : m_parent.get_volumes().volumes) { if (vol->object_idx() != m_surface_drag->gl_volume->object_idx() || vol->volume_idx() != m_surface_drag->gl_volume->volume_idx()) @@ -593,9 +662,6 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) m_parent.set_as_dirty(); return true; - } else if (mouse_event.LeftUp()) { - do_move(); - return true; } return false; } @@ -631,6 +697,23 @@ bool GLGizmoEmboss::on_init() std::string GLGizmoEmboss::on_get_name() const { return _u8L("Emboss"); } void GLGizmoEmboss::on_render() { + // Render debug view to surface move + if (m_surface_drag.has_value()) { + auto glvol = priv::get_gl_volume(m_parent.get_selection()); + auto tr = glvol->get_instance_transformation().get_matrix(); + CoordAxes from; + from.set_origin(m_surface_drag->from); + //from.render(tr, 2.); + + CoordAxes to; + to.set_origin(m_surface_drag->to); + //to.render(tr, 2.); + + CoordAxes axe; + axe.render(m_surface_drag->f_tr); + axe.render(m_surface_drag->t_tr); + } + // no volume selected if (m_volume == nullptr || priv::get_volume(m_parent.get_selection().get_model()->objects, m_volume_id) == nullptr) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index 0cfe34508e..610d10e720 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp @@ -316,11 +316,24 @@ private: // Help convert world transformation to instance space Transform3d instance_inv; + // Start dragging volume transformation + Transform3d volume_tr; + // Dragged gl volume GLVolume *gl_volume; // condition for raycaster RaycastManager::AllowVolumes condition; + + // Visuzalization + Vec3d from = Vec3d::Zero(); + Vec3d to = Vec3d::Zero(); + + Vec3d from_dir = Vec3d::UnitZ(); + Vec3d to_dir = Vec3d::UnitZ(); + + Transform3d f_tr = Transform3d::Identity(); + Transform3d t_tr = Transform3d::Identity(); }; // Keep data about dragging only during drag&drop std::optional m_surface_drag; From c1b480e57f8aafbcb7a68d6e71064c01265b94d0 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Tue, 7 Feb 2023 12:10:40 +0100 Subject: [PATCH 02/12] On rayCast miss add part simillar way as right panel do. Fix: https://github.com/prusa3d/PrusaSlicer/issues/9611 --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 28 ++++++++++++++++--------- src/slic3r/Utils/RaycastManager.hpp | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index b88705ad36..b7081b2104 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -229,13 +229,17 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mous GLVolume *gl_volume = priv::get_hovered_gl_volume(m_parent); DataBase emboss_data = priv::create_emboss_data_base(m_text, m_style_manager, m_job_cancel); - // Try to cast ray into scene and find object for add volume - if (priv::start_create_volume_on_surface_job(emboss_data, volume_type, mouse_pos, gl_volume, m_raycast_manager)) - // object found - return; - - // object is not under mouse position soo create object on plater - priv::start_create_object_job(emboss_data, mouse_pos); + if (gl_volume != nullptr) { + // Try to cast ray into scene and find object for add volume + if (!priv::start_create_volume_on_surface_job(emboss_data, volume_type, mouse_pos, gl_volume, m_raycast_manager)) { + // When model is broken. It could appear that hit miss the object. + // So add part near by in simmilar manner as right panel do + create_volume(volume_type); + } + } else { + // object is not under mouse position soo create object on plater + priv::start_create_object_job(emboss_data, mouse_pos); + } } // Designed for create volume without information of mouse in scene @@ -266,8 +270,9 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type) const GLVolume *vol = nullptr; const Camera &camera = wxGetApp().plater()->get_camera(); priv::find_closest_volume(selection, screen_center, camera, objects, &coor, &vol); - if (!priv::start_create_volume_on_surface_job(emboss_data, volume_type, coor, vol, m_raycast_manager)) { - assert(vol != nullptr); + if (vol == nullptr) { + priv::start_create_object_job(emboss_data, screen_center); + } else if (!priv::start_create_volume_on_surface_job(emboss_data, volume_type, coor, vol, m_raycast_manager)) { // in centroid of convex hull is not hit with object // soo create transfomation on border of object @@ -3924,7 +3929,9 @@ GLVolume * priv::get_hovered_gl_volume(const GLCanvas3D &canvas) { bool priv::start_create_volume_on_surface_job( DataBase &emboss_data, ModelVolumeType volume_type, const Vec2d &screen_coor, const GLVolume *gl_volume, RaycastManager &raycaster) { + assert(gl_volume != nullptr); if (gl_volume == nullptr) return false; + Plater *plater = wxGetApp().plater(); const ModelObjectPtrs &objects = plater->model().objects; @@ -3941,7 +3948,8 @@ bool priv::start_create_volume_on_surface_job( // 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 // also hit must exist. But there is options to add text by object list - if (!hit.has_value()) return false; + if (!hit.has_value()) + return false; Transform3d hit_object_trmat = raycaster.get_transformation(hit->tr_key); Transform3d hit_instance_trmat = gl_volume->get_instance_transformation().get_matrix(); diff --git a/src/slic3r/Utils/RaycastManager.hpp b/src/slic3r/Utils/RaycastManager.hpp index 94da384d2d..5451c4e92e 100644 --- a/src/slic3r/Utils/RaycastManager.hpp +++ b/src/slic3r/Utils/RaycastManager.hpp @@ -124,7 +124,7 @@ public: std::optional closest(const Vec3d &point, const ISkip *skip = nullptr) const; /// - /// Getter on transformation + /// Getter on transformation from hitted volume to world /// /// Define transformation /// Transformation for key From fb488e745b66e1805f937a9b8aff9faccfd7dc4f Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Tue, 7 Feb 2023 14:58:04 +0100 Subject: [PATCH 03/12] Allowe cast on surface of corrupted meshes. Skip filtration --> allowe move over surface under the bed --- src/slic3r/Utils/RaycastManager.cpp | 38 ++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/src/slic3r/Utils/RaycastManager.cpp b/src/slic3r/Utils/RaycastManager.cpp index 12fc3dfeda..be11c7f894 100644 --- a/src/slic3r/Utils/RaycastManager.cpp +++ b/src/slic3r/Utils/RaycastManager.cpp @@ -121,6 +121,33 @@ void RaycastManager::actualize(const ModelInstance *instance, const ISkip *skip) m_transformations.erase(m_transformations.begin() + i); } +#include "slic3r/GUI/CameraUtils.hpp" +namespace priv { + +// Copy functionality from MeshRaycaster::unproject_on_mesh without filtering +static std::optional unproject_on_mesh(const MeshRaycaster &raycaster, + const Vec2d &mouse_pos, const Transform3d &transformation, const Camera &camera) { + + Vec3d point; + Vec3d direction; + CameraUtils::ray_from_screen_pos(camera, mouse_pos, point, direction); + Transform3d inv = transformation.inverse(); + point = inv*point; + direction = inv.linear()*direction; + + const AABBMesh &aabb_mesh = raycaster.get_aabb_mesh(); + std::vector hits = aabb_mesh.query_ray_hits(point, direction); + + if (hits.empty()) + return {}; // no intersection found + + const AABBMesh::hit_result &hit = hits.front(); + return RaycastManager::SurfacePoint( + hit.position().cast(), + hit.normal().cast() + ); +} +} // namespace priv std::optional RaycastManager::unproject( const Vec2d &mouse_pos, const Camera &camera, const ISkip *skip) const @@ -137,12 +164,11 @@ std::optional RaycastManager::unproject( -> bool { return volume_id == it.first; }); if (raycaster_it == m_raycasters.end()) continue; const MeshRaycaster &raycaster = *(raycaster_it->second); - SurfacePoint surface_point; - bool success = raycaster.unproject_on_mesh( - mouse_pos, transformation, camera, - surface_point.position, surface_point.normal); - if (!success) continue; - + std::optional surface_point_opt = priv::unproject_on_mesh( + raycaster, mouse_pos, transformation, camera); + if (!surface_point_opt.has_value()) + continue; + const SurfacePoint &surface_point = *surface_point_opt; Vec3d act_hit_tr = transformation * surface_point.position.cast(); double squared_distance = (camera.get_position() - act_hit_tr).squaredNorm(); if (closest.has_value() && From 040f721873aefaa2707f8f61f6fbf83e625dd97d Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Tue, 7 Feb 2023 15:23:08 +0100 Subject: [PATCH 04/12] Fix translation mentioned by issue: https://github.com/prusa3d/PrusaSlicer/issues/9583 --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index b7081b2104..abdeec66e4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -1703,9 +1703,9 @@ void GLGizmoEmboss::draw_text_input() auto &ff = m_style_manager.get_font_file_with_cache(); float imgui_size = StyleManager::get_imgui_font_size(prop, *ff.font_file, scale); if (imgui_size > StyleManager::max_imgui_font_size) - append_warning(_u8L("To tall"), _u8L("Diminished font height inside text input.")); + append_warning(_u8L("Too tall"), _u8L("Diminished font height inside text input.")); if (imgui_size < StyleManager::min_imgui_font_size) - append_warning(_u8L("To small"), _u8L("Enlarged font height inside text input.")); + append_warning(_u8L("Too small"), _u8L("Enlarged font height inside text input.")); if (!who.empty()) warning = GUI::format(_L("%1% is NOT shown."), who); } From fc9bae667da0a32c6b0f6f72452eeeffd1bd300f Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Thu, 9 Feb 2023 09:12:09 +0100 Subject: [PATCH 05/12] separate calculation of rotation --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 162 ++++++++++++++---------- src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp | 4 +- 2 files changed, 97 insertions(+), 69 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index abdeec66e4..84ae365082 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -467,6 +467,41 @@ Vec2d priv::calc_mouse_to_center_text_offset(const Vec2d& mouse, const ModelVolu } return nearest_offset; } +namespace priv { + +static bool allign_z(const Vec3d &z_t, Transform3d &rotate) +{ + // Transformed unit vector Z direction (f)rom, (t)o + const Vec3d& z_f = Vec3d::UnitZ(); + Vec3d z_t_norm = z_t.normalized(); + double cos_angle = z_t_norm.dot(z_f); + + // Calculate rotation of Z-vectors from current to wanted position + rotate = Transform3d::Identity(); + + if (cos_angle == 0.) { + // check that direction is not same + if (z_t_norm.z() > 0.) + return false; + + // opposit direction of z_t and z_f (a.k.a. angle 180 DEG) + rotate = Eigen::AngleAxis(M_PI, Vec3d::UnitX()); + return true; + } else if (cos_angle >= 1. || cos_angle <= -1.) { + // bad cas angle value almost zero angle so no rotation + return false; + } + + // Calculate only when angle is not zero + // Calculate rotation axe from current to wanted inside instance + Vec3d axe = z_t_norm.cross(z_f); + axe.normalize(); + double angle = acos(cos_angle); + rotate = Eigen::AngleAxis(-angle, axe); + return true; +} + +} bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) { @@ -544,6 +579,11 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) Vec2d mouse_offset = priv::calc_mouse_to_center_text_offset(mouse_pos, *m_volume); Transform3d instance_inv = gl_volume->get_instance_transformation().get_matrix().inverse(); Transform3d volume_tr = gl_volume->get_volume_transformation().get_matrix(); + TextConfiguration &tc = *m_volume->text_configuration; + // fix baked transformation from .3mf store process + if (tc.fix_3mf_tr.has_value()) + volume_tr = volume_tr * tc.fix_3mf_tr->inverse(); + m_surface_drag = SurfaceDrag{mouse_offset, instance_inv, volume_tr, gl_volume, condition}; // Cancel job to prevent interuption of dragging (duplicit result) @@ -566,76 +606,38 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) Vec2d offseted_mouse = mouse_pos + m_surface_drag->mouse_offset; const Camera &camera = wxGetApp().plater()->get_camera(); auto hit = m_raycast_manager.unproject(offseted_mouse, camera, &m_surface_drag->condition); + m_surface_drag->exist_hit = hit.has_value(); if (!hit.has_value()) { // cross hair need redraw m_parent.set_as_dirty(); return true; } - // Calculate temporary position + // Calculate offset: transformation to wanted position Transform3d object_trmat = m_raycast_manager.get_transformation(hit->tr_key); - Transform3d trmat = create_transformation_onto_surface(hit->position, hit->normal); - - // !!!!!!!!!!!!!!!! USE DIRECT hit position and normal - - //TextConfiguration &tc = *m_volume->text_configuration; - //const FontProp& font_prop = tc.style.prop; - //apply_transformation(font_prop, trmat); - - //// fix baked transformation from .3mf store process - //if (tc.fix_3mf_tr.has_value()) - // trmat = trmat * (*tc.fix_3mf_tr); - - // volume transfomration in world coor - Transform3d wanted_world = object_trmat * trmat; - Transform3d wanted_volume = m_surface_drag->instance_inv * wanted_world; - - // Calculate offset inside instance: - // transformation from curret to wanted position - Vec3d from_position = m_surface_drag->volume_tr * Vec3d::Zero(); - Vec3d to_position = wanted_volume * Vec3d::Zero(); - Transform3d hit_to_instance = object_trmat * m_surface_drag->instance_inv; - Vec3d to_position2 = hit_to_instance * hit->position.cast(); - Vec3d z_t2 = hit_to_instance.linear() * hit->normal.cast(); + Transform3d hit_to_volume = hit_to_instance * m_surface_drag->volume_tr.inverse(); + Vec3d offset_volume = hit_to_volume * hit->position.cast(); + Transform3d translate{Eigen::Translation(offset_volume)}; - Vec3d offset_instance = to_position - from_position; - Transform3d trnsl{Eigen::Translation(offset_instance)}; + Transform3d rotate; + // normal transformed to volume + Vec3d z_t = hit_to_volume.linear() * hit->normal.cast(); + bool exist_rotate = priv::allign_z(z_t, rotate); + Transform3d volume_tr = m_surface_drag->volume_tr * translate * rotate; + assert(volume_tr.matrix()(0, 0) == volume_tr.matrix()(0, 0)); // Check valid transformation not a NAN + if (volume_tr.matrix()(0, 0) != volume_tr.matrix()(0, 0)) + return true; + + // Check scale in world + // current transformation from volume to world Transform3d current_world = m_surface_drag->instance_inv.inverse() * m_surface_drag->volume_tr; - auto current_world_linear = current_world.linear(); - auto wanted_world_linear = wanted_world.linear(); - // Calculate rotation of Z-vectors from current to wanted position - Transform3d rot = Transform3d::Identity(); - // Transformed unit vector Z direction (f)rom, (t)o - Vec3d z_f = m_surface_drag->volume_tr.linear() * Vec3d::UnitZ(); - Vec3d z_t = wanted_volume.linear() * Vec3d::UnitZ(); - z_f.normalize(); - z_t.normalize(); - double cos_angle = z_t.dot(z_f); - - // Calculate only when angle is not zero - if (cos_angle < 1. && cos_angle > -1.) { - m_surface_drag->from = from_position; - m_surface_drag->to = to_position; - m_surface_drag->from_dir = z_f; - m_surface_drag->to_dir = z_t; - - m_surface_drag->f_tr = current_world; - m_surface_drag->t_tr = wanted_world; - - // TODO: solve opposit direction of z_t and z_f (a.k.a. angle 180 DEG) - // if (cos_angle == 0.) {} - - // Calculate rotation axe from current to wanted inside instance - Vec3d axe = z_t.cross(z_f); - axe.normalize(); - double angle = acos(cos_angle); - rot = Eigen::AngleAxis(-angle, axe); - } + Transform3d wanted_world = m_surface_drag->instance_inv.inverse() * volume_tr; + auto wanted_world_linear = wanted_world.linear(); // Calculate scale in world auto calc_scale = [¤t_world_linear, wanted_world_linear](const Vec3d &dir) -> double { @@ -643,18 +645,32 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) Vec3d wanted = wanted_world_linear * dir; double current_sq = current.squaredNorm(); double wanted_sq = wanted.squaredNorm(); - return sqrt(wanted_sq / current_sq); + return sqrt(current_sq / wanted_sq); }; double y_scale = calc_scale(Vec3d::UnitY()); double z_scale = calc_scale(Vec3d::UnitZ()); Transform3d scale(Eigen::Scaling(1., y_scale, z_scale)); + volume_tr = volume_tr * scale; - Transform3d volume_tr = trnsl * m_surface_drag->volume_tr * rot; + // recalculate rotation for scaled volume + //Transform3d hit_to_volume2 = hit_to_instance * (m_surface_drag->volume_tr*scale).inverse(); + //z_t = hit_to_volume2.linear() * hit->normal.cast(); + //bool exist_rotate2 = priv::allign_z(z_t, rotate); + //volume_tr = m_surface_drag->volume_tr * translate * rotate * scale; - assert(volume_tr.matrix()(0,0) == volume_tr.matrix()(0,0)); // Check valid transformation not a NAN - Transform3d volume_tr2 = m_surface_drag->instance_inv * wanted_world; + const TextConfiguration &tc = *m_volume->text_configuration; + // fix baked transformation from .3mf store process + if (tc.fix_3mf_tr.has_value()) + volume_tr = volume_tr * (*tc.fix_3mf_tr); - // Update transformation inside of instances + // apply move in Z direction for move with flat surface above texture + const FontProp &prop = tc.style.prop; + if (!prop.use_surface && prop.distance.has_value()) { + Vec3d translate = Vec3d::UnitZ() * (*prop.distance); + volume_tr.translate(translate); + } + + // Update transformation forf all instances for (GLVolume *vol : m_parent.get_volumes().volumes) { if (vol->object_idx() != m_surface_drag->gl_volume->object_idx() || vol->volume_idx() != m_surface_drag->gl_volume->volume_idx()) @@ -662,7 +678,7 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) vol->set_volume_transformation(volume_tr); } - // calculate scale + // update scale of selected volume --> should be approx the same calculate_scale(); m_parent.set_as_dirty(); @@ -862,7 +878,13 @@ void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit) ImVec2 center( mouse_pos.x + m_surface_drag->mouse_offset.x(), mouse_pos.y + m_surface_drag->mouse_offset.y()); - priv::draw_cross_hair(center); + ImU32 color = ImGui::GetColorU32( + m_surface_drag->exist_hit ? + ImVec4(1.f, 1.f, 1.f, .75f) : // transparent white + ImVec4(1.f, .3f, .3f, .75f) + ); // Warning color + const float radius = 16.f; + priv::draw_cross_hair(center, radius, color); } #ifdef SHOW_FINE_POSITION @@ -1115,18 +1137,22 @@ GLGizmoEmboss::GuiCfg GLGizmoEmboss::create_gui_configuration() EmbossStyles GLGizmoEmboss::create_default_styles() { wxFont wx_font_normal = *wxNORMAL_FONT; - wxFont wx_font_small = *wxSMALL_FONT; - #ifdef __APPLE__ - wx_font_normal.SetFaceName("Helvetica"); - wx_font_small.SetFaceName("Helvetica"); + // Set normal font to helvetica when possible + wxArrayString facenames = wxFontEnumerator::GetFacenames(Facenames::encoding); + for (const wxString &facename : facenames) { + if (facename.IsSameAs("Helvetica")) { + wx_font_normal = wxFont(wxFontInfo().FaceName(facename).Encoding(Facenames::encoding)); + break; + } + } #endif // __APPLE__ // https://docs.wxwidgets.org/3.0/classwx_font.html // Predefined objects/pointers: wxNullFont, wxNORMAL_FONT, wxSMALL_FONT, wxITALIC_FONT, wxSWISS_FONT EmbossStyles styles = { WxFontUtils::create_emboss_style(wx_font_normal, _u8L("NORMAL")), // wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) - WxFontUtils::create_emboss_style(wx_font_normal, _u8L("SMALL")), // A font using the wxFONTFAMILY_SWISS family and 2 points smaller than wxNORMAL_FONT. + WxFontUtils::create_emboss_style(*wxSMALL_FONT, _u8L("SMALL")), // A font using the wxFONTFAMILY_SWISS family and 2 points smaller than wxNORMAL_FONT. WxFontUtils::create_emboss_style(*wxITALIC_FONT, _u8L("ITALIC")), // A font using the wxFONTFAMILY_ROMAN family and wxFONTSTYLE_ITALIC style and of the same size of wxNORMAL_FONT. WxFontUtils::create_emboss_style(*wxSWISS_FONT, _u8L("SWISS")), // A font identic to wxNORMAL_FONT except for the family used which is wxFONTFAMILY_SWISS. WxFontUtils::create_emboss_style(wxFont(10, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD), _u8L("MODERN")), diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index 610d10e720..0c9b3b98ed 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp @@ -255,7 +255,7 @@ private: std::vector bad = {}; // Configuration of font encoding - const wxFontEncoding encoding = wxFontEncoding::wxFONTENCODING_SYSTEM; + static const wxFontEncoding encoding = wxFontEncoding::wxFONTENCODING_SYSTEM; // Identify if preview texture exists GLuint texture_id = 0; @@ -325,6 +325,8 @@ private: // condition for raycaster RaycastManager::AllowVolumes condition; + bool exist_hit = true; + // Visuzalization Vec3d from = Vec3d::Zero(); Vec3d to = Vec3d::Zero(); From 88af7762fcd766343425672c08e4f90db0c76632 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Mon, 13 Feb 2023 12:07:31 +0100 Subject: [PATCH 06/12] Remove dependency on main app in job --- .../GUI/Jobs/CreateFontStyleImagesJob.cpp | 57 ++++++++----------- .../GUI/Jobs/CreateFontStyleImagesJob.hpp | 6 +- src/slic3r/Utils/EmbossStyleManager.cpp | 16 +++++- src/slic3r/Utils/EmbossStyleManager.hpp | 3 + 4 files changed, 43 insertions(+), 39 deletions(-) diff --git a/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp b/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp index d1a671330a..8aa9e23cb9 100644 --- a/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp +++ b/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp @@ -2,11 +2,6 @@ // rasterization of ExPoly #include "libslic3r/SLA/AGGRaster.hpp" - -// for get DPI -#include "slic3r/GUI/GUI_App.hpp" -#include "slic3r/GUI/MainFrame.hpp" - #include "slic3r/GUI/3DScene.hpp" // ::glsafe // ability to request new frame after finish rendering @@ -20,15 +15,15 @@ using namespace Slic3r::GUI; using namespace Slic3r::GUI::Emboss; -CreateFontStyleImagesJob::CreateFontStyleImagesJob( - StyleManager::StyleImagesData &&input) - : m_input(std::move(input)) +CreateFontStyleImagesJob::CreateFontStyleImagesJob(StyleManager::StyleImagesData &&input) + : m_input(std::move(input)), m_width(0), m_height(0) { assert(m_input.result != nullptr); assert(!m_input.styles.empty()); assert(!m_input.text.empty()); assert(m_input.max_size.x() > 1); assert(m_input.max_size.y() > 1); + assert(m_input.ppm > 1e-5); } void CreateFontStyleImagesJob::process(Ctl &ctl) @@ -36,7 +31,7 @@ void CreateFontStyleImagesJob::process(Ctl &ctl) // create shapes and calc size (bounding boxes) std::vector name_shapes(m_input.styles.size()); std::vector scales(m_input.styles.size()); - images = std::vector(m_input.styles.size()); + m_images = std::vector(m_input.styles.size()); for (auto &item : m_input.styles) { size_t index = &item - &m_input.styles.front(); @@ -44,21 +39,17 @@ void CreateFontStyleImagesJob::process(Ctl &ctl) shapes = text2shapes(item.font, m_input.text.c_str(), item.prop); // create image description - StyleManager::StyleImage &image = images[index]; + StyleManager::StyleImage &image = m_images[index]; BoundingBox &bounding_box = image.bounding_box; for (ExPolygon &shape : shapes) bounding_box.merge(BoundingBox(shape.contour.points)); for (ExPolygon &shape : shapes) shape.translate(-bounding_box.min); // calculate conversion from FontPoint to screen pixels by size of font - auto mf = wxGetApp().mainframe; - // dot per inch for monitor - int dpi = get_dpi_for_window(mf); - double ppm = dpi / 25.4; // pixel per milimeter const auto &cn = item.prop.collection_number; unsigned int font_index = (cn.has_value()) ? *cn : 0; double unit_per_em = item.font.font_file->infos[font_index].unit_per_em; - double scale = item.prop.size_in_mm / unit_per_em * SHAPE_SCALE * ppm; + double scale = item.prop.size_in_mm / unit_per_em * SHAPE_SCALE * m_input.ppm; scales[index] = scale; //double scale = font_prop.size_in_mm * SCALING_FACTOR; @@ -78,30 +69,30 @@ void CreateFontStyleImagesJob::process(Ctl &ctl) // arrange bounding boxes int offset_y = 0; - width = 0; - for (StyleManager::StyleImage &image : images) { + m_width = 0; + for (StyleManager::StyleImage &image : m_images) { image.offset.y() = offset_y; offset_y += image.tex_size.y+1; - if (width < image.tex_size.x) - width = image.tex_size.x; + if (m_width < image.tex_size.x) + m_width = image.tex_size.x; } - height = offset_y; - for (StyleManager::StyleImage &image : images) { + m_height = offset_y; + for (StyleManager::StyleImage &image : m_images) { const Point &o = image.offset; const ImVec2 &s = image.tex_size; - image.uv0 = ImVec2(o.x() / (double) width, - o.y() / (double) height); - image.uv1 = ImVec2((o.x() + s.x) / (double) width, - (o.y() + s.y) / (double) height); + image.uv0 = ImVec2(o.x() / (double) m_width, + o.y() / (double) m_height); + image.uv1 = ImVec2((o.x() + s.x) / (double) m_width, + (o.y() + s.y) / (double) m_height); } // Set up result - pixels = std::vector(4*width * height, {255}); + m_pixels = std::vector(4 * m_width * m_height, {255}); // upload sub textures - for (StyleManager::StyleImage &image : images) { + for (StyleManager::StyleImage &image : m_images) { sla::Resolution resolution(image.tex_size.x, image.tex_size.y); - size_t index = &image - &images.front(); + size_t index = &image - &m_images.front(); double pixel_dim = SCALING_FACTOR / scales[index]; sla::PixelDim dim(pixel_dim, pixel_dim); double gamma = 1.; @@ -110,7 +101,7 @@ void CreateFontStyleImagesJob::process(Ctl &ctl) for (const ExPolygon &shape : name_shapes[index]) r->draw(shape); // copy rastered data to pixels - sla::RasterEncoder encoder = [&offset = image.offset, &pix = pixels, w=width,h=height] + sla::RasterEncoder encoder = [&offset = image.offset, &pix = m_pixels, w=m_width,h=m_height] (const void *ptr, size_t width, size_t height, size_t num_components) { // bigger value create darker image unsigned char gray_level = 5; @@ -142,18 +133,18 @@ void CreateFontStyleImagesJob::finalize(bool canceled, std::exception_ptr &) glsafe(::glBindTexture(target, tex_id)); glsafe(::glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); glsafe(::glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); - GLint w = width, h=height; + GLint w = m_width, h = m_height; glsafe(::glTexImage2D(target, level, GL_RGBA, w, h, border, format, type, - (const void *) pixels.data())); + (const void *) m_pixels.data())); // set up texture id void *texture_id = (void *) (intptr_t) tex_id; - for (StyleManager::StyleImage &image : images) + for (StyleManager::StyleImage &image : m_images) image.texture_id = texture_id; // move to result m_input.result->styles = std::move(m_input.styles); - m_input.result->images = std::move(images); + m_input.result->images = std::move(m_images); // bind default texture GLuint no_texture_id = 0; diff --git a/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.hpp b/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.hpp index c220f2ee01..b8c2757a62 100644 --- a/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.hpp +++ b/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.hpp @@ -19,11 +19,11 @@ class CreateFontStyleImagesJob : public Job // Output data // texture size - int width, height; + int m_width, m_height; // texture data - std::vector pixels; + std::vector m_pixels; // descriptors of sub textures - std::vector images; + std::vector m_images; public: CreateFontStyleImagesJob(StyleManager::StyleImagesData &&input); diff --git a/src/slic3r/Utils/EmbossStyleManager.cpp b/src/slic3r/Utils/EmbossStyleManager.cpp index 9c6738ece3..af1aae669f 100644 --- a/src/slic3r/Utils/EmbossStyleManager.cpp +++ b/src/slic3r/Utils/EmbossStyleManager.cpp @@ -304,12 +304,15 @@ void StyleManager::init_trunc_names(float max_width) { } } -#include "slic3r/GUI/Jobs/CreateFontStyleImagesJob.hpp" - // for access to worker #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/Plater.hpp" +// for get DPI +#include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/MainFrame.hpp" +#include "slic3r/GUI/GUI_ObjectManipulation.hpp" + void StyleManager::init_style_images(const Vec2i &max_size, const std::string &text) { @@ -361,8 +364,15 @@ void StyleManager::init_style_images(const Vec2i &max_size, style.prop }); } + + auto mf = wxGetApp().mainframe; + // dot per inch for monitor + int dpi = get_dpi_for_window(mf); + // pixel per milimeter + double ppm = dpi / ObjectManipulation::in_to_mm; + auto &worker = wxGetApp().plater()->get_ui_job_worker(); - StyleImagesData data{std::move(styles), max_size, text, m_temp_style_images}; + StyleImagesData data{std::move(styles), max_size, text, m_temp_style_images, ppm}; queue_job(worker, std::make_unique(std::move(data))); } diff --git a/src/slic3r/Utils/EmbossStyleManager.hpp b/src/slic3r/Utils/EmbossStyleManager.hpp index 8183214e95..08fa72642b 100644 --- a/src/slic3r/Utils/EmbossStyleManager.hpp +++ b/src/slic3r/Utils/EmbossStyleManager.hpp @@ -277,6 +277,9 @@ private: // place to store result in main thread in Finalize std::shared_ptr result; + + // pixel per milimeter (scaled DPI) + double ppm; }; std::shared_ptr m_temp_style_images; bool m_exist_style_images; From f42ae64277069c5fd3cd641cd845a4d59aae6097 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Tue, 14 Feb 2023 16:06:59 +0100 Subject: [PATCH 07/12] Change Text property after move over surface when world size is changed(re-create text volume). NOTE: Not intuitive during dragging. --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 348 +++++++++++++++++++----- src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp | 8 + 2 files changed, 290 insertions(+), 66 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 84ae365082..e602bbd76c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -467,21 +467,20 @@ Vec2d priv::calc_mouse_to_center_text_offset(const Vec2d& mouse, const ModelVolu } return nearest_offset; } -namespace priv { -static bool allign_z(const Vec3d &z_t, Transform3d &rotate) +namespace priv { +static bool allign_vec(const Vec3d &z_f, const Vec3d &z_t, Transform3d &rotate) { - // Transformed unit vector Z direction (f)rom, (t)o - const Vec3d& z_f = Vec3d::UnitZ(); - Vec3d z_t_norm = z_t.normalized(); - double cos_angle = z_t_norm.dot(z_f); + Vec3d z_f_norm = z_f.normalized(); + Vec3d z_t_norm = z_t.normalized(); + double cos_angle = z_t_norm.dot(z_f_norm); // Calculate rotation of Z-vectors from current to wanted position rotate = Transform3d::Identity(); if (cos_angle == 0.) { // check that direction is not same - if (z_t_norm.z() > 0.) + if (z_t_norm.z() > 0.) return false; // opposit direction of z_t and z_f (a.k.a. angle 180 DEG) @@ -494,13 +493,187 @@ static bool allign_z(const Vec3d &z_t, Transform3d &rotate) // Calculate only when angle is not zero // Calculate rotation axe from current to wanted inside instance - Vec3d axe = z_t_norm.cross(z_f); + Vec3d axe = z_t_norm.cross(z_f_norm); axe.normalize(); double angle = acos(cos_angle); - rotate = Eigen::AngleAxis(-angle, axe); + rotate = Eigen::AngleAxis(-angle, axe); return true; } +static bool allign_z(const Vec3d &z_t, Transform3d &rotate) +{ + // Transformed unit vector Z direction (f)rom, (t)o + const Vec3d& z_f = Vec3d::UnitZ(); + return allign_vec(Vec3d::UnitZ(), z_t, rotate); +} + + // Calculate scale in world +static std::optional calc_scale(const Matrix3d &from, const Matrix3d &to, const Vec3d &dir) +{ + Vec3d from_dir = from * dir; + Vec3d to_dir = to * dir; + double from_scale_sq = from_dir.squaredNorm(); + double to_scale_sq = to_dir.squaredNorm(); + if (is_approx(from_scale_sq, to_scale_sq, 1e-3)) + return {}; // no scale + return sqrt(from_scale_sq / to_scale_sq); +}; + +// Copy from branch et_transformation --> Geometry +// suggested by @bubnikv +void reset_skew(Transform3d& m) +{ + auto new_scale_factor = [](const Matrix3d& s) { + return pow(s(0, 0) * s(1, 1) * s(2, 2), 1. / 3.); // scale average + }; + + const Eigen::JacobiSVD svd(m.linear(), Eigen::ComputeFullU | Eigen::ComputeFullV); + Matrix3d u = svd.matrixU(); + Matrix3d v = svd.matrixV(); + Matrix3d s = svd.singularValues().asDiagonal(); + + //Matrix3d mirror; + m = Eigen::Translation3d(m.translation()) * Transform3d(u * Eigen::Scaling(new_scale_factor(s)) * v.transpose());// * mirror; +} + +// Multiply from right +static Transform3d surface_transformR(const Vec3d &p, const Vec3d &n, const Transform3d &v, const Transform3d &i) { + Transform3d to_volume = (i * v).inverse(); + Vec3d offset_volume = to_volume * p; + Transform3d translate{Eigen::Translation(offset_volume)}; + + Transform3d rotate; + // normal transformed to volume + Vec3d z_t = to_volume.linear() * n; + bool exist_rotate = priv::allign_z(z_t, rotate); + return v * translate * rotate; +} + +/// +/// Create transformation for volume to move over surface +/// Multiply from Left side - NOT WORK - with scaled instances +/// +/// Point in world coordinate +/// Normal in world coordinate - orientation +/// Original volume transformation +/// Instance transformation +/// Transformation of volume to lay on surface +static Transform3d surface_transformL(const Vec3d &p, const Vec3d &n, const Transform3d &v, const Transform3d &i) { + // w .. original world + Transform3d w = i * v; + + // remove already existing of skew before calc rotation + // priv::reset_skew(w); + + // z .. unit z vector in world coordinate + Vec3d z = w.linear() * Vec3d::UnitZ(); + Transform3d rot = Transform3d::Identity(); + bool exist_rot = priv::allign_vec(z, n, rot); + + // rot_w .. new rotation applied on world + Transform3d rot_w = rot * w; + + // p0 .. Zero of volume in world + Vec3d p0 = rot_w * Vec3d::Zero(); + Vec3d offset = p - p0; // in world + Transform3d tr{Eigen::Translation(offset)}; + + // w2 .. wanted world transformation + Transform3d w2 = tr * rot_w; + + //priv::reset_skew(w2); + + // _ .. inverse + // i_ .. instance inverse + Transform3d i_ = i.inverse(); + + // w = i * v \\ left multiply by i_ + // i_ * w = i_ * i * v + // v = i_ * w + return i_ * w2; + // NOTE: Do not keep scale of text when move over scaled instance +} + +// transformation inside of instance +static Transform3d surface_transform2(const Vec3d &p, const Vec3d &n, const Transform3d &v, const Transform3d &i) +{ + // _ .. inverse + // i_ .. instance inverse + Transform3d i_ = i.inverse(); + Vec3d pp = i_ * p; + Vec3d nn = i_.linear() * n.normalized(); + nn.normalize(); + + // z .. unit z vector in world coordinate + Vec3d z = v * Vec3d::UnitZ(); + z.normalize(); + + Transform3d rot = Transform3d::Identity(); + bool exist_rot = priv::allign_vec(z, nn, rot); + + // rot_w .. new rotation applied on world + Transform3d rotated = rot * v; + + // p0 .. Zero of volume in world + Vec3d p0 = rotated * Vec3d::Zero(); + Vec3d offset = pp - p0; // in world + Transform3d tr{Eigen::Translation(offset)}; + Transform3d volume_new = tr * rotated; + //return volume_new; + + // Remove skew in world + Transform3d world_new = i * volume_new; + reset_skew(world_new); + volume_new = i_ * world_new; + + return volume_new; +} + +// work in space defined by SVD +static Transform3d surface_transform3(const Vec3d &p, const Vec3d &n, const Transform3d &v, const Transform3d &i) { + // w .. original world + Transform3d w = i * v; + + const Eigen::JacobiSVD svd1(w.linear(), Eigen::ComputeFullU | Eigen::ComputeFullV); + Matrix3d u1 = svd1.matrixU(); + Matrix3d v1 = svd1.matrixV(); + Matrix3d s1 = svd1.singularValues().asDiagonal(); + Transform3d tr1(Eigen::Translation3d(w.translation())); + //Transform3d test = tr1 * Transform3d(u1 * s1 * v1.transpose()); + + // modification of world + Transform3d mod(s1 * v1.transpose()); + Transform3d mod_ = mod.inverse(); + Transform3d w_mod = w * mod_; + + Vec3d nn = mod_.linear() * n; + // z .. unit z vector in world coordinate + Vec3d z = w_mod.linear() * Vec3d::UnitZ(); + Transform3d rot = Transform3d::Identity(); + bool exist_rot = priv::allign_vec(z, nn, rot); + + // rot_w .. new rotation applied on world + Transform3d rot_w = rot * w; + + // p0 .. Zero of volume in world + Vec3d p0 = rot_w * Vec3d::Zero(); + Vec3d offset = p - p0; // in world + Transform3d tr{Eigen::Translation(offset)}; + + // w2 .. wanted world transformation + Transform3d w2 = tr * rot_w; + + // _ .. inverse + // i_ .. instance inverse + Transform3d i_ = i.inverse(); + + // w = i * v \\ left multiply by i_ + // i_ * w = i_ * i * v + // v = i_ * w + return i_ * w2; + // NOTE: Do not keep scale of text when move over scaled instance +} + } bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) @@ -512,7 +685,19 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) m_parent.do_move(L("Surface move")); // Update surface by new position - if (m_volume->text_configuration->style.prop.use_surface) + bool need_process = m_volume->text_configuration->style.prop.use_surface; + + if (m_surface_drag->y_scale.has_value()) { + m_style_manager.get_style().prop.size_in_mm *= (*m_surface_drag->y_scale); + need_process |= set_height(); + } + + if (m_surface_drag->z_scale.has_value()) { + m_style_manager.get_style().prop.emboss *= (*m_surface_drag->z_scale); + need_process |= set_depth(); + } + + if (need_process) process(); // calculate scale @@ -612,45 +797,52 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) m_parent.set_as_dirty(); return true; } - // Calculate offset: transformation to wanted position - Transform3d object_trmat = m_raycast_manager.get_transformation(hit->tr_key); - Transform3d hit_to_instance = object_trmat * m_surface_drag->instance_inv; + Transform3d hit_to_world = m_raycast_manager.get_transformation(hit->tr_key); + //priv::reset_skew(hit_to_world); + + Transform3d hit_to_instance = hit_to_world * m_surface_drag->instance_inv; Transform3d hit_to_volume = hit_to_instance * m_surface_drag->volume_tr.inverse(); - Vec3d offset_volume = hit_to_volume * hit->position.cast(); + + Vec3d hit_position = hit->position.cast(); + Vec3d offset_volume = hit_to_volume * hit_position; Transform3d translate{Eigen::Translation(offset_volume)}; Transform3d rotate; // normal transformed to volume - Vec3d z_t = hit_to_volume.linear() * hit->normal.cast(); + Vec3d hit_normal = hit->normal.cast(); + Vec3d z_t = hit_to_volume.linear() * hit_normal; bool exist_rotate = priv::allign_z(z_t, rotate); + // Edit position from right + Transform3d volume_new = m_surface_drag->volume_tr * translate * rotate; - Transform3d volume_tr = m_surface_drag->volume_tr * translate * rotate; - assert(volume_tr.matrix()(0, 0) == volume_tr.matrix()(0, 0)); // Check valid transformation not a NAN - if (volume_tr.matrix()(0, 0) != volume_tr.matrix()(0, 0)) + const Transform3d &instance = m_surface_drag->gl_volume->get_instance_transformation().get_matrix(); + const Transform3d &volume = m_surface_drag->volume_tr; + + Vec3d hit_position_world = hit_to_world * hit_position; + Vec3d hit_normal_world = hit_to_world.linear() * hit_normal; + + // REWRITE transformation + Transform3d volume_R = priv::surface_transformR(hit_position_world, hit_normal_world, volume, instance); + Transform3d volume_L = priv::surface_transformL(hit_position_world, hit_normal_world, volume, instance); + Transform3d volume_2 = priv::surface_transform2(hit_position_world, hit_normal_world, volume, instance); + Transform3d volume_3 = priv::surface_transform3(hit_position_world, hit_normal_world, volume, instance); + //volume_new = volume_L; + + assert(volume_new.matrix()(0, 0) == volume_new.matrix()(0, 0)); // Check valid transformation not a NAN + if (volume_new.matrix()(0, 0) != volume_new.matrix()(0, 0)) return true; // Check scale in world - - // current transformation from volume to world - Transform3d current_world = m_surface_drag->instance_inv.inverse() * m_surface_drag->volume_tr; + // Calculate Scale to keep size after move over scaled surface + Transform3d current_world = instance * volume; auto current_world_linear = current_world.linear(); - Transform3d wanted_world = m_surface_drag->instance_inv.inverse() * volume_tr; + Transform3d wanted_world = instance * volume_new; auto wanted_world_linear = wanted_world.linear(); - // Calculate scale in world - auto calc_scale = [¤t_world_linear, wanted_world_linear](const Vec3d &dir) -> double { - Vec3d current = current_world_linear * dir; - Vec3d wanted = wanted_world_linear * dir; - double current_sq = current.squaredNorm(); - double wanted_sq = wanted.squaredNorm(); - return sqrt(current_sq / wanted_sq); - }; - double y_scale = calc_scale(Vec3d::UnitY()); - double z_scale = calc_scale(Vec3d::UnitZ()); - Transform3d scale(Eigen::Scaling(1., y_scale, z_scale)); - volume_tr = volume_tr * scale; + m_surface_drag->y_scale = priv::calc_scale(current_world_linear, wanted_world_linear, Vec3d::UnitY()); + m_surface_drag->z_scale = priv::calc_scale(current_world_linear, wanted_world_linear, Vec3d::UnitZ()); // recalculate rotation for scaled volume //Transform3d hit_to_volume2 = hit_to_instance * (m_surface_drag->volume_tr*scale).inverse(); @@ -661,13 +853,13 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) const TextConfiguration &tc = *m_volume->text_configuration; // fix baked transformation from .3mf store process if (tc.fix_3mf_tr.has_value()) - volume_tr = volume_tr * (*tc.fix_3mf_tr); + volume_new = volume_new * (*tc.fix_3mf_tr); // apply move in Z direction for move with flat surface above texture const FontProp &prop = tc.style.prop; if (!prop.use_surface && prop.distance.has_value()) { Vec3d translate = Vec3d::UnitZ() * (*prop.distance); - volume_tr.translate(translate); + volume_new.translate(translate); } // Update transformation forf all instances @@ -675,7 +867,7 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) if (vol->object_idx() != m_surface_drag->gl_volume->object_idx() || vol->volume_idx() != m_surface_drag->gl_volume->volume_idx()) continue; - vol->set_volume_transformation(volume_tr); + vol->set_volume_transformation(volume_new); } // update scale of selected volume --> should be approx the same @@ -1136,10 +1328,12 @@ GLGizmoEmboss::GuiCfg GLGizmoEmboss::create_gui_configuration() EmbossStyles GLGizmoEmboss::create_default_styles() { + wxFontEnumerator::InvalidateCache(); + wxArrayString facenames = wxFontEnumerator::GetFacenames(Facenames::encoding); + wxFont wx_font_normal = *wxNORMAL_FONT; #ifdef __APPLE__ // Set normal font to helvetica when possible - wxArrayString facenames = wxFontEnumerator::GetFacenames(Facenames::encoding); for (const wxString &facename : facenames) { if (facename.IsSameAs("Helvetica")) { wx_font_normal = wxFont(wxFontInfo().FaceName(facename).Encoding(Facenames::encoding)); @@ -1181,7 +1375,6 @@ EmbossStyles GLGizmoEmboss::create_default_styles() // No valid style in defult list // at least one style must contain loadable font - wxArrayString facenames = wxFontEnumerator::GetFacenames(wxFontEncoding::wxFONTENCODING_SYSTEM); wxFont wx_font; for (const wxString &face : facenames) { wx_font = wxFont(face); @@ -3082,6 +3275,31 @@ void GLGizmoEmboss::draw_style_edit() { #endif // SHOW_WX_WEIGHT_INPUT } +bool GLGizmoEmboss::set_height() { + float &value = m_style_manager.get_style().prop.size_in_mm; + + // size can't be zero or negative + priv::Limits::apply(value, priv::limits.size_in_mm); + + if (m_volume == nullptr || !m_volume->text_configuration.has_value()) { + assert(false); + return false; + } + + // only different value need process + if (is_approx(value, m_volume->text_configuration->style.prop.size_in_mm)) + return false; + + // store font size into path serialization + const std::optional &wx_font_opt = m_style_manager.get_wx_font(); + if (wx_font_opt.has_value()) { + wxFont wx_font = *wx_font_opt; + wx_font.SetPointSize(static_cast(value)); + m_style_manager.set_wx_font(wx_font); + } + return true; +} + void GLGizmoEmboss::draw_height(bool use_inch) { float &value = m_style_manager.get_style().prop.size_in_mm; @@ -3090,24 +3308,21 @@ void GLGizmoEmboss::draw_height(bool use_inch) const char *size_format = ((use_inch) ? "%.2f in" : "%.1f mm"); const std::string revert_text_size = _u8L("Revert text size."); const std::string& name = m_gui_cfg->translations.size; - if (rev_input_mm(name, value, stored, revert_text_size, 0.1f, 1.f, size_format, use_inch, m_scale_height)) { - // size can't be zero or negative - priv::Limits::apply(value, priv::limits.size_in_mm); - // only different value need process - if (!is_approx(value, m_volume->text_configuration->style.prop.size_in_mm)) { - // store font size into path - EmbossStyle &style = m_style_manager.get_style(); - if (style.type == WxFontUtils::get_actual_type()) { - const std::optional &wx_font_opt = m_style_manager.get_wx_font(); - if (wx_font_opt.has_value()) { - wxFont wx_font = *wx_font_opt; - wx_font.SetPointSize(static_cast(value)); - m_style_manager.set_wx_font(wx_font); - } - } + if (rev_input_mm(name, value, stored, revert_text_size, 0.1f, 1.f, size_format, use_inch, m_scale_height)) + if (set_height()) process(); - } - } +} + + +bool GLGizmoEmboss::set_depth() +{ + float &value = m_style_manager.get_style().prop.emboss; + + // size can't be zero or negative + priv::Limits::apply(value, priv::limits.emboss); + + // only different value need process + return !is_approx(value, m_volume->text_configuration->style.prop.emboss); } void GLGizmoEmboss::draw_depth(bool use_inch) @@ -3118,11 +3333,9 @@ void GLGizmoEmboss::draw_depth(bool use_inch) const std::string revert_emboss_depth = _u8L("Revert embossed depth."); const char *size_format = ((use_inch) ? "%.3f in" : "%.2f mm"); const std::string name = m_gui_cfg->translations.depth; - if (rev_input_mm(name, value, stored, revert_emboss_depth, 0.1f, 1.f, size_format, use_inch, m_scale_depth)) { - // size can't be zero or negative - priv::Limits::apply(value, priv::limits.emboss); - process(); - } + if (rev_input_mm(name, value, stored, revert_emboss_depth, 0.1f, 1.f, size_format, use_inch, m_scale_depth)) + if (set_depth()) + process(); } @@ -3977,14 +4190,17 @@ bool priv::start_create_volume_on_surface_job( if (!hit.has_value()) return false; - Transform3d hit_object_trmat = raycaster.get_transformation(hit->tr_key); - Transform3d hit_instance_trmat = gl_volume->get_instance_transformation().get_matrix(); + Transform3d hit_to_world = raycaster.get_transformation(hit->tr_key); + // priv::reset_skew(hit_to_world); + Transform3d instance = gl_volume->get_instance_transformation().get_matrix(); // Create result volume transformation - Transform3d surface_trmat = create_transformation_onto_surface(hit->position, hit->normal); - const FontProp &font_prop = emboss_data.text_configuration.style.prop; + Transform3d surface_trmat = create_transformation_onto_surface(hit->position, hit->normal); + const FontProp &font_prop = emboss_data.text_configuration.style.prop; apply_transformation(font_prop, surface_trmat); - Transform3d volume_trmat = hit_instance_trmat.inverse() * hit_object_trmat * surface_trmat; + Transform3d world_new = hit_to_world * surface_trmat; + // priv::reset_skew(world_new); + Transform3d volume_trmat = instance.inverse() * world_new; start_create_volume_job(obj, volume_trmat, emboss_data, volume_type); return true; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index 0c9b3b98ed..e1fded204d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp @@ -112,6 +112,11 @@ private: void draw_height(bool use_inch); void draw_depth(bool use_inch); + // call after set m_style_manager.get_style().prop.size_in_mm + bool set_height(); + // call after set m_style_manager.get_style().prop.emboss + bool set_depth(); + bool draw_italic_button(); bool draw_bold_button(); void draw_advanced(); @@ -336,6 +341,9 @@ private: Transform3d f_tr = Transform3d::Identity(); Transform3d t_tr = Transform3d::Identity(); + + std::optional y_scale; + std::optional z_scale; }; // Keep data about dragging only during drag&drop std::optional m_surface_drag; From 89ff154f9b8f91d0929cc726575927c97f49b2b0 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Tue, 14 Feb 2023 18:16:05 +0100 Subject: [PATCH 08/12] temp --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index e602bbd76c..35aec716e8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -799,8 +799,6 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) } // Calculate offset: transformation to wanted position Transform3d hit_to_world = m_raycast_manager.get_transformation(hit->tr_key); - //priv::reset_skew(hit_to_world); - Transform3d hit_to_instance = hit_to_world * m_surface_drag->instance_inv; Transform3d hit_to_volume = hit_to_instance * m_surface_drag->volume_tr.inverse(); From 6d0d24eecf0f172a2cdfb272fe6196b08fcc9169 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Wed, 15 Feb 2023 11:05:20 +0100 Subject: [PATCH 09/12] Get GL volume by volume by selection (not hovered volume) --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 76 +++++++++++++++++++++---- 1 file changed, 66 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 056719c198..44e664f8f8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -375,6 +375,7 @@ static Vec2d calc_mouse_to_center_text_offset(const Vec2d &mouse, const ModelVol /// Containe what is selected /// Slected when only one volume otherwise nullptr static const GLVolume *get_gl_volume(const Selection &selection); +static GLVolume *get_gl_volume(const GLCanvas3D &canvas); /// /// Get transformation to world @@ -395,6 +396,7 @@ static void change_window_position(std::optional &output_window_offset, } // namespace priv const GLVolume *priv::get_gl_volume(const Selection &selection) { + // return selection.get_first_volume(); const auto &list = selection.get_volume_idxs(); if (list.size() != 1) return nullptr; @@ -402,6 +404,19 @@ const GLVolume *priv::get_gl_volume(const Selection &selection) { return selection.get_volume(volume_idx); } +GLVolume *priv::get_gl_volume(const GLCanvas3D &canvas) { + const GLVolume *gl_volume = get_gl_volume(canvas.get_selection()); + if (gl_volume == nullptr) + return nullptr; + + const GLVolumePtrs &gl_volumes = canvas.get_volumes().volumes; + for (GLVolume *v : gl_volumes) + if (v->composite_id == gl_volume->composite_id) + return v; + + return nullptr; +} + Transform3d priv::world_matrix(const GLVolume *gl_volume, const Model *model) { if (!gl_volume) @@ -536,17 +551,40 @@ void reset_skew(Transform3d& m) m = Eigen::Translation3d(m.translation()) * Transform3d(u * Eigen::Scaling(new_scale_factor(s)) * v.transpose());// * mirror; } +void reset_skew_respect_z(Transform3d &m) +{ + Vec3d z_before = m * Vec3d::UnitZ(); + priv::reset_skew(m); + Vec3d z_after = m * Vec3d::UnitZ(); + + Transform3d rot; // = Transform3d::Identity(); + if (priv::allign_vec(z_after, z_before, rot)) + m = rot * m; +} + // Multiply from right static Transform3d surface_transformR(const Vec3d &p, const Vec3d &n, const Transform3d &v, const Transform3d &i) { Transform3d to_volume = (i * v).inverse(); Vec3d offset_volume = to_volume * p; Transform3d translate{Eigen::Translation(offset_volume)}; + + // new transformation for volume + Transform3d v_new = v * translate; + // rotation when exists Transform3d rotate; + // normal transformed to volume Vec3d z_t = to_volume.linear() * n; - bool exist_rotate = priv::allign_z(z_t, rotate); - return v * translate * rotate; + if (priv::allign_z(z_t, rotate)) + v_new = v_new * rotate; + + // Reset skew in world + Transform3d w_new = i * v_new; + priv::reset_skew_respect_z(w_new); + v_new = i.inverse() * w_new; + + return v_new; } /// @@ -581,7 +619,7 @@ static Transform3d surface_transformL(const Vec3d &p, const Vec3d &n, const Tran // w2 .. wanted world transformation Transform3d w2 = tr * rot_w; - //priv::reset_skew(w2); + //priv::reset_skew_respect_z(w2); // _ .. inverse // i_ .. instance inverse @@ -721,15 +759,15 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) if (m_volume == nullptr) return false; - // must exist hover object - int hovered_id = m_parent.get_first_hover_volume_idx(); - if (hovered_id < 0) + if (m_parent.get_first_hover_volume_idx() < 0) return false; - GLVolume *gl_volume = m_parent.get_volumes().volumes[hovered_id]; - const ModelObjectPtrs &objects = m_parent.get_model()->objects; + GLVolume *gl_volume = priv::get_gl_volume(m_parent); + if (gl_volume == nullptr) + return false; // hovered object must be actual text volume + const ModelObjectPtrs &objects = m_parent.get_model()->objects; if (m_volume != priv::get_model_volume(gl_volume, objects)) return false; @@ -825,7 +863,7 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) Transform3d volume_L = priv::surface_transformL(hit_position_world, hit_normal_world, volume, instance); Transform3d volume_2 = priv::surface_transform2(hit_position_world, hit_normal_world, volume, instance); Transform3d volume_3 = priv::surface_transform3(hit_position_world, hit_normal_world, volume, instance); - //volume_new = volume_L; + volume_new = volume_R; assert(volume_new.matrix()(0, 0) == volume_new.matrix()(0, 0)); // Check valid transformation not a NAN if (volume_new.matrix()(0, 0) != volume_new.matrix()(0, 0)) @@ -3701,6 +3739,21 @@ void GLGizmoEmboss::draw_advanced() ImGui::SetTooltip("%s", _u8L("Use camera direction for text orientation").c_str()); } + ImGui::SameLine(); + if (ImGui::Button(_u8L("Reset scale").c_str())) { + GLVolume *gl_volume = priv::get_gl_volume(m_parent); + if (gl_volume != nullptr) { + Transform3d w = gl_volume->world_matrix(); + priv::reset_skew_respect_z(w); + Transform3d i = gl_volume->get_instance_transformation().get_matrix(); + Transform3d v_new = i.inverse() * w; + gl_volume->set_volume_transformation(v_new); + m_parent.do_move(L("Reset scale")); + } + } else if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("%s", _u8L("Reset skew of text to be normal in world").c_str()); + } + #ifdef ALLOW_DEBUG_MODE ImGui::Text("family = %s", (font_prop.family.has_value() ? font_prop.family->c_str() : @@ -4197,7 +4250,10 @@ bool priv::start_create_volume_on_surface_job( const FontProp &font_prop = emboss_data.text_configuration.style.prop; apply_transformation(font_prop, surface_trmat); Transform3d world_new = hit_to_world * surface_trmat; - // priv::reset_skew(world_new); + + // Reset skew + priv::reset_skew_respect_z(world_new); + Transform3d volume_trmat = instance.inverse() * world_new; start_create_volume_job(obj, volume_trmat, emboss_data, volume_type); return true; From 67155e8da01acc7b78391a6144ec94c2e52fe25b Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Thu, 16 Feb 2023 13:09:29 +0100 Subject: [PATCH 10/12] RaycastManager use directly AABBMesh instead of MeshRayCaster --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 38 ++-- src/slic3r/Utils/RaycastManager.cpp | 261 +++++++++++++----------- src/slic3r/Utils/RaycastManager.hpp | 82 +++++--- 3 files changed, 215 insertions(+), 166 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 44e664f8f8..c6ce9da8fe 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -559,7 +559,7 @@ void reset_skew_respect_z(Transform3d &m) Transform3d rot; // = Transform3d::Identity(); if (priv::allign_vec(z_after, z_before, rot)) - m = rot * m; + m = m * rot; } // Multiply from right @@ -3489,21 +3489,33 @@ std::optional priv::calc_surface_offset(const ModelVolume &volume, Raycas std::optional hit_opt = raycast_manager.unproject(point, direction, &cond); // Try to find closest point when no hit object in emboss direction - if (!hit_opt.has_value()) - hit_opt = raycast_manager.closest(point); + if (!hit_opt.has_value()) { + std::optional close_point_opt = raycast_manager.closest(point); - // It should NOT appear. Closest point always exists. - if (!hit_opt.has_value()) - return {}; + // It should NOT appear. Closest point always exists. + assert(close_point_opt.has_value()); + if (!close_point_opt.has_value()) + return {}; + + // It is no neccesary to move with origin by very small value + if (close_point_opt->squared_distance < EPSILON) + return {}; + + const RaycastManager::ClosePoint &close_point = *close_point_opt; + Transform3d hit_tr = raycast_manager.get_transformation(close_point.tr_key); + Vec3d hit_world = hit_tr * close_point.point; + Vec3d offset_world = hit_world - point; // vector in world + Vec3d offset_volume = to_world.inverse().linear() * offset_world; + return offset_volume; + } // It is no neccesary to move with origin by very small value - if (hit_opt->squared_distance < EPSILON) - return {}; - const RaycastManager::Hit &hit = *hit_opt; - Transform3d hit_tr = raycast_manager.get_transformation(hit.tr_key); - Vec3d hit_world = hit_tr * hit.position.cast(); - Vec3d offset_world = hit_world - point; // vector in world + if (hit.squared_distance < EPSILON) + return {}; + Transform3d hit_tr = raycast_manager.get_transformation(hit.tr_key); + Vec3d hit_world = hit_tr * hit.position; + Vec3d offset_world = hit_world - point; // vector in world // TIP: It should be close to only z move Vec3d offset_volume = to_world.inverse().linear() * offset_world; return offset_volume; @@ -4246,7 +4258,7 @@ bool priv::start_create_volume_on_surface_job( Transform3d instance = gl_volume->get_instance_transformation().get_matrix(); // Create result volume transformation - Transform3d surface_trmat = create_transformation_onto_surface(hit->position, hit->normal); + Transform3d surface_trmat = create_transformation_onto_surface(hit->position.cast(), hit->normal.cast()); const FontProp &font_prop = emboss_data.text_configuration.style.prop; apply_transformation(font_prop, surface_trmat); Transform3d world_new = hit_to_world * surface_trmat; diff --git a/src/slic3r/Utils/RaycastManager.cpp b/src/slic3r/Utils/RaycastManager.cpp index be11c7f894..fad41424f9 100644 --- a/src/slic3r/Utils/RaycastManager.cpp +++ b/src/slic3r/Utils/RaycastManager.cpp @@ -3,69 +3,50 @@ // include for earn camera #include "slic3r/GUI/GUI_App.hpp" -#include "slic3r/GUI/Plater.hpp" -#include "slic3r/GUI/Camera.hpp" +#include "slic3r/GUI/Plater.hpp" +#include "slic3r/GUI/CameraUtils.hpp" using namespace Slic3r::GUI; namespace priv { - using namespace Slic3r; -// copied from private part of RaycastManager.hpp -using Raycaster = std::pair >; -// ModelVolume.id +static void actualize(RaycastManager::Meshes &meshes, const ModelVolumePtrs &volumes, const RaycastManager::ISkip *skip); +static const AABBMesh * get_mesh(const RaycastManager::Meshes &meshes, size_t volume_id); +static RaycastManager::TrKey create_key(const ModelVolume* volume, const ModelInstance* instance){ + return std::make_pair(instance->id().id, volume->id().id); } +static RaycastManager::TrItems::iterator find(RaycastManager::TrItems &items, const RaycastManager::TrKey &key); +static bool is_lower_key(const RaycastManager::TrKey &k1, const RaycastManager::TrKey &k2) { + return k1.first < k2.first || k1.first == k2.first && k1.second < k2.second; } +static bool is_lower(const RaycastManager::TrItem &i1, const RaycastManager::TrItem &i2) { + return is_lower_key(i1.first, i2.first); }; -using Raycasters = std::vector; + // Copy functionality from MeshRaycaster::unproject_on_mesh without filtering +using SurfacePoint = RaycastManager::SurfacePoint; +static std::optional unproject_on_mesh(const AABBMesh &aabb_mesh, + const Vec2d &mouse_pos, + const Transform3d &transformation, + const Camera &camera); -static void actualize(Raycasters &casters, const ModelVolumePtrs &volumes, const RaycastManager::ISkip *skip) -{ - // check if volume was removed - std::vector removed_casters(casters.size(), {true}); - // actualize MeshRaycaster - for (const ModelVolume *volume : volumes) { - size_t oid = volume->id().id; - if (skip != nullptr && skip->skip(oid)) - continue; - auto item = std::find_if(casters.begin(), casters.end(), - [oid](const Raycaster &it) -> bool { return oid == it.first; }); - if (item == casters.end()) { - // add new raycaster - auto raycaster = std::make_unique(volume->get_mesh_shared_ptr()); - casters.emplace_back(std::make_pair(oid, std::move(raycaster))); - } else { - size_t index = item - casters.begin(); - removed_casters[index] = false; - } - } - - // clean other raycasters - for (int i = removed_casters.size() - 1; i >= 0; --i) - if (removed_casters[i]) - casters.erase(casters.begin() + i); -} } void RaycastManager::actualize(const ModelObject *object, const ISkip *skip) { // actualize MeshRaycaster - priv::actualize(m_raycasters, object->volumes, skip); + priv::actualize(m_meshes, object->volumes, skip); // check if inscance was removed std::vector removed_transf(m_transformations.size(), {true}); - + + bool need_sort = false; // 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; - TrKey tr_key = std::make_pair(instance->id().id, volume->id().id); - auto item = std::find_if(m_transformations.begin(), - m_transformations.end(), - [&tr_key](const TrItem &it) -> bool { - return it.first == tr_key; - }); + const Transform3d &instrance_tr = instance->get_matrix(); + Transform3d transformation = instrance_tr * volume_tr; + TrKey key = priv::create_key(volume, instance); + auto item = priv::find(m_transformations, key); if (item != m_transformations.end()) { // actualize transformation all the time item->second = transformation; @@ -73,8 +54,8 @@ void RaycastManager::actualize(const ModelObject *object, const ISkip *skip) removed_transf[index] = false; } else { // add new transformation - m_transformations.emplace_back( - std::make_pair(tr_key, transformation)); + m_transformations.emplace_back(std::make_pair(key, transformation)); + need_sort = true; } } } @@ -83,17 +64,21 @@ void RaycastManager::actualize(const ModelObject *object, const ISkip *skip) for (int i = removed_transf.size() - 1; i >= 0; --i) if (removed_transf[i]) m_transformations.erase(m_transformations.begin() + i); + + if (need_sort) + std::sort(m_transformations.begin(), m_transformations.end(), priv::is_lower); } void RaycastManager::actualize(const ModelInstance *instance, const ISkip *skip) { const ModelVolumePtrs &volumes = instance->get_object()->volumes; // actualize MeshRaycaster - priv::actualize(m_raycasters, volumes, skip); + priv::actualize(m_meshes, volumes, skip); // check if inscance was removed std::vector removed_transf(m_transformations.size(), {true}); + bool need_sort = false; // actualize transformation matrices for (const ModelVolume *volume : volumes) { if (skip != nullptr && skip->skip(volume->id().id)) @@ -101,9 +86,8 @@ void RaycastManager::actualize(const ModelInstance *instance, const ISkip *skip) const Transform3d &volume_tr = volume->get_matrix(); const Transform3d &instrance_tr = instance->get_matrix(); Transform3d transformation = instrance_tr * volume_tr; - TrKey tr_key = std::make_pair(instance->id().id, volume->id().id); - auto item = std::find_if(m_transformations.begin(), m_transformations.end(), - [&tr_key](const TrItem &it) -> bool { return it.first == tr_key; }); + TrKey key = priv::create_key(volume, instance); + auto item = priv::find(m_transformations, key); if (item != m_transformations.end()) { // actualize transformation all the time item->second = transformation; @@ -111,7 +95,8 @@ void RaycastManager::actualize(const ModelInstance *instance, const ISkip *skip) removed_transf[index] = false; } else { // add new transformation - m_transformations.emplace_back(std::make_pair(tr_key, transformation)); + m_transformations.emplace_back(std::make_pair(key, transformation)); + need_sort = true; } } @@ -119,65 +104,33 @@ void RaycastManager::actualize(const ModelInstance *instance, const ISkip *skip) for (int i = removed_transf.size() - 1; i >= 0; --i) if (removed_transf[i]) m_transformations.erase(m_transformations.begin() + i); + + if (need_sort) + std::sort(m_transformations.begin(), m_transformations.end(), priv::is_lower); } -#include "slic3r/GUI/CameraUtils.hpp" -namespace priv { - -// Copy functionality from MeshRaycaster::unproject_on_mesh without filtering -static std::optional unproject_on_mesh(const MeshRaycaster &raycaster, - const Vec2d &mouse_pos, const Transform3d &transformation, const Camera &camera) { - - Vec3d point; - Vec3d direction; - CameraUtils::ray_from_screen_pos(camera, mouse_pos, point, direction); - Transform3d inv = transformation.inverse(); - point = inv*point; - direction = inv.linear()*direction; - - const AABBMesh &aabb_mesh = raycaster.get_aabb_mesh(); - std::vector hits = aabb_mesh.query_ray_hits(point, direction); - - if (hits.empty()) - return {}; // no intersection found - - const AABBMesh::hit_result &hit = hits.front(); - return RaycastManager::SurfacePoint( - hit.position().cast(), - hit.normal().cast() - ); -} -} // namespace priv - std::optional RaycastManager::unproject( const Vec2d &mouse_pos, const Camera &camera, const ISkip *skip) const { std::optional closest; for (const auto &item : m_transformations) { const TrKey &key = item.first; - size_t volume_id = key.second; + size_t volume_id = key.second; if (skip != nullptr && skip->skip(volume_id)) continue; + const AABBMesh *mesh = priv::get_mesh(m_meshes, volume_id); + if (mesh == nullptr) continue; const Transform3d &transformation = item.second; - auto raycaster_it = - std::find_if(m_raycasters.begin(), m_raycasters.end(), - [volume_id](const RaycastManager::Raycaster &it) - -> bool { return volume_id == it.first; }); - if (raycaster_it == m_raycasters.end()) continue; - const MeshRaycaster &raycaster = *(raycaster_it->second); - std::optional surface_point_opt = priv::unproject_on_mesh( - raycaster, mouse_pos, transformation, camera); + auto surface_point_opt = + priv::unproject_on_mesh(*mesh, mouse_pos, transformation, camera); if (!surface_point_opt.has_value()) continue; - const SurfacePoint &surface_point = *surface_point_opt; - Vec3d act_hit_tr = transformation * surface_point.position.cast(); + Vec3d act_hit_tr = transformation * surface_point_opt->position.cast(); double squared_distance = (camera.get_position() - act_hit_tr).squaredNorm(); if (closest.has_value() && closest->squared_distance < squared_distance) continue; - closest = Hit(key, surface_point, squared_distance); + closest = Hit{*surface_point_opt, key, squared_distance}; } - - //if (!closest.has_value()) return {}; return closest; } @@ -186,16 +139,11 @@ std::optional RaycastManager::unproject(const Vec3d &point, std::optional closest; for (const auto &item : m_transformations) { const TrKey &key = item.first; - size_t volume_id = key.second; + size_t volume_id = key.second; if (skip != nullptr && skip->skip(volume_id)) continue; const Transform3d &transformation = item.second; - auto raycaster_it = - std::find_if(m_raycasters.begin(), m_raycasters.end(), - [volume_id](const RaycastManager::Raycaster &it) - -> bool { return volume_id == it.first; }); - if (raycaster_it == m_raycasters.end()) continue; - const MeshRaycaster &raycaster = *(raycaster_it->second); - const AABBMesh& mesh = raycaster.get_aabb_mesh(); + const AABBMesh *mesh = priv::get_mesh(m_meshes, volume_id); + if (mesh == nullptr) continue; Transform3d tr_inv = transformation.inverse(); Vec3d mesh_point = tr_inv * point; Vec3d mesh_direction = tr_inv.linear() * direction; @@ -205,49 +153,50 @@ std::optional RaycastManager::unproject(const Vec3d &point, Vec3d point_negative = mesh_point + mesh_direction; // Throw ray to both directions of ray - std::vector hits = mesh.query_ray_hits(point_positive, mesh_direction); - std::vector hits_neg = mesh.query_ray_hits(point_negative, -mesh_direction); + std::vector hits = mesh->query_ray_hits(point_positive, mesh_direction); + std::vector hits_neg = mesh->query_ray_hits(point_negative, -mesh_direction); hits.insert(hits.end(), std::make_move_iterator(hits_neg.begin()), std::make_move_iterator(hits_neg.end())); for (const AABBMesh::hit_result &hit : hits) { double squared_distance = (mesh_point - hit.position()).squaredNorm(); if (closest.has_value() && closest->squared_distance < squared_distance) continue; - SurfacePoint surface_point(hit.position().cast(), hit.normal().cast()); - closest = Hit(key, surface_point, squared_distance); + closest = Hit{{hit.position(), hit.normal()}, key, squared_distance}; } } return closest; } -std::optional RaycastManager::closest(const Vec3d &point, const ISkip *skip) const { - std::optional closest; +std::optional RaycastManager::closest(const Vec3d &point, const ISkip *skip) const +{ + std::optional closest; for (const auto &item : m_transformations) { const TrKey &key = item.first; size_t volume_id = key.second; if (skip != nullptr && skip->skip(volume_id)) continue; - auto raycaster_it = std::find_if(m_raycasters.begin(), m_raycasters.end(), - [volume_id](const RaycastManager::Raycaster &it) -> bool { return volume_id == it.first; }); - if (raycaster_it == m_raycasters.end()) - continue; - const MeshRaycaster &raycaster = *(raycaster_it->second); + const AABBMesh *mesh = priv::get_mesh(m_meshes, volume_id); + if (mesh == nullptr) continue; const Transform3d &transformation = item.second; Transform3d tr_inv = transformation.inverse(); - Vec3d mesh_point_d = tr_inv * point; - Vec3f mesh_point_f = mesh_point_d.cast(); - Vec3f n; - Vec3f p = raycaster.get_closest_point(mesh_point_f, &n); - double squared_distance = (mesh_point_f - p).squaredNorm(); + Vec3d mesh_point = tr_inv * point; + + int face_idx = 0; + Vec3d closest_point; + Vec3d pointd = point.cast(); + mesh->squared_distance(pointd, face_idx, closest_point); + + double squared_distance = (mesh_point - closest_point).squaredNorm(); if (closest.has_value() && closest->squared_distance < squared_distance) continue; - SurfacePoint surface_point(p,n); - closest = Hit(key, surface_point, squared_distance); + + closest = ClosePoint{key, closest_point, squared_distance}; } return closest; } Slic3r::Transform3d RaycastManager::get_transformation(const TrKey &tr_key) const { + // TODO: transformations are sorted use lower bound auto item = std::find_if(m_transformations.begin(), m_transformations.end(), [&tr_key](const TrItem &it) -> bool { @@ -255,4 +204,78 @@ Slic3r::Transform3d RaycastManager::get_transformation(const TrKey &tr_key) cons }); if (item == m_transformations.end()) return Transform3d::Identity(); return item->second; -} \ No newline at end of file +} + +void priv::actualize(RaycastManager::Meshes &meshes, const ModelVolumePtrs &volumes, const RaycastManager::ISkip *skip) +{ + // check if volume was removed + std::vector removed_meshes(meshes.size(), {true}); + bool need_sort = false; + // actualize MeshRaycaster + for (const ModelVolume *volume : volumes) { + size_t oid = volume->id().id; + if (skip != nullptr && skip->skip(oid)) + continue; + auto item = std::find_if(meshes.begin(), meshes.end(), [oid](const RaycastManager::Mesh &it) -> bool { return oid == it.first; }); + if (item == meshes.end()) { + // add new raycaster + bool calculate_epsilon = true; + auto mesh = std::make_unique(volume->mesh(), calculate_epsilon); + meshes.emplace_back(std::make_pair(oid, std::move(mesh))); + need_sort = true; + } else { + size_t index = item - meshes.begin(); + removed_meshes[index] = false; + } + } + + // clean other raycasters + for (int i = removed_meshes.size() - 1; i >= 0; --i) + if (removed_meshes[i]) + meshes.erase(meshes.begin() + i); + + // All the time meshes must be sorted by volume id - for faster search + if (need_sort) { + auto is_lower = [](const RaycastManager::Mesh &m1, const RaycastManager::Mesh &m2) { return m1.first < m2.first; }; + std::sort(meshes.begin(), meshes.end(), is_lower); + } +} + +std::optional priv::unproject_on_mesh(const AABBMesh &aabb_mesh, + const Vec2d &mouse_pos, + const Transform3d &transformation, + const Camera &camera) +{ + Vec3d point; + Vec3d direction; + CameraUtils::ray_from_screen_pos(camera, mouse_pos, point, direction); + Transform3d inv = transformation.inverse(); + point = inv * point; + direction = inv.linear() * direction; + std::vector hits = aabb_mesh.query_ray_hits(point, direction); + + if (hits.empty()) + return {}; // no intersection found + + const AABBMesh::hit_result &hit = hits.front(); + return priv::SurfacePoint{hit.position(), hit.normal()}; +} + +const Slic3r::AABBMesh *priv::get_mesh(const RaycastManager::Meshes &meshes, size_t volume_id) +{ + auto is_lower_index = [](const RaycastManager::Mesh &m, size_t i) -> bool { return m.first < i; }; + auto it = std::lower_bound(meshes.begin(), meshes.end(), volume_id, is_lower_index); + if (it == meshes.end() || it->first != volume_id) + return nullptr; + return &(*(it->second)); +} + +RaycastManager::TrItems::iterator priv::find(RaycastManager::TrItems &items, const RaycastManager::TrKey &key) { + auto fnc = [](const RaycastManager::TrItem &it, const RaycastManager::TrKey &key)->bool { + return priv::is_lower_key(it.first, key); + }; + auto it = std::lower_bound(items.begin(), items.end(), key, fnc); + if (it == items.end() || it->first != key) + return items.end(); + return it; +} diff --git a/src/slic3r/Utils/RaycastManager.hpp b/src/slic3r/Utils/RaycastManager.hpp index 5451c4e92e..406e51c86c 100644 --- a/src/slic3r/Utils/RaycastManager.hpp +++ b/src/slic3r/Utils/RaycastManager.hpp @@ -2,12 +2,12 @@ #define slic3r_RaycastManager_hpp_ #include // unique_ptr -#include // unique_ptr -#include -#include "slic3r/GUI/MeshUtils.hpp" // MeshRaycaster +#include +#include "libslic3r/AABBMesh.hpp" // Structure to cast rays #include "libslic3r/Point.hpp" // Transform3d #include "libslic3r/ObjectID.hpp" #include "libslic3r/Model.hpp" // ModelObjectPtrs, ModelObject, ModelInstance, ModelVolume +#include "slic3r/GUI/Camera.hpp" namespace Slic3r::GUI{ @@ -17,19 +17,22 @@ namespace Slic3r::GUI{ /// class RaycastManager { - // ModelVolume.id - using Raycaster = std::pair >; - std::vector m_raycasters; +// Public structures used by RaycastManager +public: - // Key for transformation consist of unique volume and instance + // ModelVolume.id + using Mesh = std::pair >; + using Meshes = std::vector; + + // Key for transformation consist of unique volume and instance id ... ObjectId() // ModelInstance, ModelVolume using TrKey = std::pair; using TrItem = std::pair; - std::vector m_transformations; + using TrItems = std::vector; - // should contain shared pointer to camera but it is not shared pointer so it need it every time when casts rays - -public: + /// + /// Interface for identify allowed volumes to cast rays. + /// class ISkip{ public: virtual ~ISkip() = default; @@ -42,6 +45,39 @@ public: virtual bool skip(const size_t &model_volume_id) const { return false; } }; + // TODO: it is more general object move outside of this class + template + struct SurfacePoint { + using Vec3 = Eigen::Matrix; + Vec3 position = Vec3::Zero(); + Vec3 normal = Vec3::UnitZ(); + }; + + struct Hit : public SurfacePoint + { + TrKey tr_key; + double squared_distance; + }; + + struct ClosePoint + { + TrKey tr_key; + Vec3d point; + double squared_distance; + }; + +// Members +private: + // Keep structure to fast cast rays + // meshes are sorted by volume_id for faster search + Meshes m_meshes; + + // Keep transformation of meshes + TrItems m_transformations; + // Note: one mesh could have more transformations ... instances + +public: + /// /// Actualize raycasters + transformation /// Detection of removed object @@ -53,27 +89,6 @@ public: void actualize(const ModelObject *object, const ISkip *skip = nullptr); void actualize(const ModelInstance *instance, const ISkip *skip = nullptr); - // TODO: it is more general object move outside of this class - struct SurfacePoint - { - Vec3f position = Vec3f::Zero(); - Vec3f normal = Vec3f::UnitZ(); - SurfacePoint() = default; - SurfacePoint(Vec3f position, Vec3f normal) - : position(position), normal(normal) - {} - }; - - struct Hit: public SurfacePoint - { - using Key = TrKey; - Key tr_key; - double squared_distance; - Hit(const Key& tr_key, const SurfacePoint& surface_point, double squared_distance) - : SurfacePoint(surface_point), tr_key(tr_key), squared_distance(squared_distance) - {} - }; - class SkipVolume: public ISkip { size_t volume_id; @@ -95,7 +110,6 @@ public: /// /// Unproject on mesh by Mesh raycasters - /// Note: Function use current camera position from wxGetApp() /// /// Position of mouse on screen /// Projection params @@ -121,7 +135,7 @@ public: /// Point /// Define which caster will be skipped, null mean no skip /// - std::optional closest(const Vec3d &point, const ISkip *skip = nullptr) const; + std::optional closest(const Vec3d &point, const ISkip *skip = nullptr) const; /// /// Getter on transformation from hitted volume to world From b82f1fe8187a7873c795b08b114869e9b22e17e2 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Fri, 17 Feb 2023 08:16:54 +0100 Subject: [PATCH 11/12] Move over surface with relative transformation --- src/libslic3r/Emboss.cpp | 39 ++++++++--- src/libslic3r/Emboss.hpp | 12 +++- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 63 +++++++---------- src/slic3r/Utils/RaycastManager.cpp | 92 ++++++++++++++----------- src/slic3r/Utils/RaycastManager.hpp | 7 +- 5 files changed, 119 insertions(+), 94 deletions(-) diff --git a/src/libslic3r/Emboss.cpp b/src/libslic3r/Emboss.cpp index e3f7454a76..44fa402025 100644 --- a/src/libslic3r/Emboss.cpp +++ b/src/libslic3r/Emboss.cpp @@ -1540,8 +1540,28 @@ std::optional Emboss::ProjectZ::unproject(const Vec3d &p, double *depth) return Vec2d(p.x() / SHAPE_SCALE, p.y() / SHAPE_SCALE); } -Transform3d Emboss::create_transformation_onto_surface(const Vec3f &position, - const Vec3f &normal, + +Vec3d Emboss::suggest_up(const Vec3d normal, double up_limit) +{ + // Normal must be 1 + assert(is_approx(normal.norm(), 1.)); + + // wanted up direction of result + Vec3d wanted_up_side = + (std::fabs(normal.z()) > up_limit)? + Vec3d::UnitY() : Vec3d::UnitZ(); + + // create perpendicular unit vector to surface triangle normal vector + // lay on surface of triangle and define up vector for text + Vec3d wanted_up_dir = normal.cross(wanted_up_side).cross(normal); + // normal3d is NOT perpendicular to normal_up_dir + wanted_up_dir.normalize(); + + return wanted_up_dir; +} + +Transform3d Emboss::create_transformation_onto_surface(const Vec3d &position, + const Vec3d &normal, float up_limit) { // up and emboss direction for generated model @@ -1552,28 +1572,27 @@ Transform3d Emboss::create_transformation_onto_surface(const Vec3f &position, 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(); + assert(is_approx(normal.norm(), 1.)); // 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 + Vec3d wanted_up_dir = normal .cross(wanted_up_side) - .cross(wanted_emboss_dir); + .cross(normal); // normal3d is NOT perpendicular to normal_up_dir wanted_up_dir.normalize(); // perpendicular to emboss vector of text and normal Vec3d axis_view; double angle_view; - if (wanted_emboss_dir == -Vec3d::UnitZ()) { + if (normal == -Vec3d::UnitZ()) { // text_emboss_dir has opposit direction to wanted_emboss_dir axis_view = Vec3d::UnitY(); angle_view = M_PI; } else { - axis_view = text_emboss_dir.cross(wanted_emboss_dir); - angle_view = std::acos(text_emboss_dir.dot(wanted_emboss_dir)); // in rad + axis_view = text_emboss_dir.cross(normal); + angle_view = std::acos(text_emboss_dir.dot(normal)); // in rad axis_view.normalize(); } @@ -1593,7 +1612,7 @@ Transform3d Emboss::create_transformation_onto_surface(const Vec3f &position, Eigen::AngleAxis up_rot(angle_up, text_emboss_dir); Transform3d transform = Transform3d::Identity(); - transform.translate(position.cast()); + transform.translate(position); transform.rotate(view_rot); transform.rotate(up_rot); return transform; diff --git a/src/libslic3r/Emboss.hpp b/src/libslic3r/Emboss.hpp index ca27afe45c..cf15aa2cb9 100644 --- a/src/libslic3r/Emboss.hpp +++ b/src/libslic3r/Emboss.hpp @@ -273,7 +273,15 @@ namespace Emboss /// Define transformation from 2d to 3d(orientation, position, scale, ...) /// Projected shape into space indexed_triangle_set polygons2model(const ExPolygons &shape2d, const IProjection& projection); - + + /// + /// Suggest wanted up vector of embossed text by emboss direction + /// + /// Normalized vector of emboss direction in world + /// Is compared with normal.z to suggest up direction + /// Wanted up vector + Vec3d suggest_up(const Vec3d normal, double up_limit = 0.9); + /// /// Create transformation for emboss text object to lay on surface point /// @@ -282,7 +290,7 @@ namespace Emboss /// Is compared with normal.z to suggest up direction /// Transformation onto surface point Transform3d create_transformation_onto_surface( - const Vec3f &position, const Vec3f &normal, float up_limit = 0.9f); + const Vec3d &position, const Vec3d &normal, float up_limit = 0.9f); class ProjectZ : public IProjection { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index c6ce9da8fe..4493fba38e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -828,42 +828,38 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) Vec2d mouse_pos = mouse_coord.cast(); Vec2d offseted_mouse = mouse_pos + m_surface_drag->mouse_offset; const Camera &camera = wxGetApp().plater()->get_camera(); - auto hit = m_raycast_manager.unproject(offseted_mouse, camera, &m_surface_drag->condition); + auto hit = m_raycast_manager.ray_from_camera(offseted_mouse, camera, &m_surface_drag->condition); m_surface_drag->exist_hit = hit.has_value(); if (!hit.has_value()) { // cross hair need redraw m_parent.set_as_dirty(); return true; } - // Calculate offset: transformation to wanted position - Transform3d hit_to_world = m_raycast_manager.get_transformation(hit->tr_key); - Transform3d hit_to_instance = hit_to_world * m_surface_drag->instance_inv; - Transform3d hit_to_volume = hit_to_instance * m_surface_drag->volume_tr.inverse(); - - Vec3d hit_position = hit->position.cast(); - Vec3d offset_volume = hit_to_volume * hit_position; - Transform3d translate{Eigen::Translation(offset_volume)}; - - Transform3d rotate; - // normal transformed to volume - Vec3d hit_normal = hit->normal.cast(); - Vec3d z_t = hit_to_volume.linear() * hit_normal; - bool exist_rotate = priv::allign_z(z_t, rotate); - // Edit position from right - Transform3d volume_new = m_surface_drag->volume_tr * translate * rotate; const Transform3d &instance = m_surface_drag->gl_volume->get_instance_transformation().get_matrix(); const Transform3d &volume = m_surface_drag->volume_tr; - Vec3d hit_position_world = hit_to_world * hit_position; - Vec3d hit_normal_world = hit_to_world.linear() * hit_normal; + // Calculate offset: transformation to wanted position + Transform3d text_to_world_old = instance * volume; + { + // Reset skew of the text Z axis: + // Project the old Z axis into a new Z axis, which is perpendicular to the old XY plane. + Vec3d old_z = text_to_world_old.linear().col(2); + Vec3d new_z = text_to_world_old.linear().col(0).cross(text_to_world_old.linear().col(1)); + text_to_world_old.linear().col(2) = new_z * (old_z.dot(new_z) / new_z.squaredNorm()); + } - // REWRITE transformation - Transform3d volume_R = priv::surface_transformR(hit_position_world, hit_normal_world, volume, instance); - Transform3d volume_L = priv::surface_transformL(hit_position_world, hit_normal_world, volume, instance); - Transform3d volume_2 = priv::surface_transform2(hit_position_world, hit_normal_world, volume, instance); - Transform3d volume_3 = priv::surface_transform3(hit_position_world, hit_normal_world, volume, instance); - volume_new = volume_R; + // normal transformed to volume + Vec3d text_z_world = text_to_world_old.linear() * Vec3d::UnitZ(); + auto z_rotation = Eigen::Quaternion::FromTwoVectors(text_z_world, hit->normal); + Transform3d text_to_world_new = z_rotation * text_to_world_old; + + // Fix up vector ?? + //auto y_rotation = Eigen::Quaternion::FromTwoVectors(text_y_world, hit->normal); + + // Edit position from right + Transform3d volume_new{Eigen::Translation(m_surface_drag->instance_inv * hit->position)}; + volume_new.linear() = instance.linear().inverse() * text_to_world_new.linear(); assert(volume_new.matrix()(0, 0) == volume_new.matrix()(0, 0)); // Check valid transformation not a NAN if (volume_new.matrix()(0, 0) != volume_new.matrix()(0, 0)) @@ -871,14 +867,8 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) // Check scale in world // Calculate Scale to keep size after move over scaled surface - Transform3d current_world = instance * volume; - auto current_world_linear = current_world.linear(); - - Transform3d wanted_world = instance * volume_new; - auto wanted_world_linear = wanted_world.linear(); - - m_surface_drag->y_scale = priv::calc_scale(current_world_linear, wanted_world_linear, Vec3d::UnitY()); - m_surface_drag->z_scale = priv::calc_scale(current_world_linear, wanted_world_linear, Vec3d::UnitZ()); + m_surface_drag->y_scale = priv::calc_scale(text_to_world_old.linear(), text_to_world_new.linear(), Vec3d::UnitY()); + m_surface_drag->z_scale = priv::calc_scale(text_to_world_old.linear(), text_to_world_new.linear(), Vec3d::UnitZ()); // recalculate rotation for scaled volume //Transform3d hit_to_volume2 = hit_to_instance * (m_surface_drag->volume_tr*scale).inverse(); @@ -4245,7 +4235,7 @@ bool priv::start_create_volume_on_surface_job( raycaster.actualize(obj, &cond); const Camera &camera = plater->get_camera(); - std::optional hit = raycaster.unproject(screen_coor, camera); + std::optional hit = raycaster.ray_from_camera(screen_coor, camera, &cond); // 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 @@ -4253,15 +4243,14 @@ bool priv::start_create_volume_on_surface_job( if (!hit.has_value()) return false; - Transform3d hit_to_world = raycaster.get_transformation(hit->tr_key); // priv::reset_skew(hit_to_world); Transform3d instance = gl_volume->get_instance_transformation().get_matrix(); // Create result volume transformation - Transform3d surface_trmat = create_transformation_onto_surface(hit->position.cast(), hit->normal.cast()); + Transform3d surface_trmat = create_transformation_onto_surface(hit->position, hit->normal); const FontProp &font_prop = emboss_data.text_configuration.style.prop; apply_transformation(font_prop, surface_trmat); - Transform3d world_new = hit_to_world * surface_trmat; + Transform3d world_new = surface_trmat; // Reset skew priv::reset_skew_respect_z(world_new); diff --git a/src/slic3r/Utils/RaycastManager.cpp b/src/slic3r/Utils/RaycastManager.cpp index fad41424f9..3f34c37fcd 100644 --- a/src/slic3r/Utils/RaycastManager.cpp +++ b/src/slic3r/Utils/RaycastManager.cpp @@ -19,14 +19,6 @@ static bool is_lower_key(const RaycastManager::TrKey &k1, const RaycastManager:: return k1.first < k2.first || k1.first == k2.first && k1.second < k2.second; } static bool is_lower(const RaycastManager::TrItem &i1, const RaycastManager::TrItem &i2) { return is_lower_key(i1.first, i2.first); }; - - // Copy functionality from MeshRaycaster::unproject_on_mesh without filtering -using SurfacePoint = RaycastManager::SurfacePoint; -static std::optional unproject_on_mesh(const AABBMesh &aabb_mesh, - const Vec2d &mouse_pos, - const Transform3d &transformation, - const Camera &camera); - } void RaycastManager::actualize(const ModelObject *object, const ISkip *skip) @@ -108,11 +100,21 @@ void RaycastManager::actualize(const ModelInstance *instance, const ISkip *skip) if (need_sort) std::sort(m_transformations.begin(), m_transformations.end(), priv::is_lower); } - -std::optional RaycastManager::unproject( + +std::optional RaycastManager::ray_from_camera( const Vec2d &mouse_pos, const Camera &camera, const ISkip *skip) const { - std::optional closest; + // Improve it is not neccessaru to use AABBMesh and calc normal in + + struct Result + { + const AABBMesh *mesh = nullptr; + double squared_distance; + int face; + Vec3d hit_world; + const Transform3d *tramsformation; + const TrKey *key; + }result; for (const auto &item : m_transformations) { const TrKey &key = item.first; size_t volume_id = key.second; @@ -120,18 +122,46 @@ std::optional RaycastManager::unproject( const AABBMesh *mesh = priv::get_mesh(m_meshes, volume_id); if (mesh == nullptr) continue; const Transform3d &transformation = item.second; - auto surface_point_opt = - priv::unproject_on_mesh(*mesh, mouse_pos, transformation, camera); - if (!surface_point_opt.has_value()) + + Vec3d point; + Vec3d direction; + CameraUtils::ray_from_screen_pos(camera, mouse_pos, point, direction); + Transform3d inv = transformation.inverse(); + point = inv * point; + direction = inv.linear() * direction; + std::vector hits = mesh->query_ray_hits(point, direction); + if (hits.empty()) continue; // no intersection found + + const AABBMesh::hit_result &hit = hits.front(); + + // convert to world + Vec3d hit_world = transformation * hit.position(); + double squared_distance = (camera.get_position() - hit_world).squaredNorm(); + if (result.mesh != nullptr && + result.squared_distance < squared_distance) continue; - Vec3d act_hit_tr = transformation * surface_point_opt->position.cast(); - double squared_distance = (camera.get_position() - act_hit_tr).squaredNorm(); - if (closest.has_value() && - closest->squared_distance < squared_distance) - continue; - closest = Hit{*surface_point_opt, key, squared_distance}; + + result.mesh = mesh; + result.squared_distance = squared_distance; + result.face = hit.face(); + result.hit_world = hit_world; + result.tramsformation = &transformation; + result.key = &key; } - return closest; + + if (result.mesh == nullptr) + return {}; + + const Vec3i tri = result.mesh->indices(result.face); + Vec3d pts[3]; + auto tr = result.tramsformation->linear(); + for (int i = 0; i < 3; ++i) + pts[i] = tr * result.mesh->vertices(tri[i]).cast(); + Vec3d normal_world = (pts[1] - pts[0]).cross(pts[2] - pts[1]); + normal_world.normalize(); + + SurfacePoint point_world{result.hit_world, normal_world}; + return RaycastManager::Hit{point_world, *result.key, result.squared_distance}; } std::optional RaycastManager::unproject(const Vec3d &point, const Vec3d &direction, const ISkip *skip) const @@ -241,26 +271,6 @@ void priv::actualize(RaycastManager::Meshes &meshes, const ModelVolumePtrs &volu } } -std::optional priv::unproject_on_mesh(const AABBMesh &aabb_mesh, - const Vec2d &mouse_pos, - const Transform3d &transformation, - const Camera &camera) -{ - Vec3d point; - Vec3d direction; - CameraUtils::ray_from_screen_pos(camera, mouse_pos, point, direction); - Transform3d inv = transformation.inverse(); - point = inv * point; - direction = inv.linear() * direction; - std::vector hits = aabb_mesh.query_ray_hits(point, direction); - - if (hits.empty()) - return {}; // no intersection found - - const AABBMesh::hit_result &hit = hits.front(); - return priv::SurfacePoint{hit.position(), hit.normal()}; -} - const Slic3r::AABBMesh *priv::get_mesh(const RaycastManager::Meshes &meshes, size_t volume_id) { auto is_lower_index = [](const RaycastManager::Mesh &m, size_t i) -> bool { return m.first < i; }; diff --git a/src/slic3r/Utils/RaycastManager.hpp b/src/slic3r/Utils/RaycastManager.hpp index 406e51c86c..5bd28d00a6 100644 --- a/src/slic3r/Utils/RaycastManager.hpp +++ b/src/slic3r/Utils/RaycastManager.hpp @@ -114,10 +114,9 @@ public: /// 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, - const Camera &camera, - const ISkip *skip = nullptr) const; + /// Position on surface, normal direction in world coorinate + /// + key, to know hitted instance and volume + std::optional ray_from_camera(const Vec2d &mouse_pos, const Camera &camera, const ISkip *skip = nullptr) const; /// /// Unproject Ray(point direction) on mesh by MeshRaycasters From 5be8e41545f8202b1b973ba1d82368f20ef8ee1e Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Fri, 17 Feb 2023 10:13:54 +0100 Subject: [PATCH 12/12] Clean up calculation of transformation --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 251 ++++-------------------- src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp | 19 +- 2 files changed, 36 insertions(+), 234 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 4493fba38e..5aba107287 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -551,167 +551,6 @@ void reset_skew(Transform3d& m) m = Eigen::Translation3d(m.translation()) * Transform3d(u * Eigen::Scaling(new_scale_factor(s)) * v.transpose());// * mirror; } -void reset_skew_respect_z(Transform3d &m) -{ - Vec3d z_before = m * Vec3d::UnitZ(); - priv::reset_skew(m); - Vec3d z_after = m * Vec3d::UnitZ(); - - Transform3d rot; // = Transform3d::Identity(); - if (priv::allign_vec(z_after, z_before, rot)) - m = m * rot; -} - -// Multiply from right -static Transform3d surface_transformR(const Vec3d &p, const Vec3d &n, const Transform3d &v, const Transform3d &i) { - Transform3d to_volume = (i * v).inverse(); - Vec3d offset_volume = to_volume * p; - Transform3d translate{Eigen::Translation(offset_volume)}; - - // new transformation for volume - Transform3d v_new = v * translate; - - // rotation when exists - Transform3d rotate; - - // normal transformed to volume - Vec3d z_t = to_volume.linear() * n; - if (priv::allign_z(z_t, rotate)) - v_new = v_new * rotate; - - // Reset skew in world - Transform3d w_new = i * v_new; - priv::reset_skew_respect_z(w_new); - v_new = i.inverse() * w_new; - - return v_new; -} - -/// -/// Create transformation for volume to move over surface -/// Multiply from Left side - NOT WORK - with scaled instances -/// -/// Point in world coordinate -/// Normal in world coordinate - orientation -/// Original volume transformation -/// Instance transformation -/// Transformation of volume to lay on surface -static Transform3d surface_transformL(const Vec3d &p, const Vec3d &n, const Transform3d &v, const Transform3d &i) { - // w .. original world - Transform3d w = i * v; - - // remove already existing of skew before calc rotation - // priv::reset_skew(w); - - // z .. unit z vector in world coordinate - Vec3d z = w.linear() * Vec3d::UnitZ(); - Transform3d rot = Transform3d::Identity(); - bool exist_rot = priv::allign_vec(z, n, rot); - - // rot_w .. new rotation applied on world - Transform3d rot_w = rot * w; - - // p0 .. Zero of volume in world - Vec3d p0 = rot_w * Vec3d::Zero(); - Vec3d offset = p - p0; // in world - Transform3d tr{Eigen::Translation(offset)}; - - // w2 .. wanted world transformation - Transform3d w2 = tr * rot_w; - - //priv::reset_skew_respect_z(w2); - - // _ .. inverse - // i_ .. instance inverse - Transform3d i_ = i.inverse(); - - // w = i * v \\ left multiply by i_ - // i_ * w = i_ * i * v - // v = i_ * w - return i_ * w2; - // NOTE: Do not keep scale of text when move over scaled instance -} - -// transformation inside of instance -static Transform3d surface_transform2(const Vec3d &p, const Vec3d &n, const Transform3d &v, const Transform3d &i) -{ - // _ .. inverse - // i_ .. instance inverse - Transform3d i_ = i.inverse(); - Vec3d pp = i_ * p; - Vec3d nn = i_.linear() * n.normalized(); - nn.normalize(); - - // z .. unit z vector in world coordinate - Vec3d z = v * Vec3d::UnitZ(); - z.normalize(); - - Transform3d rot = Transform3d::Identity(); - bool exist_rot = priv::allign_vec(z, nn, rot); - - // rot_w .. new rotation applied on world - Transform3d rotated = rot * v; - - // p0 .. Zero of volume in world - Vec3d p0 = rotated * Vec3d::Zero(); - Vec3d offset = pp - p0; // in world - Transform3d tr{Eigen::Translation(offset)}; - Transform3d volume_new = tr * rotated; - //return volume_new; - - // Remove skew in world - Transform3d world_new = i * volume_new; - reset_skew(world_new); - volume_new = i_ * world_new; - - return volume_new; -} - -// work in space defined by SVD -static Transform3d surface_transform3(const Vec3d &p, const Vec3d &n, const Transform3d &v, const Transform3d &i) { - // w .. original world - Transform3d w = i * v; - - const Eigen::JacobiSVD svd1(w.linear(), Eigen::ComputeFullU | Eigen::ComputeFullV); - Matrix3d u1 = svd1.matrixU(); - Matrix3d v1 = svd1.matrixV(); - Matrix3d s1 = svd1.singularValues().asDiagonal(); - Transform3d tr1(Eigen::Translation3d(w.translation())); - //Transform3d test = tr1 * Transform3d(u1 * s1 * v1.transpose()); - - // modification of world - Transform3d mod(s1 * v1.transpose()); - Transform3d mod_ = mod.inverse(); - Transform3d w_mod = w * mod_; - - Vec3d nn = mod_.linear() * n; - // z .. unit z vector in world coordinate - Vec3d z = w_mod.linear() * Vec3d::UnitZ(); - Transform3d rot = Transform3d::Identity(); - bool exist_rot = priv::allign_vec(z, nn, rot); - - // rot_w .. new rotation applied on world - Transform3d rot_w = rot * w; - - // p0 .. Zero of volume in world - Vec3d p0 = rot_w * Vec3d::Zero(); - Vec3d offset = p - p0; // in world - Transform3d tr{Eigen::Translation(offset)}; - - // w2 .. wanted world transformation - Transform3d w2 = tr * rot_w; - - // _ .. inverse - // i_ .. instance inverse - Transform3d i_ = i.inverse(); - - // w = i * v \\ left multiply by i_ - // i_ * w = i_ * i * v - // v = i_ * w - return i_ * w2; - // NOTE: Do not keep scale of text when move over scaled instance -} - } bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) @@ -725,15 +564,15 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) // Update surface by new position bool need_process = m_volume->text_configuration->style.prop.use_surface; - if (m_surface_drag->y_scale.has_value()) { - m_style_manager.get_style().prop.size_in_mm *= (*m_surface_drag->y_scale); - need_process |= set_height(); - } + //if (m_surface_drag->y_scale.has_value()) { + // m_style_manager.get_style().prop.size_in_mm *= (*m_surface_drag->y_scale); + // need_process |= set_height(); + //} - if (m_surface_drag->z_scale.has_value()) { - m_style_manager.get_style().prop.emboss *= (*m_surface_drag->z_scale); - need_process |= set_depth(); - } + //if (m_surface_drag->z_scale.has_value()) { + // m_style_manager.get_style().prop.emboss *= (*m_surface_drag->z_scale); + // need_process |= set_depth(); + //} if (need_process) process(); @@ -800,14 +639,16 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY()); Vec2d mouse_pos = mouse_coord.cast(); Vec2d mouse_offset = priv::calc_mouse_to_center_text_offset(mouse_pos, *m_volume); - Transform3d instance_inv = gl_volume->get_instance_transformation().get_matrix().inverse(); Transform3d volume_tr = gl_volume->get_volume_transformation().get_matrix(); TextConfiguration &tc = *m_volume->text_configuration; // fix baked transformation from .3mf store process if (tc.fix_3mf_tr.has_value()) volume_tr = volume_tr * tc.fix_3mf_tr->inverse(); - m_surface_drag = SurfaceDrag{mouse_offset, instance_inv, volume_tr, gl_volume, condition}; + Transform3d instance_tr = gl_volume->get_instance_transformation().get_matrix(); + Transform3d instance_tr_inv = instance_tr.inverse(); + Transform3d world_tr = instance_tr * volume_tr; + m_surface_drag = SurfaceDrag{mouse_offset, world_tr, instance_tr_inv, gl_volume, condition}; // Cancel job to prevent interuption of dragging (duplicit result) if (m_job_cancel != nullptr) @@ -836,45 +677,36 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) return true; } - const Transform3d &instance = m_surface_drag->gl_volume->get_instance_transformation().get_matrix(); - const Transform3d &volume = m_surface_drag->volume_tr; - + auto world_linear = m_surface_drag->world.linear(); // Calculate offset: transformation to wanted position - Transform3d text_to_world_old = instance * volume; { // Reset skew of the text Z axis: // Project the old Z axis into a new Z axis, which is perpendicular to the old XY plane. - Vec3d old_z = text_to_world_old.linear().col(2); - Vec3d new_z = text_to_world_old.linear().col(0).cross(text_to_world_old.linear().col(1)); - text_to_world_old.linear().col(2) = new_z * (old_z.dot(new_z) / new_z.squaredNorm()); + Vec3d old_z = world_linear.col(2); + Vec3d new_z = world_linear.col(0).cross(world_linear.col(1)); + world_linear.col(2) = new_z * (old_z.dot(new_z) / new_z.squaredNorm()); } - // normal transformed to volume - Vec3d text_z_world = text_to_world_old.linear() * Vec3d::UnitZ(); + Vec3d text_z_world = world_linear.col(2); // world_linear * Vec3d::UnitZ() auto z_rotation = Eigen::Quaternion::FromTwoVectors(text_z_world, hit->normal); - Transform3d text_to_world_new = z_rotation * text_to_world_old; + Transform3d world_new = z_rotation * m_surface_drag->world; + auto world_new_linear = world_new.linear(); // Fix up vector ?? - //auto y_rotation = Eigen::Quaternion::FromTwoVectors(text_y_world, hit->normal); + //auto y_rotation = Eigen::Quaternion::FromTwoVectors(text_y_world, hit->normal); // Edit position from right Transform3d volume_new{Eigen::Translation(m_surface_drag->instance_inv * hit->position)}; - volume_new.linear() = instance.linear().inverse() * text_to_world_new.linear(); + volume_new.linear() = m_surface_drag->instance_inv.linear() * world_new_linear; + // Check that transformation matrix is valid transformation assert(volume_new.matrix()(0, 0) == volume_new.matrix()(0, 0)); // Check valid transformation not a NAN if (volume_new.matrix()(0, 0) != volume_new.matrix()(0, 0)) return true; - // Check scale in world - // Calculate Scale to keep size after move over scaled surface - m_surface_drag->y_scale = priv::calc_scale(text_to_world_old.linear(), text_to_world_new.linear(), Vec3d::UnitY()); - m_surface_drag->z_scale = priv::calc_scale(text_to_world_old.linear(), text_to_world_new.linear(), Vec3d::UnitZ()); - - // recalculate rotation for scaled volume - //Transform3d hit_to_volume2 = hit_to_instance * (m_surface_drag->volume_tr*scale).inverse(); - //z_t = hit_to_volume2.linear() * hit->normal.cast(); - //bool exist_rotate2 = priv::allign_z(z_t, rotate); - //volume_tr = m_surface_drag->volume_tr * translate * rotate * scale; + // Check that scale in world did not changed + assert(!priv::calc_scale(world_linear, world_new_linear, Vec3d::UnitY()).has_value()); + assert(!priv::calc_scale(world_linear, world_new_linear, Vec3d::UnitZ()).has_value()); const TextConfiguration &tc = *m_volume->text_configuration; // fix baked transformation from .3mf store process @@ -888,7 +720,7 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) volume_new.translate(translate); } - // Update transformation forf all instances + // Update transformation for all instances for (GLVolume *vol : m_parent.get_volumes().volumes) { if (vol->object_idx() != m_surface_drag->gl_volume->object_idx() || vol->volume_idx() != m_surface_drag->gl_volume->volume_idx()) @@ -936,23 +768,6 @@ bool GLGizmoEmboss::on_init() std::string GLGizmoEmboss::on_get_name() const { return _u8L("Emboss"); } void GLGizmoEmboss::on_render() { - // Render debug view to surface move - if (m_surface_drag.has_value()) { - auto glvol = priv::get_gl_volume(m_parent.get_selection()); - auto tr = glvol->get_instance_transformation().get_matrix(); - CoordAxes from; - from.set_origin(m_surface_drag->from); - //from.render(tr, 2.); - - CoordAxes to; - to.set_origin(m_surface_drag->to); - //to.render(tr, 2.); - - CoordAxes axe; - axe.render(m_surface_drag->f_tr); - axe.render(m_surface_drag->t_tr); - } - // no volume selected if (m_volume == nullptr || priv::get_volume(m_parent.get_selection().get_model()->objects, m_volume_id) == nullptr) @@ -3745,12 +3560,12 @@ void GLGizmoEmboss::draw_advanced() if (ImGui::Button(_u8L("Reset scale").c_str())) { GLVolume *gl_volume = priv::get_gl_volume(m_parent); if (gl_volume != nullptr) { - Transform3d w = gl_volume->world_matrix(); - priv::reset_skew_respect_z(w); - Transform3d i = gl_volume->get_instance_transformation().get_matrix(); - Transform3d v_new = i.inverse() * w; - gl_volume->set_volume_transformation(v_new); - m_parent.do_move(L("Reset scale")); + //Transform3d w = gl_volume->world_matrix(); + //priv::reset_skew_respect_z(w); + //Transform3d i = gl_volume->get_instance_transformation().get_matrix(); + //Transform3d v_new = i.inverse() * w; + //gl_volume->set_volume_transformation(v_new); + //m_parent.do_move(L("Reset scale")); } } else if (ImGui::IsItemHovered()) { ImGui::SetTooltip("%s", _u8L("Reset skew of text to be normal in world").c_str()); @@ -4253,7 +4068,7 @@ bool priv::start_create_volume_on_surface_job( Transform3d world_new = surface_trmat; // Reset skew - priv::reset_skew_respect_z(world_new); + //priv::reset_skew_respect_z(world_new); Transform3d volume_trmat = instance.inverse() * world_new; start_create_volume_job(obj, volume_trmat, emboss_data, volume_type); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index e1fded204d..209d025fbb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp @@ -317,13 +317,13 @@ private: // hold screen coor offset of cursor from object center Vec2d mouse_offset; + // Start dragging text transformations to world + Transform3d world; + // Invers transformation of text volume instance // Help convert world transformation to instance space Transform3d instance_inv; - // Start dragging volume transformation - Transform3d volume_tr; - // Dragged gl volume GLVolume *gl_volume; @@ -331,19 +331,6 @@ private: RaycastManager::AllowVolumes condition; bool exist_hit = true; - - // Visuzalization - Vec3d from = Vec3d::Zero(); - Vec3d to = Vec3d::Zero(); - - Vec3d from_dir = Vec3d::UnitZ(); - Vec3d to_dir = Vec3d::UnitZ(); - - Transform3d f_tr = Transform3d::Identity(); - Transform3d t_tr = Transform3d::Identity(); - - std::optional y_scale; - std::optional z_scale; }; // Keep data about dragging only during drag&drop std::optional m_surface_drag;