From b7f4159d57b1769dfbdf0f91c16afc01b604d02c Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Tue, 28 Feb 2023 16:17:09 +0100 Subject: [PATCH] extend functionality of surface drag --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 104 +----------------------- src/slic3r/GUI/SurfaceDrag.cpp | 99 +++++++++++++++++++++- src/slic3r/GUI/SurfaceDrag.hpp | 38 +++++++++ src/slic3r/Utils/RaycastManager.cpp | 22 ++--- src/slic3r/Utils/RaycastManager.hpp | 4 +- 5 files changed, 149 insertions(+), 118 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 7bf9635a4d..a0a367d938 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -345,16 +345,6 @@ bool GLGizmoEmboss::on_mouse_for_rotation(const wxMouseEvent &mouse_event) } namespace priv { -/// -/// Get transformation to world -/// - use fix after store to 3mf when exists -/// -/// Scene volume -/// To identify MovelVolume with fix transformation -/// -static Transform3d world_matrix(const GLVolume *gl_volume, const Model *model); -static Transform3d world_matrix(const Selection &selection); - /// /// Change position of emboss window /// @@ -363,36 +353,6 @@ static Transform3d world_matrix(const Selection &selection); static void change_window_position(std::optional &output_window_offset, bool try_to_fix); } // namespace priv -Transform3d priv::world_matrix(const GLVolume *gl_volume, const Model *model) -{ - if (!gl_volume) - return Transform3d::Identity(); - Transform3d res = gl_volume->world_matrix(); - - if (!model) - return res; - - const ModelVolume* mv = get_model_volume(*gl_volume, model->objects); - if (!mv) - return res; - - const std::optional &tc = mv->text_configuration; - if (!tc.has_value()) - return res; - - const std::optional &fix = tc->fix_3mf_tr; - if (!fix.has_value()) - return res; - - return res * fix->inverse(); -} - -Transform3d priv::world_matrix(const Selection &selection) -{ - const GLVolume *gl_volume = get_selected_gl_volume(selection); - return world_matrix(gl_volume, selection.get_model()); -} - bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) { // exist selected volume? @@ -1115,17 +1075,6 @@ static inline void execute_job(std::shared_ptr j) }); } -namespace priv { -/// -/// Calculate translation of text volume onto surface of model -/// -/// Text -/// AABB trees of object. Actualize object containing text -/// Transformation of actual instance -/// Offset of volume in volume coordinate -std::optional calc_surface_offset(const ModelVolume &volume, RaycastManager &raycast_manager, const Selection &selection); -} // namespace priv - bool GLGizmoEmboss::process() { // no volume is selected -> selection from right panel @@ -1160,7 +1109,7 @@ bool GLGizmoEmboss::process() // when it is new applying of use surface than move origin onto surfaca if (!m_volume->text_configuration->style.prop.use_surface) { - auto offset = priv::calc_surface_offset(*m_volume, m_raycast_manager, m_parent.get_selection()); + auto offset = calc_surface_offset(m_parent.get_selection(), m_raycast_manager); if (offset.has_value()) text_tr *= Eigen::Translation(*offset); } @@ -1231,7 +1180,7 @@ bool priv::apply_camera_dir(const Camera &camera, GLCanvas3D &canvas) { if (sel.is_empty()) return false; // camera direction transformed into volume coordinate system - Transform3d to_world = priv::world_matrix(sel); + Transform3d to_world = world_matrix_fixed(sel); Vec3d cam_dir_tr = to_world.inverse().linear() * cam_dir; cam_dir_tr.normalize(); @@ -2949,53 +2898,6 @@ void GLGizmoEmboss::do_rotate(float relative_z_angle) m_parent.do_rotate(snapshot_name); } -std::optional priv::calc_surface_offset(const ModelVolume &volume, RaycastManager &raycast_manager, const Selection &selection) { - // Move object on surface - auto cond = RaycastManager::SkipVolume(volume.id().id); - raycast_manager.actualize(volume.get_object(), &cond); - - //const Selection &selection = m_parent.get_selection(); - const GLVolume *gl_volume = get_selected_gl_volume(selection); - Transform3d to_world = priv::world_matrix(gl_volume, selection.get_model()); - Vec3d point = to_world * Vec3d::Zero(); - Vec3d direction = to_world.linear() * (-Vec3d::UnitZ()); - - // ray in direction of text projection(from volume zero to z-dir) - std::optional hit_opt = raycast_manager.closest_hit(point, direction, &cond); - - // Try to find closest point when no hit object in emboss direction - if (!hit_opt.has_value()) { - std::optional close_point_opt = raycast_manager.closest(point); - - // 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 - const RaycastManager::Hit &hit = *hit_opt; - 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; -} - void GLGizmoEmboss::draw_advanced() { const auto &ff = m_style_manager.get_font_file_with_cache(); @@ -3610,7 +3512,7 @@ bool priv::start_create_volume_on_surface_job( auto cond = RaycastManager::AllowVolumes({vol_id}); RaycastManager::Meshes meshes = create_meshes(canvas, cond); - raycaster.actualize(obj, &cond, &meshes); + raycaster.actualize(*obj, &cond, &meshes); const Camera &camera = plater->get_camera(); std::optional hit = ray_from_camera(raycaster, screen_coor, camera, &cond); diff --git a/src/slic3r/GUI/SurfaceDrag.cpp b/src/slic3r/GUI/SurfaceDrag.cpp index 46b6121588..33f64c0c61 100644 --- a/src/slic3r/GUI/SurfaceDrag.cpp +++ b/src/slic3r/GUI/SurfaceDrag.cpp @@ -104,11 +104,14 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event, gl_volumes[hovered_idx] != gl_volume) return false; - const ModelObject *object = get_model_object(*gl_volume, canvas.get_model()->objects); + const ModelObject *object = get_model_object(*gl_volume, canvas.get_model()->objects); + assert(object != nullptr); + if (object == nullptr) + return false; + const ModelInstance *instance = get_model_instance(*gl_volume, *object); const ModelVolume *volume = get_model_volume(*gl_volume, *object); - - assert(object != nullptr && instance != nullptr && volume != nullptr); + assert(instance != nullptr && volume != nullptr); if (object == nullptr || instance == nullptr || volume == nullptr) return false; @@ -131,7 +134,7 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event, // initialize raycasters // INFO: It could slows down for big objects // (may be move to thread and do not show drag until it finish) - raycast_manager.actualize(instance, &condition, &meshes); + raycast_manager.actualize(*instance, &condition, &meshes); // wxCoord == int --> wx/types.h Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY()); @@ -242,4 +245,92 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event, return false; } +std::optional calc_surface_offset(const Selection &selection, RaycastManager &raycast_manager) { + const GLVolume *gl_volume_ptr = get_selected_gl_volume(selection); + if (gl_volume_ptr == nullptr) + return {}; + const GLVolume& gl_volume = *gl_volume_ptr; + + const ModelObjectPtrs &objects = selection.get_model()->objects; + const ModelVolume* volume = get_model_volume(gl_volume, objects); + if (volume == nullptr) + return {}; + + const ModelInstance* instance = get_model_instance(gl_volume, objects); + if (instance == nullptr) + return {}; + + // Move object on surface + auto cond = RaycastManager::SkipVolume(volume->id().id); + raycast_manager.actualize(*instance, &cond); + + Transform3d to_world = world_matrix_fixed(gl_volume, selection.get_model()->objects); + Vec3d point = to_world * Vec3d::Zero(); + Vec3d direction = to_world.linear() * (-Vec3d::UnitZ()); + + // ray in direction of text projection(from volume zero to z-dir) + std::optional hit_opt = raycast_manager.closest_hit(point, direction, &cond); + + // Try to find closest point when no hit object in emboss direction + if (!hit_opt.has_value()) { + std::optional close_point_opt = raycast_manager.closest(point); + + // 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 + const RaycastManager::Hit &hit = *hit_opt; + 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; +} + +Transform3d world_matrix_fixed(const GLVolume &gl_volume, const ModelObjectPtrs &objects) +{ + Transform3d res = gl_volume.world_matrix(); + + const ModelVolume *mv = get_model_volume(gl_volume, objects); + if (!mv) + return res; + + const std::optional &tc = mv->text_configuration; + if (!tc.has_value()) + return res; + + const std::optional &fix = tc->fix_3mf_tr; + if (!fix.has_value()) + return res; + + return res * fix->inverse(); +} + +Transform3d world_matrix_fixed(const Selection &selection) +{ + const GLVolume *gl_volume = get_selected_gl_volume(selection); + assert(gl_volume != nullptr); + if (gl_volume == nullptr) + return Transform3d::Identity(); + + return world_matrix_fixed(*gl_volume, selection.get_model()->objects); +} + } // namespace Slic3r::GUI \ No newline at end of file diff --git a/src/slic3r/GUI/SurfaceDrag.hpp b/src/slic3r/GUI/SurfaceDrag.hpp index c3dc9cd2db..a3765f86bf 100644 --- a/src/slic3r/GUI/SurfaceDrag.hpp +++ b/src/slic3r/GUI/SurfaceDrag.hpp @@ -12,6 +12,7 @@ class GLVolume; namespace Slic3r::GUI { class GLCanvas3D; +class Selection; struct Camera; // Data for drag&drop over surface with mouse @@ -37,11 +38,48 @@ struct SurfaceDrag bool exist_hit = true; }; +/// +/// Mouse event handler, when move(drag&drop) volume over model surface +/// NOTE: Dragged volume has to be selected. And also has to be hovered on start of dragging. +/// +/// Contain type of event and mouse position +/// Actual viewport of camera +/// Structure which keep information about dragging +/// Contain gl_volumes and selection +/// AABB trees for raycast in object +/// Refresh state inside of function +/// True when event is processed otherwise false bool on_mouse_surface_drag(const wxMouseEvent &mouse_event, const Camera &camera, std::optional &surface_drag, GLCanvas3D &canvas, RaycastManager &raycast_manager); +/// +/// Calculate translation of volume onto surface of model +/// +/// Must contain only one selected volume, Transformation of current instance +/// AABB trees of object. Actualize object +/// Offset of volume in volume coordinate +std::optional calc_surface_offset(const Selection &selection, RaycastManager &raycast_manager); + +/// +/// Get transformation to world +/// - use fix after store to 3mf when exists +/// +/// Scene volume +/// To identify Model volume with fix transformation +/// Fixed Transformation of gl_volume +Transform3d world_matrix_fixed(const GLVolume &gl_volume, const ModelObjectPtrs& objects); + +/// +/// Get transformation to world +/// - use fix after store to 3mf when exists +/// NOTE: when not one volume selected return identity +/// +/// Selected volume +/// Fixed Transformation of selected volume in selection +Transform3d world_matrix_fixed(const Selection &selection); + } // namespace Slic3r::GUI #endif // slic3r_SurfaceDrag_hpp_ \ No newline at end of file diff --git a/src/slic3r/Utils/RaycastManager.cpp b/src/slic3r/Utils/RaycastManager.cpp index 18c9bb2f19..63cb580dbe 100644 --- a/src/slic3r/Utils/RaycastManager.cpp +++ b/src/slic3r/Utils/RaycastManager.cpp @@ -7,8 +7,8 @@ namespace priv { using namespace Slic3r; static void actualize(RaycastManager::Meshes &meshes, const ModelVolumePtrs &volumes, const RaycastManager::ISkip *skip, RaycastManager::Meshes *input = nullptr); 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::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; } @@ -16,23 +16,23 @@ static bool is_lower(const RaycastManager::TrItem &i1, const RaycastManager::TrI return is_lower_key(i1.first, i2.first); }; } -void RaycastManager::actualize(const ModelObject *object, const ISkip *skip, Meshes *meshes) +void RaycastManager::actualize(const ModelObject &object, const ISkip *skip, Meshes *meshes) { // actualize MeshRaycaster - priv::actualize(m_meshes, object->volumes, skip, meshes); + priv::actualize(m_meshes, object.volumes, skip, meshes); // 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) { + 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) { + for (const ModelInstance *instance : object.instances) { const Transform3d &instrance_tr = instance->get_matrix(); Transform3d transformation = instrance_tr * volume_tr; - TrKey key = priv::create_key(volume, instance); + TrKey key = priv::create_key(*volume, *instance); auto item = priv::find(m_transformations, key); if (item != m_transformations.end()) { // actualize transformation all the time @@ -56,9 +56,9 @@ void RaycastManager::actualize(const ModelObject *object, const ISkip *skip, Mes std::sort(m_transformations.begin(), m_transformations.end(), priv::is_lower); } -void RaycastManager::actualize(const ModelInstance *instance, const ISkip *skip, Meshes *meshes) +void RaycastManager::actualize(const ModelInstance &instance, const ISkip *skip, Meshes *meshes) { - const ModelVolumePtrs &volumes = instance->get_object()->volumes; + const ModelVolumePtrs &volumes = instance.get_object()->volumes; // actualize MeshRaycaster priv::actualize(m_meshes, volumes, skip, meshes); @@ -72,9 +72,9 @@ void RaycastManager::actualize(const ModelInstance *instance, const ISkip *skip, if (skip != nullptr && skip->skip(volume->id().id)) continue; const Transform3d &volume_tr = volume->get_matrix(); - const Transform3d &instrance_tr = instance->get_matrix(); + const Transform3d &instrance_tr = instance.get_matrix(); Transform3d transformation = instrance_tr * volume_tr; - TrKey key = priv::create_key(volume, instance); + TrKey key = priv::create_key(*volume, instance); auto item = priv::find(m_transformations, key); if (item != m_transformations.end()) { // actualize transformation all the time diff --git a/src/slic3r/Utils/RaycastManager.hpp b/src/slic3r/Utils/RaycastManager.hpp index a3cd3ef910..41ec82d6c8 100644 --- a/src/slic3r/Utils/RaycastManager.hpp +++ b/src/slic3r/Utils/RaycastManager.hpp @@ -86,8 +86,8 @@ public: /// Model representation /// Condifiton for skip actualization /// Speed up for already created AABBtrees - void actualize(const ModelObject *object, const ISkip *skip = nullptr, Meshes *meshes = nullptr); - void actualize(const ModelInstance *instance, const ISkip *skip = nullptr, Meshes* meshes = nullptr); + void actualize(const ModelObject &object, const ISkip *skip = nullptr, Meshes *meshes = nullptr); + void actualize(const ModelInstance &instance, const ISkip *skip = nullptr, Meshes* meshes = nullptr); class SkipVolume: public ISkip {