From 7c1cf6fa7e3c540beef5f9eeedb314a485ac9cb4 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Fri, 8 Apr 2022 15:05:43 +0200 Subject: [PATCH] Offseted move with text volume over surface + use fix of .3mf transformation --- src/slic3r/GUI/CameraUtils.cpp | 8 +- src/slic3r/GUI/CameraUtils.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 155 ++++++++++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp | 3 + 4 files changed, 118 insertions(+), 49 deletions(-) diff --git a/src/slic3r/GUI/CameraUtils.cpp b/src/slic3r/GUI/CameraUtils.cpp index 768c491c6d..0081b32b18 100644 --- a/src/slic3r/GUI/CameraUtils.cpp +++ b/src/slic3r/GUI/CameraUtils.cpp @@ -27,7 +27,7 @@ Points CameraUtils::project(const Camera & camera, result.reserve(points.size()); int window_height = viewport[3]; - // Iterate over all points and determine whether they're in the rectangle. + // convert to points --> loss precision for (int i = 0; i < projections.rows(); ++i) { double x = projections(i, 0); double y = projections(i, 1); @@ -37,6 +37,12 @@ Points CameraUtils::project(const Camera & camera, return result; } +Point CameraUtils::project(const Camera &camera, const Vec3d &point) +{ + // IMPROVE: do it faster when you need it (inspire in project multi point) + return project(camera, std::vector{point}).front(); +} + Slic3r::Polygon CameraUtils::create_hull2d(const Camera & camera, const GLVolume &volume) { diff --git a/src/slic3r/GUI/CameraUtils.hpp b/src/slic3r/GUI/CameraUtils.hpp index 262c1ceff6..7d1b43d64e 100644 --- a/src/slic3r/GUI/CameraUtils.hpp +++ b/src/slic3r/GUI/CameraUtils.hpp @@ -25,6 +25,7 @@ public: /// projected points by camera into coordinate of camera. /// x(from left to right), y(from top to bottom) static Points project(const Camera& camera, const std::vector &points); + static Point project(const Camera& camera, const Vec3d &point); /// /// Create hull around GLVolume in 2d space of camera diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index c5fa0010bf..cea3112fde 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -45,6 +45,7 @@ #define SHOW_FONT_FILE_PROPERTY // ascent, descent, line gap, cache --> in advanced #define SHOW_FONT_COUNT // count of enumerated font --> in font combo box #define SHOW_CONTAIN_3MF_FIX // when contain fix matrix --> show gray '3mf' next to close button +#define SHOW_OFFSET_DURING_DRAGGING // when drag with text over surface visualize used center #define SHOW_IMGUI_ATLAS #define SHOW_ICONS_TEXTURE #define SHOW_FINE_POSITION @@ -106,32 +107,6 @@ void GLGizmoEmboss::set_fine_position() ImGuiWrapper::draw(rect); } -#ifdef SHOW_FINE_POSITION -static void draw_fine_position(const Selection &selection) -{ - const Selection::IndicesList indices = selection.get_volume_idxs(); - // no selected volume - if (indices.empty()) return; - const GLVolume *volume = selection.get_volume(*indices.begin()); - // bad volume selected (e.g. deleted one) - if (volume == nullptr) return; - - const Camera &camera = wxGetApp().plater()->get_camera(); - Slic3r::Polygon hull = CameraUtils::create_hull2d(camera, *volume); - - ImVec2 windows_size(174, 202); - Size c_size = m_parent.get_canvas_size(); - ImVec2 canvas_size(c_size.get_width(), c_size.get_height()); - ImVec2 offset = ImGuiWrapper::suggest_location(windows_size, hull,canvas_size); - Slic3r::Polygon rect( - {Point(offset.x, offset.y), Point(offset.x + windows_size.x, offset.y), - Point(offset.x + windows_size.x, offset.y + windows_size.y), - Point(offset.x, offset.y + windows_size.y)}); - ImGuiWrapper::draw(hull); - ImGuiWrapper::draw(rect); -} -#endif // SHOW_FINE_POSITION - void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mouse_pos) { assert(volume_type == ModelVolumeType::MODEL_PART || @@ -168,20 +143,6 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mous queue_job(worker, std::make_unique(std::move(data))); } -#ifdef DRAW_PLACE_TO_ADD_TEXT -static void draw_place_to_add_text() { - ImVec2 mp = ImGui::GetMousePos(); - Vec2d mouse_pos(mp.x, mp.y); - const Camera &camera = wxGetApp().plater()->get_camera(); - Vec3d p1 = CameraUtils::get_z0_position(camera, mouse_pos); - std::vector rect3d{p1 + Vec3d(5, 5, 0), p1 + Vec3d(-5, 5, 0), - p1 + Vec3d(-5, -5, 0), p1 + Vec3d(5, -5, 0)}; - Points rect2d = CameraUtils::project(camera, rect3d); - ImGuiWrapper::draw(Slic3r::Polygon(rect2d)); -} -#endif // DRAW_PLACE_TO_ADD_TEXT - - bool GLGizmoEmboss::on_mouse_for_rotation(const wxMouseEvent &mouse_event) { if (mouse_event.Moving()) return false; @@ -226,6 +187,43 @@ bool GLGizmoEmboss::on_mouse_for_rotation(const wxMouseEvent &mouse_event) return used; } +static Vec2d calc_mouse_to_center_text_offset(const Vec2d& mouse, const ModelVolume& mv) { + const Transform3d &volume_tr = mv.get_matrix(); + const Camera &camera = wxGetApp().plater()->get_camera(); + assert(mv.text_configuration.has_value()); + + auto calc_offset = [&mouse, &volume_tr, &camera, &mv] + (const Transform3d &instrance_tr) -> Vec2d { + Transform3d to_world = instrance_tr * volume_tr; + + // Use fix of .3mf loaded tranformation when exist + if (mv.text_configuration->fix_3mf_tr.has_value()) + to_world = to_world * (*mv.text_configuration->fix_3mf_tr); + // zero point of volume in world coordinate system + Vec3d volume_center = to_world.translation(); + // screen coordinate of volume center + Vec2i coor = CameraUtils::project(camera, volume_center); + return coor.cast() - mouse; + }; + + auto object = mv.get_object(); + assert(!object->instances.empty()); + // Speed up for one instance + if (object->instances.size() == 1) + return calc_offset(object->instances.front()->get_matrix()); + + Vec2d nearest_offset; + double nearest_offset_size = std::numeric_limits::max(); + for (const ModelInstance *instance : object->instances) { + Vec2d offset = calc_offset(instance->get_matrix()); + double offset_size = offset.norm(); + if (nearest_offset_size < offset_size) continue; + nearest_offset_size = offset_size; + nearest_offset = offset; + } + return nearest_offset; +} + bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) { // filter events @@ -257,6 +255,10 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) allowed_volumes_id.emplace_back(v->id().id); } } + + // wxCoord == int --> wx/types.h + Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY()); + Vec2d mouse_pos = mouse_coord.cast(); RaycastManager::AllowVolumes condition(std::move(allowed_volumes_id)); // detect start text dragging @@ -265,14 +267,14 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) // IMPROVE: move to job, for big scene it slows down ModelObject *act_model_object = act_model_volume->get_object(); m_raycast_manager.actualize(act_model_object, &condition); + m_dragging_mouse_offset = calc_mouse_to_center_text_offset(mouse_pos, *m_volume); return false; } - // wxCoord == int --> wx/types.h - Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY()); - Vec2d mouse_pos = mouse_coord.cast(); const Camera &camera = wxGetApp().plater()->get_camera(); - auto hit = m_raycast_manager.unproject(mouse_pos, camera, &condition); + assert(m_dragging_mouse_offset.has_value()); + Vec2d offseted_mouse = mouse_pos + *m_dragging_mouse_offset; + auto hit = m_raycast_manager.unproject(offseted_mouse, camera, &condition); if (!hit.has_value()) { // there is no hit // show common translation of object @@ -310,7 +312,8 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) m_parent.toggle_model_objects_visibility(true); // Apply temporary position - m_temp_transformation = {}; + m_temp_transformation = {}; + m_dragging_mouse_offset = {}; } return false; } @@ -414,6 +417,61 @@ void GLGizmoEmboss::on_render_for_picking() { m_rotate_gizmo.render_for_picking(); } +#ifdef SHOW_FINE_POSITION +// draw suggested position of window +static void draw_fine_position(const Selection &selection, + const Size &canvas, + const ImVec2 &windows_size) +{ + const Selection::IndicesList indices = selection.get_volume_idxs(); + // no selected volume + if (indices.empty()) return; + const GLVolume *volume = selection.get_volume(*indices.begin()); + // bad volume selected (e.g. deleted one) + if (volume == nullptr) return; + + const Camera &camera = wxGetApp().plater()->get_camera(); + Slic3r::Polygon hull = CameraUtils::create_hull2d(camera, *volume); + ImVec2 canvas_size(canvas.get_width(), canvas.get_height()); + ImVec2 offset = ImGuiWrapper::suggest_location(windows_size, hull, + canvas_size); + Slic3r::Polygon rect( + {Point(offset.x, offset.y), Point(offset.x + windows_size.x, offset.y), + Point(offset.x + windows_size.x, offset.y + windows_size.y), + Point(offset.x, offset.y + windows_size.y)}); + ImGuiWrapper::draw(hull); + ImGuiWrapper::draw(rect); +} +#endif // SHOW_FINE_POSITION + +#ifdef DRAW_PLACE_TO_ADD_TEXT +static void draw_place_to_add_text() +{ + ImVec2 mp = ImGui::GetMousePos(); + Vec2d mouse_pos(mp.x, mp.y); + const Camera &camera = wxGetApp().plater()->get_camera(); + Vec3d p1 = CameraUtils::get_z0_position(camera, mouse_pos); + std::vector rect3d{p1 + Vec3d(5, 5, 0), p1 + Vec3d(-5, 5, 0), + p1 + Vec3d(-5, -5, 0), p1 + Vec3d(5, -5, 0)}; + Points rect2d = CameraUtils::project(camera, rect3d); + ImGuiWrapper::draw(Slic3r::Polygon(rect2d)); +} +#endif // DRAW_PLACE_TO_ADD_TEXT + +#ifdef SHOW_OFFSET_DURING_DRAGGING +static void draw_mouse_offset(const std::optional &offset) +{ + if (!offset.has_value()) return; + // debug draw + auto draw_list = ImGui::GetOverlayDrawList(); + ImVec2 p1 = ImGui::GetMousePos(); + ImVec2 p2(p1.x + offset->x(), p1.y + offset->y()); + ImU32 color = ImGui::GetColorU32(ImGuiWrapper::COL_ORANGE_LIGHT); + float thickness = 3.f; + draw_list->AddLine(p1, p2, color, thickness); +} +#endif // SHOW_OFFSET_DURING_DRAGGING + void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit) { initialize(); @@ -424,13 +482,14 @@ void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit) ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, min_window_size); #ifdef SHOW_FINE_POSITION - // draw suggested position of window - draw_fine_position(m_parent.get_selection()); + draw_fine_position(m_parent.get_selection(), m_parent.get_canvas_size(), min_window_size); #endif // SHOW_FINE_POSITION #ifdef DRAW_PLACE_TO_ADD_TEXT draw_place_to_add_text(); #endif // DRAW_PLACE_TO_ADD_TEXT - +#ifdef SHOW_OFFSET_DURING_DRAGGING + draw_mouse_offset(m_dragging_mouse_offset); +#endif // SHOW_OFFSET_DURING_DRAGGING // check if is set window offset if (m_set_window_offset.has_value()) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index fc4b9b2323..c1de15f951 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp @@ -232,6 +232,9 @@ private: // Rotation gizmo GLGizmoRotate m_rotate_gizmo; + // when draging with text object hold screen offset of cursor from object center + std::optional m_dragging_mouse_offset; + // TODO: it should be accessible by other gizmo too. // May be move to plater? RaycastManager m_raycast_manager;