From 1ca872f81ebf797358abc5bc1eb758b07bbc0f0e Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 30 Sep 2020 15:11:17 +0200 Subject: [PATCH 01/14] Fixed size of selected single volumes --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 53 +++++++++++------------ 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 7243e8c73..0d108ba7d 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -65,8 +65,8 @@ static wxBitmapComboBox* create_word_local_combo(wxWindow *parent) temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT); - temp->Append(_(L("World coordinates"))); - temp->Append(_(L("Local coordinates"))); + temp->Append(_L("World coordinates")); + temp->Append(_L("Local coordinates")); temp->SetSelection(0); temp->SetValue(temp->GetString(0)); @@ -85,7 +85,7 @@ static wxBitmapComboBox* create_word_local_combo(wxWindow *parent) temp->SetItemBitmap(0, empty_bmp); #endif - temp->SetToolTip(_(L("Select coordinate space, in which the transformation will be performed."))); + temp->SetToolTip(_L("Select coordinate space, in which the transformation will be performed.")); return temp; } @@ -108,8 +108,8 @@ void msw_rescale_word_local_combo(wxBitmapComboBox* combo) // Set rescaled size combo->SetSize(size); - combo->Append(_(L("World coordinates"))); - combo->Append(_(L("Local coordinates"))); + combo->Append(_L("World coordinates")); + combo->Append(_L("Local coordinates")); wxBitmap empty_bmp(1, combo->GetFont().GetPixelSize().y + 2); empty_bmp.SetWidth(0); @@ -158,9 +158,9 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : sizer->Add(m_fix_throught_netfab_bitmap); - auto name_label = new wxStaticText(m_parent, wxID_ANY, _(L("Name"))+":"); + auto name_label = new wxStaticText(m_parent, wxID_ANY, _L("Name")+":"); set_font_and_background_style(name_label, wxGetApp().normal_font()); - name_label->SetToolTip(_(L("Object name"))); + name_label->SetToolTip(_L("Object name")); sizer->Add(name_label); m_main_grid_sizer->Add(sizer); @@ -268,7 +268,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : // We will add a button to toggle mirroring to each axis: auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_off", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW); - btn->SetToolTip(wxString::Format(_(L("Toggle %c axis mirroring")), (int)label)); + btn->SetToolTip(wxString::Format(_L("Toggle %c axis mirroring"), (int)label)); btn->SetBitmapDisabled_(m_mirror_bitmap_hidden); m_mirror_buttons[axis_idx].first = btn; @@ -342,7 +342,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : // Add drop to bed button m_drop_to_bed_button = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "drop_to_bed")); - m_drop_to_bed_button->SetToolTip(_(L("Drop to bed"))); + m_drop_to_bed_button->SetToolTip(_L("Drop to bed")); m_drop_to_bed_button->Bind(wxEVT_BUTTON, [=](wxCommandEvent& e) { // ??? GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); @@ -354,7 +354,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : const Geometry::Transformation& instance_trafo = volume->get_instance_transformation(); Vec3d diff = m_cache.position - instance_trafo.get_matrix(true).inverse() * Vec3d(0., 0., get_volume_min_z(volume)); - Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Drop to bed"))); + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed")); change_position_value(0, diff.x()); change_position_value(1, diff.y()); change_position_value(2, diff.z()); @@ -369,7 +369,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : // Add reset rotation button m_reset_rotation_button = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo")); - m_reset_rotation_button->SetToolTip(_(L("Reset rotation"))); + m_reset_rotation_button->SetToolTip(_L("Reset rotation")); m_reset_rotation_button->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) { GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); Selection& selection = canvas->get_selection(); @@ -404,9 +404,9 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : // Add reset scale button m_reset_scale_button = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo")); - m_reset_scale_button->SetToolTip(_(L("Reset scale"))); + m_reset_scale_button->SetToolTip(_L("Reset scale")); m_reset_scale_button->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) { - Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Reset scale"))); + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset scale")); change_scale_value(0, 100.); change_scale_value(1, 100.); change_scale_value(2, 100.); @@ -509,8 +509,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection) m_world_coordinates = true; ObjectList* obj_list = wxGetApp().obj_list(); - if (selection.is_single_full_instance()) - { + if (selection.is_single_full_instance()) { // all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); m_new_position = volume->get_instance_offset(); @@ -528,7 +527,8 @@ void ObjectManipulation::update_settings_value(const Selection& selection) m_new_rotation = Vec3d::Zero(); m_new_size = selection.get_scaled_instance_bounding_box().size(); m_new_scale = m_new_size.cwiseProduct(selection.get_unscaled_instance_bounding_box().size().cwiseInverse()) * 100.; - } else { + } + else { m_new_rotation = volume->get_instance_rotation() * (180. / M_PI); m_new_size = volume->get_instance_transformation().get_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size()); m_new_scale = volume->get_instance_scaling_factor() * 100.; @@ -536,8 +536,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection) m_new_enabled = true; } - else if (selection.is_single_full_object() && obj_list->is_selected(itObject)) - { + else if (selection.is_single_full_object() && obj_list->is_selected(itObject)) { const BoundingBoxf3& box = selection.get_bounding_box(); m_new_position = box.center(); m_new_rotation = Vec3d::Zero(); @@ -547,18 +546,16 @@ void ObjectManipulation::update_settings_value(const Selection& selection) m_new_scale_label_string = L("Scale"); m_new_enabled = true; } - else if (selection.is_single_modifier() || selection.is_single_volume()) - { + else if (selection.is_single_modifier() || selection.is_single_volume()) { // the selection contains a single volume const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); m_new_position = volume->get_volume_offset(); m_new_rotation = volume->get_volume_rotation() * (180. / M_PI); m_new_scale = volume->get_volume_scaling_factor() * 100.; - m_new_size = volume->get_volume_transformation().get_scaling_factor().cwiseProduct(volume->bounding_box().size()); + m_new_size = volume->get_instance_transformation().get_scaling_factor().cwiseProduct(volume->get_volume_transformation().get_scaling_factor().cwiseProduct(volume->bounding_box().size())); m_new_enabled = true; } - else if (obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot)) - { + else if (obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot)) { reset_settings_value(); m_new_move_label_string = L("Translate"); m_new_rotate_label_string = L("Rotate"); @@ -624,7 +621,7 @@ void ObjectManipulation::update_if_dirty() if (selection.requires_uniform_scale()) { m_lock_bnt->SetLock(true); - m_lock_bnt->SetToolTip(_(L("You cannot use non-uniform scaling mode for multiple objects/parts selection"))); + m_lock_bnt->SetToolTip(_L("You cannot use non-uniform scaling mode for multiple objects/parts selection")); m_lock_bnt->disable(); } else { @@ -924,11 +921,11 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value) if (! Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) { // Cannot apply scaling in the world coordinate system. wxMessageDialog dlg(GUI::wxGetApp().mainframe, - _(L("The currently manipulated object is tilted (rotation angles are not multiples of 90°).\n" + _L("The currently manipulated object is tilted (rotation angles are not multiples of 90°).\n" "Non-uniform scaling of tilted objects is only possible in the World coordinate system,\n" - "once the rotation is embedded into the object coordinates.")) + "\n" + - _(L("This operation is irreversible.\n" - "Do you want to proceed?")), + "once the rotation is embedded into the object coordinates.") + "\n" + + _L("This operation is irreversible.\n" + "Do you want to proceed?"), SLIC3R_APP_NAME, wxYES_NO | wxCANCEL | wxCANCEL_DEFAULT | wxICON_QUESTION); if (dlg.ShowModal() != wxID_YES) { From 8bf0f75e83846ba2588c75a3f4330175b9a87117 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 30 Sep 2020 17:33:08 +0200 Subject: [PATCH 02/14] Fixed compilation with wxWidgets 3.0 --- src/slic3r/GUI/GCodeViewer.cpp | 2 ++ src/slic3r/GUI/GUI_Utils.hpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 0e3378e9a..8ab17717c 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index a68a0a88a..ad6bca720 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -116,7 +116,7 @@ public: this->Bind(EVT_DPI_CHANGED_SLICER, [this](const DpiChangedEvent& evt) { m_scale_factor = (float)evt.dpi / (float)DPI_DEFAULT; - m_new_font_point_size = get_default_font_for_dpi(evt.dpi).GetPointSize(); + m_new_font_point_size = get_default_font_for_dpi(this, evt.dpi).GetPointSize(); if (!m_can_rescale) return; From c696e6ec192cbf44e4073585999ff866d69f0e12 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 25 Sep 2020 09:07:52 +0200 Subject: [PATCH 03/14] Experiment with spherical cursor (painting gizmos) --- src/libslic3r/TriangleSelector.cpp | 8 +++++--- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index 9f04374fd..abbc3bc56 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -61,7 +61,7 @@ void TriangleSelector::select_patch(const Vec3f& hit, int facet_start, // add neighboring facets to list to be proccessed later for (int n=0; n<3; ++n) { int neighbor_idx = m_mesh->stl.neighbors_start[facet].neighbor[n]; - if (neighbor_idx >=0 && faces_camera(neighbor_idx)) + if (neighbor_idx >=0 && true/*faces_camera(neighbor_idx)*/) facets_to_check.push_back(neighbor_idx); } } @@ -206,8 +206,10 @@ void TriangleSelector::split_triangle(int facet_idx) // Calculate distance of a point from a line. bool TriangleSelector::is_point_inside_cursor(const Vec3f& point) const { - Vec3f diff = m_cursor.center - point; - return (diff - diff.dot(m_cursor.dir) * m_cursor.dir).squaredNorm() < m_cursor.radius_sqr; + Vec3f diff = m_cursor.center - point; + // return (diff - diff.dot(m_cursor.dir) * m_cursor.dir).squaredNorm() < m_cursor.radius_sqr; + + return diff.squaredNorm() < m_cursor.radius_sqr; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 939d3c48a..4b3b9e52b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -119,6 +119,8 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection) const void GLGizmoPainterBase::render_cursor_circle() const { + return; + const Camera& camera = wxGetApp().plater()->get_camera(); float zoom = (float)camera.get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; From 1ca8120398e00d37c439c32dad4994d836235750 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 30 Sep 2020 17:01:51 +0200 Subject: [PATCH 04/14] Sphere selection added as an option for painting gizmos --- src/libslic3r/TriangleSelector.cpp | 13 ++-- src/libslic3r/TriangleSelector.hpp | 7 +++ src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 64 +++++++++++++++++++- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 7 +++ src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp | 20 +++++- 6 files changed, 103 insertions(+), 10 deletions(-) diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index abbc3bc56..1462b1a76 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -35,14 +35,15 @@ void TriangleSelector::Triangle::set_division(int sides_to_split, int special_si void TriangleSelector::select_patch(const Vec3f& hit, int facet_start, const Vec3f& source, const Vec3f& dir, - float radius, EnforcerBlockerType new_state) + float radius, CursorType cursor_type, + EnforcerBlockerType new_state) { assert(facet_start < m_orig_size_indices); assert(is_approx(dir.norm(), 1.f)); // Save current cursor center, squared radius and camera direction, // so we don't have to pass it around. - m_cursor = {hit, source, dir, radius*radius}; + m_cursor = {hit, source, dir, radius*radius, cursor_type}; // In case user changed cursor size since last time, update triangle edge limit. if (m_old_cursor_radius != radius) { @@ -61,7 +62,7 @@ void TriangleSelector::select_patch(const Vec3f& hit, int facet_start, // add neighboring facets to list to be proccessed later for (int n=0; n<3; ++n) { int neighbor_idx = m_mesh->stl.neighbors_start[facet].neighbor[n]; - if (neighbor_idx >=0 && true/*faces_camera(neighbor_idx)*/) + if (neighbor_idx >=0 && (m_cursor.type == SPHERE || faces_camera(neighbor_idx))) facets_to_check.push_back(neighbor_idx); } } @@ -207,9 +208,11 @@ void TriangleSelector::split_triangle(int facet_idx) bool TriangleSelector::is_point_inside_cursor(const Vec3f& point) const { Vec3f diff = m_cursor.center - point; - // return (diff - diff.dot(m_cursor.dir) * m_cursor.dir).squaredNorm() < m_cursor.radius_sqr; - return diff.squaredNorm() < m_cursor.radius_sqr; + if (m_cursor.type == CIRCLE) + return (diff - diff.dot(m_cursor.dir) * m_cursor.dir).squaredNorm() < m_cursor.radius_sqr; + else // SPHERE + return diff.squaredNorm() < m_cursor.radius_sqr; } diff --git a/src/libslic3r/TriangleSelector.hpp b/src/libslic3r/TriangleSelector.hpp index be1b20ed4..899539c8e 100644 --- a/src/libslic3r/TriangleSelector.hpp +++ b/src/libslic3r/TriangleSelector.hpp @@ -17,6 +17,11 @@ enum class EnforcerBlockerType : int8_t; // to recursively subdivide the triangles and make the selection finer. class TriangleSelector { public: + enum CursorType { + CIRCLE, + SPHERE + }; + void set_edge_limit(float edge_limit); // Create new object on a TriangleMesh. The referenced mesh must @@ -29,6 +34,7 @@ public: const Vec3f& source, // camera position (mesh coords) const Vec3f& dir, // direction of the ray (mesh coords) float radius, // radius of the cursor + CursorType type, // current type of cursor EnforcerBlockerType new_state); // enforcer or blocker? // Get facets currently in the given state. @@ -127,6 +133,7 @@ protected: Vec3f source; Vec3f dir; float radius_sqr; + CursorType type; }; Cursor m_cursor; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 6b3456b60..58346a414 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -66,7 +66,7 @@ void GLGizmoFdmSupports::on_render() const render_triangles(selection); m_c->object_clipper()->render_cut(); - render_cursor_circle(); + render_cursor(); glsafe(::glDisable(GL_BLEND)); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 4b3b9e52b..e7d3e17c2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -21,6 +21,14 @@ GLGizmoPainterBase::GLGizmoPainterBase(GLCanvas3D& parent, const std::string& ic : GLGizmoBase(parent, icon_filename, sprite_id) { m_clipping_plane.reset(new ClippingPlane()); + // Make sphere and save it into a vertex buffer. + const TriangleMesh sphere_mesh = make_sphere(1., (2*M_PI)/24.); + for (size_t i=0; i(), + sphere_mesh.stl.facet_start[i].normal.cast()); + for (const stl_triangle_vertex_indices& indices : sphere_mesh.its.indices) + m_vbo_sphere.push_triangle(indices(0), indices(1), indices(2)); + m_vbo_sphere.finalize_geometry(true); } @@ -117,10 +125,18 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection) const } +void GLGizmoPainterBase::render_cursor() const +{ + if (m_cursor_type == TriangleSelector::SPHERE) + render_cursor_sphere(); + else + render_cursor_circle(); +} + + + void GLGizmoPainterBase::render_cursor_circle() const { - return; - const Camera& camera = wxGetApp().plater()->get_camera(); float zoom = (float)camera.get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; @@ -164,6 +180,46 @@ void GLGizmoPainterBase::render_cursor_circle() const } +void GLGizmoPainterBase::render_cursor_sphere() const +{ + int mesh_id = m_last_mesh_idx_and_hit.first; + if (mesh_id == -1) + return; + + const Vec3f hit_pos = m_last_mesh_idx_and_hit.second; + const Selection& selection = m_parent.get_selection(); + const ModelObject* mo = m_c->selection_info()->model_object(); + const ModelVolume* mv = mo->volumes[mesh_id]; + const ModelInstance* mi = mo->instances[selection.get_instance_idx()]; + const Transform3d instance_matrix = mi->get_transformation().get_matrix() * mv->get_matrix(); + const Transform3d instance_scaling_matrix_inverse = Geometry::Transformation(instance_matrix).get_matrix(true, true, false, true).inverse(); + const bool is_left_handed = Geometry::Transformation(instance_matrix).is_left_handed(); + + glsafe(::glPushMatrix()); + glsafe(::glMultMatrixd(instance_matrix.data())); + // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. + glsafe(::glTranslatef(hit_pos(0), hit_pos(1), hit_pos(2))); + glsafe(::glMultMatrixd(instance_scaling_matrix_inverse.data())); + glsafe(::glScaled(m_cursor_radius, m_cursor_radius, m_cursor_radius)); + + if (is_left_handed) + glFrontFace(GL_CW); + + float render_color[4] = { 0.f, 0.f, 0.f, 0.15f }; + if (m_button_down == Button::Left) + render_color[2] = 1.f; + else // right + render_color[0] = 1.f; + glsafe(::glColor4fv(render_color)); + + m_vbo_sphere.render(); + + if (is_left_handed) + glFrontFace(GL_CCW); + + glsafe(::glPopMatrix()); +} + bool GLGizmoPainterBase::is_mesh_point_clipped(const Vec3d& point) const { @@ -354,8 +410,9 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous assert(mesh_id < int(m_triangle_selectors.size())); m_triangle_selectors[mesh_id]->select_patch(closest_hit, closest_facet, camera_pos, - dir, limit, new_state); + dir, limit, m_cursor_type, new_state); m_last_mouse_position = mouse_position; + m_last_mesh_idx_and_hit = {mesh_id, closest_hit}; } return true; @@ -392,6 +449,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous m_button_down = Button::None; m_last_mouse_position = Vec2d::Zero(); + m_last_mesh_idx_and_hit = {-1, Vec3f::Zero()}; return true; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index b3e2b65f1..47bd26608 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -67,10 +67,13 @@ public: protected: void render_triangles(const Selection& selection) const; + void render_cursor() const; void render_cursor_circle() const; + void render_cursor_sphere() const; virtual void update_model_object() const = 0; virtual void update_from_model_object() = 0; void activate_internal_undo_redo_stack(bool activate); + void set_cursor_type(TriangleSelector::CursorType); float m_cursor_radius = 2.f; static constexpr float CursorRadiusMin = 0.4f; // cannot be zero @@ -80,16 +83,20 @@ protected: // For each model-part volume, store status and division of the triangles. std::vector> m_triangle_selectors; + TriangleSelector::CursorType m_cursor_type = TriangleSelector::SPHERE; + private: bool is_mesh_point_clipped(const Vec3d& point) const; float m_clipping_plane_distance = 0.f; std::unique_ptr m_clipping_plane; + GLIndexedVertexArray m_vbo_sphere; bool m_internal_stack_active = false; bool m_schedule_update = false; Vec2d m_last_mouse_position = Vec2d::Zero(); + std::pair m_last_mesh_idx_and_hit = {-1, Vec3f::Zero()}; enum class Button { None, diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index d0edfba13..1b1b1f10f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -25,6 +25,7 @@ bool GLGizmoSeam::on_init() m_desc["clipping_of_view"] = _L("Clipping of view") + ": "; m_desc["reset_direction"] = _L("Reset direction"); m_desc["cursor_size"] = _L("Cursor size") + ": "; + m_desc["cursor_type"] = _L("Cursor size") + ": "; m_desc["enforce_caption"] = _L("Left mouse button") + ": "; m_desc["enforce"] = _L("Enforce seam"); m_desc["block_caption"] = _L("Right mouse button") + " "; @@ -55,7 +56,7 @@ void GLGizmoSeam::on_render() const render_triangles(selection); m_c->object_clipper()->render_cut(); - render_cursor_circle(); + render_cursor(); glsafe(::glDisable(GL_BLEND)); } @@ -134,6 +135,23 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) ImGui::EndTooltip(); } + + m_imgui->text(m_desc.at("cursor_type")); + ImGui::SameLine(/*clipping_slider_left*/); + //ImGui::PushItemWidth(window_width - clipping_slider_left); + int selection = int(m_cursor_type); + m_imgui->combo(" ", {"Circle", "Sphere"}, selection); + m_cursor_type = TriangleSelector::CursorType(selection); + /*if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(max_tooltip_width); + ImGui::TextUnformatted(_L("Alt + Mouse wheel").ToUTF8().data()); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + }*/ + + + ImGui::Separator(); if (m_c->object_clipper()->get_position() == 0.f) m_imgui->text(m_desc.at("clipping_of_view")); From 6744a40cd5dfadc65d43131d13635f24744600ed Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 30 Sep 2020 22:10:03 +0200 Subject: [PATCH 05/14] Slight refactoring --- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 29 +++++++------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index e7d3e17c2..ef4b31877 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -314,9 +314,15 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } m_last_mouse_position = Vec2d::Zero(); // only actual hits should be saved + // Precalculate transformations of individual meshes. + std::vector trafo_matrices; + for (const ModelVolume* mv : mo->volumes) { + if (mv->is_model_part()) + trafo_matrices.emplace_back(instance_trafo * mv->get_matrix()); + } + // Now "click" into all the prepared points and spill paint around them. for (const Vec2d& mp : mouse_positions) { - std::vector>> hit_positions_and_facet_ids; bool clipped_mesh_was_hit = false; Vec3f normal = Vec3f::Zero(); @@ -327,9 +333,6 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous size_t closest_facet = 0; int closest_hit_mesh_id = -1; - // Transformations of individual meshes - std::vector trafo_matrices; - int mesh_id = -1; // Cast a ray on all meshes, pick the closest hit and save it for the respective mesh for (const ModelVolume* mv : mo->volumes) { @@ -338,9 +341,6 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous ++mesh_id; - trafo_matrices.push_back(instance_trafo * mv->get_matrix()); - hit_positions_and_facet_ids.push_back(std::vector>()); - if (m_c->raycaster()->raycasters()[mesh_id]->unproject_on_mesh( mp, trafo_matrices[mesh_id], @@ -366,18 +366,19 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } } } + mesh_id = closest_hit_mesh_id; bool dragging_while_painting = (action == SLAGizmoEventType::Dragging && m_button_down != Button::None); // The mouse button click detection is enabled when there is a valid hit // or when the user clicks the clipping plane. Missing the object entirely // shall not capture the mouse. - if (closest_hit_mesh_id != -1 || clipped_mesh_was_hit) { + if (mesh_id != -1 || clipped_mesh_was_hit) { if (m_button_down == Button::None) m_button_down = ((action == SLAGizmoEventType::LeftDown) ? Button::Left : Button::Right); } - if (closest_hit_mesh_id == -1) { + if (mesh_id == -1) { // In case we have no valid hit, we can return. The event will // be stopped in following two cases: // 1. clicking the clipping plane @@ -386,16 +387,6 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous || dragging_while_painting; } - // Find respective mesh id. - mesh_id = -1; - for (const ModelVolume* mv : mo->volumes) { - if (! mv->is_model_part()) - continue; - ++mesh_id; - if (mesh_id == closest_hit_mesh_id) - break; - } - const Transform3d& trafo_matrix = trafo_matrices[mesh_id]; // Calculate how far can a point be from the line (in mesh coords). From fac7e735acb219e5ef8fc891c7a202127e4f1e24 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 30 Sep 2020 22:28:49 +0200 Subject: [PATCH 06/14] Moved the raycasting query in painting gizmos to a separate function This way it can be called when rendering the spherical cursor and when processing the mouse clicks/drags --- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 93 +++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 6 ++ 2 files changed, 57 insertions(+), 42 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index ef4b31877..1c5edbb03 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -323,50 +323,13 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous // Now "click" into all the prepared points and spill paint around them. for (const Vec2d& mp : mouse_positions) { - bool clipped_mesh_was_hit = false; - Vec3f normal = Vec3f::Zero(); + bool clipped_mesh_was_hit = false; Vec3f hit = Vec3f::Zero(); size_t facet = 0; - Vec3f closest_hit = Vec3f::Zero(); - double closest_hit_squared_distance = std::numeric_limits::max(); - size_t closest_facet = 0; - int closest_hit_mesh_id = -1; - int mesh_id = -1; - // Cast a ray on all meshes, pick the closest hit and save it for the respective mesh - for (const ModelVolume* mv : mo->volumes) { - if (! mv->is_model_part()) - continue; - ++mesh_id; - - if (m_c->raycaster()->raycasters()[mesh_id]->unproject_on_mesh( - mp, - trafo_matrices[mesh_id], - camera, - hit, - normal, - m_clipping_plane.get(), - &facet)) - { - // In case this hit is clipped, skip it. - if (is_mesh_point_clipped(hit.cast())) { - clipped_mesh_was_hit = true; - continue; - } - - // Is this hit the closest to the camera so far? - double hit_squared_distance = (camera.get_position()-trafo_matrices[mesh_id]*hit.cast()).squaredNorm(); - if (hit_squared_distance < closest_hit_squared_distance) { - closest_hit_squared_distance = hit_squared_distance; - closest_facet = facet; - closest_hit_mesh_id = mesh_id; - closest_hit = hit; - } - } - } - mesh_id = closest_hit_mesh_id; + get_mesh_hit(mp, camera, trafo_matrices, mesh_id, hit, facet, clipped_mesh_was_hit); bool dragging_while_painting = (action == SLAGizmoEventType::Dragging && m_button_down != Button::None); @@ -397,13 +360,13 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous // Calculate direction from camera to the hit (in mesh coords): Vec3f camera_pos = (trafo_matrix.inverse() * camera.get_position()).cast(); - Vec3f dir = (closest_hit - camera_pos).normalized(); + Vec3f dir = (hit - camera_pos).normalized(); assert(mesh_id < int(m_triangle_selectors.size())); - m_triangle_selectors[mesh_id]->select_patch(closest_hit, closest_facet, camera_pos, + m_triangle_selectors[mesh_id]->select_patch(hit, facet, camera_pos, dir, limit, m_cursor_type, new_state); m_last_mouse_position = mouse_position; - m_last_mesh_idx_and_hit = {mesh_id, closest_hit}; + m_last_mesh_idx_and_hit = {mesh_id, hit}; } return true; @@ -448,6 +411,52 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } +void GLGizmoPainterBase::get_mesh_hit(const Vec2d& mouse_position, + const Camera& camera, + const std::vector& trafo_matrices, + int& mesh_id, Vec3f& hit, size_t& facet, + bool& clipped_mesh_was_hit) const +{ + Vec3f normal = Vec3f::Zero(); + size_t current_facet = 0; + Vec3f closest_hit = Vec3f::Zero(); + double closest_hit_squared_distance = std::numeric_limits::max(); + size_t closest_facet = 0; + int closest_hit_mesh_id = -1; + + // Cast a ray on all meshes, pick the closest hit and save it for the respective mesh + for (mesh_id = 0; mesh_id < int(trafo_matrices.size()); ++mesh_id) { + + if (m_c->raycaster()->raycasters()[mesh_id]->unproject_on_mesh( + mouse_position, + trafo_matrices[mesh_id], + camera, + hit, + normal, + m_clipping_plane.get(), + ¤t_facet)) + { + // In case this hit is clipped, skip it. + if (is_mesh_point_clipped(hit.cast())) { + clipped_mesh_was_hit = true; + continue; + } + + // Is this hit the closest to the camera so far? + double hit_squared_distance = (camera.get_position()-trafo_matrices[mesh_id]*hit.cast()).squaredNorm(); + if (hit_squared_distance < closest_hit_squared_distance) { + closest_hit_squared_distance = hit_squared_distance; + closest_facet = current_facet; + closest_hit_mesh_id = mesh_id; + closest_hit = hit; + } + } + } + + mesh_id = closest_hit_mesh_id; + facet = closest_facet; + hit = closest_hit; +} bool GLGizmoPainterBase::on_is_activable() const { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index 47bd26608..177bad53d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -21,6 +21,7 @@ namespace GUI { enum class SLAGizmoEventType : unsigned char; class ClippingPlane; +class Camera; enum class PainterGizmoType { FDM_SUPPORTS, @@ -88,6 +89,11 @@ protected: private: bool is_mesh_point_clipped(const Vec3d& point) const; + void get_mesh_hit(const Vec2d& mouse_position, + const Camera& camera, + const std::vector& trafo_matrices, + int& mesh_id, Vec3f& hit, size_t& facet, + bool& clipped_mesh_was_hit) const; float m_clipping_plane_distance = 0.f; std::unique_ptr m_clipping_plane; From 3ec5d9e2cfacb65fd49b707e29b28afe16abf2b2 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 1 Oct 2020 00:03:20 +0200 Subject: [PATCH 07/14] Cache raycast results so they don't have to be repeated on the same mouse pos Fixed incorrect handling of clipping plane with multiple volumes - only the first volume was correctly clipped by the painter. --- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 118 +++++++++---------- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 25 ++-- 2 files changed, 76 insertions(+), 67 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 1c5edbb03..c421e63de 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -182,33 +182,41 @@ void GLGizmoPainterBase::render_cursor_circle() const void GLGizmoPainterBase::render_cursor_sphere() const { - int mesh_id = m_last_mesh_idx_and_hit.first; - if (mesh_id == -1) + Vec2d mouse_position(m_parent.get_local_mouse_position()(0), m_parent.get_local_mouse_position()(1)); + + const ModelObject* mo = m_c->selection_info()->model_object(); + const Selection& selection = m_parent.get_selection(); + const ModelInstance* mi = mo->instances[selection.get_instance_idx()]; + const Camera& camera = wxGetApp().plater()->get_camera(); + + // Precalculate transformations of individual meshes. + std::vector trafo_matrices; + for (const ModelVolume* mv : mo->volumes) { + if (mv->is_model_part()) + trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix()); + } + update_raycast_cache(mouse_position, camera, trafo_matrices); + if (m_rr.mesh_id == -1) return; - const Vec3f hit_pos = m_last_mesh_idx_and_hit.second; - const Selection& selection = m_parent.get_selection(); - const ModelObject* mo = m_c->selection_info()->model_object(); - const ModelVolume* mv = mo->volumes[mesh_id]; - const ModelInstance* mi = mo->instances[selection.get_instance_idx()]; - const Transform3d instance_matrix = mi->get_transformation().get_matrix() * mv->get_matrix(); - const Transform3d instance_scaling_matrix_inverse = Geometry::Transformation(instance_matrix).get_matrix(true, true, false, true).inverse(); - const bool is_left_handed = Geometry::Transformation(instance_matrix).is_left_handed(); + const Transform3d& complete_matrix = trafo_matrices[m_rr.mesh_id]; + const Transform3d complete_scaling_matrix_inverse = Geometry::Transformation(complete_matrix).get_matrix(true, true, false, true).inverse(); + const bool is_left_handed = Geometry::Transformation(complete_matrix).is_left_handed(); glsafe(::glPushMatrix()); - glsafe(::glMultMatrixd(instance_matrix.data())); + glsafe(::glMultMatrixd(complete_matrix.data())); // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. - glsafe(::glTranslatef(hit_pos(0), hit_pos(1), hit_pos(2))); - glsafe(::glMultMatrixd(instance_scaling_matrix_inverse.data())); + glsafe(::glTranslatef(m_rr.hit(0), m_rr.hit(1), m_rr.hit(2))); + glsafe(::glMultMatrixd(complete_scaling_matrix_inverse.data())); glsafe(::glScaled(m_cursor_radius, m_cursor_radius, m_cursor_radius)); if (is_left_handed) glFrontFace(GL_CW); - float render_color[4] = { 0.f, 0.f, 0.f, 0.15f }; + float render_color[4] = { 0.f, 0.f, 0.f, 0.25f }; if (m_button_down == Button::Left) render_color[2] = 1.f; - else // right + else if (m_button_down == Button::Right) render_color[0] = 1.f; glsafe(::glColor4fv(render_color)); @@ -221,16 +229,12 @@ void GLGizmoPainterBase::render_cursor_sphere() const } -bool GLGizmoPainterBase::is_mesh_point_clipped(const Vec3d& point) const +bool GLGizmoPainterBase::is_mesh_point_clipped(const Vec3d& point, const Transform3d& trafo) const { if (m_c->object_clipper()->get_position() == 0.) return false; auto sel_info = m_c->selection_info(); - int active_inst = m_c->selection_info()->get_active_instance(); - const ModelInstance* mi = sel_info->model_object()->instances[active_inst]; - const Transform3d& trafo = mi->get_transformation().get_matrix(); - Vec3d transformed_point = trafo * point; transformed_point(2) += sel_info->get_sla_shift(); return m_c->object_clipper()->get_clipping_plane()->is_point_clipped(transformed_point); @@ -299,20 +303,20 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous // add several positions from between into the list, so there // are no gaps in the painted region. { - if (m_last_mouse_position == Vec2d::Zero()) - m_last_mouse_position = mouse_position; + if (m_last_mouse_click == Vec2d::Zero()) + m_last_mouse_click = mouse_position; // resolution describes minimal distance limit using circle radius // as a unit (e.g., 2 would mean the patches will be touching). double resolution = 0.7; double diameter_px = resolution * m_cursor_radius * camera.get_zoom(); - int patches_in_between = int(((mouse_position - m_last_mouse_position).norm() - diameter_px) / diameter_px); + int patches_in_between = int(((mouse_position - m_last_mouse_click).norm() - diameter_px) / diameter_px); if (patches_in_between > 0) { - Vec2d diff = (mouse_position - m_last_mouse_position)/(patches_in_between+1); + Vec2d diff = (mouse_position - m_last_mouse_click)/(patches_in_between+1); for (int i=1; i<=patches_in_between; ++i) - mouse_positions.emplace_back(m_last_mouse_position + i*diff); + mouse_positions.emplace_back(m_last_mouse_click + i*diff); } } - m_last_mouse_position = Vec2d::Zero(); // only actual hits should be saved + m_last_mouse_click = Vec2d::Zero(); // only actual hits should be saved // Precalculate transformations of individual meshes. std::vector trafo_matrices; @@ -323,34 +327,28 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous // Now "click" into all the prepared points and spill paint around them. for (const Vec2d& mp : mouse_positions) { - - bool clipped_mesh_was_hit = false; - Vec3f hit = Vec3f::Zero(); - size_t facet = 0; - int mesh_id = -1; - - get_mesh_hit(mp, camera, trafo_matrices, mesh_id, hit, facet, clipped_mesh_was_hit); + update_raycast_cache(mp, camera, trafo_matrices); bool dragging_while_painting = (action == SLAGizmoEventType::Dragging && m_button_down != Button::None); // The mouse button click detection is enabled when there is a valid hit // or when the user clicks the clipping plane. Missing the object entirely // shall not capture the mouse. - if (mesh_id != -1 || clipped_mesh_was_hit) { + if (m_rr.mesh_id != -1 || m_rr.clipped_mesh_was_hit) { if (m_button_down == Button::None) m_button_down = ((action == SLAGizmoEventType::LeftDown) ? Button::Left : Button::Right); } - if (mesh_id == -1) { + if (m_rr.mesh_id == -1) { // In case we have no valid hit, we can return. The event will // be stopped in following two cases: // 1. clicking the clipping plane // 2. dragging while painting (to prevent scene rotations and moving the object) - return clipped_mesh_was_hit + return m_rr.clipped_mesh_was_hit || dragging_while_painting; } - const Transform3d& trafo_matrix = trafo_matrices[mesh_id]; + const Transform3d& trafo_matrix = trafo_matrices[m_rr.mesh_id]; // Calculate how far can a point be from the line (in mesh coords). // FIXME: The scaling of the mesh can be non-uniform. @@ -360,13 +358,12 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous // Calculate direction from camera to the hit (in mesh coords): Vec3f camera_pos = (trafo_matrix.inverse() * camera.get_position()).cast(); - Vec3f dir = (hit - camera_pos).normalized(); + Vec3f dir = (m_rr.hit - camera_pos).normalized(); - assert(mesh_id < int(m_triangle_selectors.size())); - m_triangle_selectors[mesh_id]->select_patch(hit, facet, camera_pos, + assert(m_rr.mesh_id < int(m_triangle_selectors.size())); + m_triangle_selectors[m_rr.mesh_id]->select_patch(m_rr.hit, m_rr.facet, camera_pos, dir, limit, m_cursor_type, new_state); - m_last_mouse_position = mouse_position; - m_last_mesh_idx_and_hit = {mesh_id, hit}; + m_last_mouse_click = mouse_position; } return true; @@ -402,8 +399,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous update_model_object(); m_button_down = Button::None; - m_last_mouse_position = Vec2d::Zero(); - m_last_mesh_idx_and_hit = {-1, Vec3f::Zero()}; + m_last_mouse_click = Vec2d::Zero(); return true; } @@ -411,21 +407,27 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } -void GLGizmoPainterBase::get_mesh_hit(const Vec2d& mouse_position, - const Camera& camera, - const std::vector& trafo_matrices, - int& mesh_id, Vec3f& hit, size_t& facet, - bool& clipped_mesh_was_hit) const + +void GLGizmoPainterBase::update_raycast_cache(const Vec2d& mouse_position, + const Camera& camera, + const std::vector& trafo_matrices) const { + if (m_rr.mouse_position == mouse_position) { + // Same query as last time - the answer is already in the cache. + return; + } + + bool clipped_mesh_was_hit{false}; Vec3f normal = Vec3f::Zero(); - size_t current_facet = 0; + Vec3f hit = Vec3f::Zero(); + size_t facet = 0; Vec3f closest_hit = Vec3f::Zero(); double closest_hit_squared_distance = std::numeric_limits::max(); size_t closest_facet = 0; int closest_hit_mesh_id = -1; // Cast a ray on all meshes, pick the closest hit and save it for the respective mesh - for (mesh_id = 0; mesh_id < int(trafo_matrices.size()); ++mesh_id) { + for (int mesh_id = 0; mesh_id < int(trafo_matrices.size()); ++mesh_id) { if (m_c->raycaster()->raycasters()[mesh_id]->unproject_on_mesh( mouse_position, @@ -434,10 +436,10 @@ void GLGizmoPainterBase::get_mesh_hit(const Vec2d& mouse_position, hit, normal, m_clipping_plane.get(), - ¤t_facet)) + &facet)) { // In case this hit is clipped, skip it. - if (is_mesh_point_clipped(hit.cast())) { + if (is_mesh_point_clipped(hit.cast(), trafo_matrices[mesh_id])) { clipped_mesh_was_hit = true; continue; } @@ -446,16 +448,14 @@ void GLGizmoPainterBase::get_mesh_hit(const Vec2d& mouse_position, double hit_squared_distance = (camera.get_position()-trafo_matrices[mesh_id]*hit.cast()).squaredNorm(); if (hit_squared_distance < closest_hit_squared_distance) { closest_hit_squared_distance = hit_squared_distance; - closest_facet = current_facet; + closest_facet = facet; closest_hit_mesh_id = mesh_id; closest_hit = hit; } } } - mesh_id = closest_hit_mesh_id; - facet = closest_facet; - hit = closest_hit; + m_rr = {mouse_position, closest_hit_mesh_id, closest_hit, closest_facet, clipped_mesh_was_hit}; } bool GLGizmoPainterBase::on_is_activable() const @@ -564,13 +564,13 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui) m_iva_blockers.finalize_geometry(true); if (m_iva_enforcers.has_VBOs()) { - ::glColor4f(0.f, 0.f, 1.f, 0.3f); + ::glColor4f(0.f, 0.f, 1.f, 0.4f); m_iva_enforcers.render(); } if (m_iva_blockers.has_VBOs()) { - ::glColor4f(1.f, 0.f, 0.f, 0.3f); + ::glColor4f(1.f, 0.f, 0.f, 0.4f); m_iva_blockers.render(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index 177bad53d..02b4dd1c7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -88,12 +88,10 @@ protected: private: - bool is_mesh_point_clipped(const Vec3d& point) const; - void get_mesh_hit(const Vec2d& mouse_position, - const Camera& camera, - const std::vector& trafo_matrices, - int& mesh_id, Vec3f& hit, size_t& facet, - bool& clipped_mesh_was_hit) const; + bool is_mesh_point_clipped(const Vec3d& point, const Transform3d& trafo) const; + void update_raycast_cache(const Vec2d& mouse_position, + const Camera& camera, + const std::vector& trafo_matrices) const; float m_clipping_plane_distance = 0.f; std::unique_ptr m_clipping_plane; @@ -101,8 +99,7 @@ private: bool m_internal_stack_active = false; bool m_schedule_update = false; - Vec2d m_last_mouse_position = Vec2d::Zero(); - std::pair m_last_mesh_idx_and_hit = {-1, Vec3f::Zero()}; + Vec2d m_last_mouse_click = Vec2d::Zero(); enum class Button { None, @@ -113,6 +110,18 @@ private: Button m_button_down = Button::None; EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state) + // Following cache holds result of a raycast query. The queries are asked + // during rendering the sphere cursor and painting, this saves repeated + // raycasts when the mouse position is the same as before. + struct RaycastResult { + Vec2d mouse_position; + int mesh_id; + Vec3f hit; + size_t facet; + bool clipped_mesh_was_hit; + }; + mutable RaycastResult m_rr; + protected: void on_set_state() override; void on_start_dragging() override {} From 3f7d41df15e023271054720f31dd690afaeca671 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 1 Oct 2020 00:41:19 +0200 Subject: [PATCH 08/14] Imgui dialog layout adjustments after the new combo was added --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 37 ++++++++++++++++--- src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp | 38 +++++++++++++------- 2 files changed, 58 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 58346a414..04288c13f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -42,6 +42,7 @@ bool GLGizmoFdmSupports::on_init() m_desc["clipping_of_view"] = _L("Clipping of view") + ": "; m_desc["reset_direction"] = _L("Reset direction"); m_desc["cursor_size"] = _L("Cursor size") + ": "; + m_desc["cursor_type"] = _L("Cursor type") + ": "; m_desc["enforce_caption"] = _L("Left mouse button") + ": "; m_desc["enforce"] = _L("Enforce supports"); m_desc["block_caption"] = _L("Right mouse button") + " "; @@ -78,16 +79,26 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l if (! m_c->selection_info()->model_object()) return; - const float approx_height = m_imgui->scaled(18.0f); + const float approx_height = m_imgui->scaled(14.0f); y = std::min(y, bottom_limit - approx_height); m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); if (! m_setting_angle) { m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); + std::vector cursor_types; + cursor_types.push_back(_L("Circle").ToUTF8().data()); + cursor_types.push_back(_L("Sphere").ToUTF8().data()); + // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: - const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f); + const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, + m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + + m_imgui->scaled(1.5f); const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f); + const float cursor_type_combo_left = m_imgui->calc_text_size(m_desc.at("cursor_type")).x + m_imgui->scaled(1.f); + const float cursor_type_combo_width = std::max(m_imgui->calc_text_size(wxString::FromUTF8(cursor_types[0])).x, + m_imgui->calc_text_size(wxString::FromUTF8(cursor_types[1])).x) + + m_imgui->scaled(2.5f); const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f); const float minimal_slider_width = m_imgui->scaled(4.f); @@ -103,6 +114,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l float window_width = minimal_slider_width + std::max(cursor_slider_left, clipping_slider_left); window_width = std::max(window_width, total_text_max); window_width = std::max(window_width, button_width); + window_width = std::max(window_width, cursor_type_combo_left + cursor_type_combo_width); auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) { m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, caption); @@ -139,8 +151,8 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; m_imgui->text(m_desc.at("cursor_size")); - ImGui::SameLine(clipping_slider_left); - ImGui::PushItemWidth(window_width - clipping_slider_left); + ImGui::SameLine(cursor_slider_left); + ImGui::PushItemWidth(window_width - cursor_slider_left); ImGui::SliderFloat(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); @@ -150,6 +162,23 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l ImGui::EndTooltip(); } + + m_imgui->text(m_desc.at("cursor_type")); + ImGui::SameLine(window_width - cursor_type_combo_width - m_imgui->scaled(0.5f)); + ImGui::PushItemWidth(cursor_type_combo_width); + int selection = int(m_cursor_type); + m_imgui->combo("", cursor_types, selection); + m_cursor_type = TriangleSelector::CursorType(selection); + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(max_tooltip_width); + ImGui::TextUnformatted(_L("Sphere paints all facets inside, regardless of their orientation.\n\n" + "Circle ignores facets facing away from the camera.").ToUTF8().data()); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } + + ImGui::Separator(); if (m_c->object_clipper()->get_position() == 0.f) m_imgui->text(m_desc.at("clipping_of_view")); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index 1b1b1f10f..0cbfaeedc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -25,7 +25,7 @@ bool GLGizmoSeam::on_init() m_desc["clipping_of_view"] = _L("Clipping of view") + ": "; m_desc["reset_direction"] = _L("Reset direction"); m_desc["cursor_size"] = _L("Cursor size") + ": "; - m_desc["cursor_type"] = _L("Cursor size") + ": "; + m_desc["cursor_type"] = _L("Cursor type") + ": "; m_desc["enforce_caption"] = _L("Left mouse button") + ": "; m_desc["enforce"] = _L("Enforce seam"); m_desc["block_caption"] = _L("Right mouse button") + " "; @@ -68,16 +68,26 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) if (! m_c->selection_info()->model_object()) return; - const float approx_height = m_imgui->scaled(18.0f); + const float approx_height = m_imgui->scaled(14.0f); y = std::min(y, bottom_limit - approx_height); m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); + std::vector cursor_types; + cursor_types.push_back(_L("Circle").ToUTF8().data()); + cursor_types.push_back(_L("Sphere").ToUTF8().data()); + m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: - const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f); - const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f); + const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, + m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + + m_imgui->scaled(1.5f); + const float cursor_size_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f); + const float cursor_type_combo_left = m_imgui->calc_text_size(m_desc.at("cursor_type")).x + m_imgui->scaled(1.f); + const float cursor_type_combo_width = std::max(m_imgui->calc_text_size(wxString::FromUTF8(cursor_types[0])).x, + m_imgui->calc_text_size(wxString::FromUTF8(cursor_types[1])).x) + + m_imgui->scaled(2.5f); const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f); const float minimal_slider_width = m_imgui->scaled(4.f); @@ -90,9 +100,10 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) caption_max += m_imgui->scaled(1.f); total_text_max += m_imgui->scaled(1.f); - float window_width = minimal_slider_width + std::max(cursor_slider_left, clipping_slider_left); + float window_width = minimal_slider_width + std::max(cursor_size_slider_left, clipping_slider_left); window_width = std::max(window_width, total_text_max); window_width = std::max(window_width, button_width); + window_width = std::max(window_width, cursor_type_combo_left + cursor_type_combo_width); auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) { static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f); @@ -124,8 +135,8 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; m_imgui->text(m_desc.at("cursor_size")); - ImGui::SameLine(clipping_slider_left); - ImGui::PushItemWidth(window_width - clipping_slider_left); + ImGui::SameLine(cursor_size_slider_left); + ImGui::PushItemWidth(window_width - cursor_size_slider_left); ImGui::SliderFloat(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); @@ -137,18 +148,19 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) m_imgui->text(m_desc.at("cursor_type")); - ImGui::SameLine(/*clipping_slider_left*/); - //ImGui::PushItemWidth(window_width - clipping_slider_left); + ImGui::SameLine(window_width - cursor_type_combo_width - m_imgui->scaled(0.5f)); + ImGui::PushItemWidth(cursor_type_combo_width); int selection = int(m_cursor_type); - m_imgui->combo(" ", {"Circle", "Sphere"}, selection); + m_imgui->combo("", cursor_types, selection); m_cursor_type = TriangleSelector::CursorType(selection); - /*if (ImGui::IsItemHovered()) { + if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(max_tooltip_width); - ImGui::TextUnformatted(_L("Alt + Mouse wheel").ToUTF8().data()); + ImGui::TextUnformatted(_L("Sphere paints all facets inside, regardless of their orientation.\n\n" + "Circle ignores facets facing away from the camera.").ToUTF8().data()); ImGui::PopTextWrapPos(); ImGui::EndTooltip(); - }*/ + } From fad1f5e84f2de4970120639b369bd6fd0b99f888 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 1 Oct 2020 08:34:16 +0200 Subject: [PATCH 09/14] Fixed typo --- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index 02b4dd1c7..8a9e87124 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -21,7 +21,7 @@ namespace GUI { enum class SLAGizmoEventType : unsigned char; class ClippingPlane; -class Camera; +struct Camera; enum class PainterGizmoType { FDM_SUPPORTS, From 43f122b5ee506e9e9093d12b9273ff7a02d9ee7d Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 1 Oct 2020 09:25:11 +0200 Subject: [PATCH 10/14] Filament selection in configuration wizard: compatible printers in html window, bug fixes. --- src/slic3r/GUI/ConfigWizard.cpp | 362 ++++++++++++++++++------ src/slic3r/GUI/ConfigWizard_private.hpp | 50 ++-- 2 files changed, 293 insertions(+), 119 deletions(-) diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index c98b736b7..9c4338d86 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -566,20 +566,20 @@ PageMaterials::PageMaterials(ConfigWizard *parent, Materials *materials, wxStrin , list_type(new StringList(this)) , list_vendor(new StringList(this)) , list_profile(new PresetList(this)) - , compatible_printers(new wxStaticText(this, wxID_ANY, _(L("")))) { append_spacer(VERTICAL_SPACING); const int em = parent->em_unit(); const int list_h = 30*em; - list_printer->SetWindowStyle(wxLB_EXTENDED); list_printer->SetMinSize(wxSize(23*em, list_h)); list_type->SetMinSize(wxSize(8*em, list_h)); list_vendor->SetMinSize(wxSize(13*em, list_h)); list_profile->SetMinSize(wxSize(23*em, list_h)); + + grid = new wxFlexGridSizer(4, em/2, em); grid->AddGrowableCol(3, 1); grid->AddGrowableRow(1, 1); @@ -601,17 +601,19 @@ PageMaterials::PageMaterials(ConfigWizard *parent, Materials *materials, wxStrin btn_sizer->Add(sel_none); + grid->Add(new wxBoxSizer(wxHORIZONTAL)); grid->Add(new wxBoxSizer(wxHORIZONTAL)); grid->Add(new wxBoxSizer(wxHORIZONTAL)); grid->Add(btn_sizer, 0, wxALIGN_RIGHT); - - auto* notes_sizer = new wxBoxSizer(wxHORIZONTAL); - notes_sizer->Add(compatible_printers); - grid->Add(notes_sizer); - append(grid, 1, wxEXPAND); + append_spacer(VERTICAL_SPACING); + + html_window = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, + wxSize(60 * em, 20 * em), wxHW_SCROLLBAR_AUTO); + append(html_window, 0, wxEXPAND); + list_printer->Bind(wxEVT_LISTBOX, [this](wxCommandEvent& evt) { update_lists(evt.GetInt(), list_type->GetSelection(), list_vendor->GetSelection()); }); @@ -627,28 +629,25 @@ PageMaterials::PageMaterials(ConfigWizard *parent, Materials *materials, wxStrin sel_all->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { select_all(true); }); sel_none->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { select_all(false); }); - + /* Bind(wxEVT_PAINT, [this](wxPaintEvent& evt) {on_paint();}); list_profile->Bind(wxEVT_MOTION, [this](wxMouseEvent& evt) { on_mouse_move_on_profiles(evt); }); list_profile->Bind(wxEVT_ENTER_WINDOW, [this](wxMouseEvent& evt) { on_mouse_enter_profiles(evt); }); list_profile->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& evt) { on_mouse_leave_profiles(evt); }); - + */ reload_presets(); + set_compatible_printers_html_window(std::vector(), false); } void PageMaterials::on_paint() { - if (first_paint) { - first_paint = false; - prepare_compatible_printers_label(); - } } void PageMaterials::on_mouse_move_on_profiles(wxMouseEvent& evt) { const wxClientDC dc(list_profile); const wxPoint pos = evt.GetLogicalPosition(dc); int item = list_profile->HitTest(pos); - BOOST_LOG_TRIVIAL(error) << "hit test: " << item; + //BOOST_LOG_TRIVIAL(debug) << "hit test: " << item; on_material_hovered(item); } void PageMaterials::on_mouse_enter_profiles(wxMouseEvent& evt) @@ -666,10 +665,11 @@ void PageMaterials::reload_presets() for (const Preset* printer : materials->printers) { list_printer->append(printer->name, &printer->name); } - + sort_list_data(list_printer, true, false); if (list_printer->GetCount() > 0) { list_printer->SetSelection(0); - sel_printer_prev = wxNOT_FOUND; + sel_printer_count_prev = wxNOT_FOUND; + sel_printer_item_prev = wxNOT_FOUND; sel_type_prev = wxNOT_FOUND; sel_vendor_prev = wxNOT_FOUND; update_lists(0, 0, 0); @@ -678,34 +678,105 @@ void PageMaterials::reload_presets() presets_loaded = true; } -void PageMaterials::prepare_compatible_printers_label() +void PageMaterials::set_compatible_printers_html_window(const std::vector& printer_names, bool all_printers) { - assert(grid->GetColWidths().size() == 4); - compatible_printers_width = grid->GetColWidths()[3]; - empty_printers_label = "Compatible printers:"; - for (const Preset* printer : materials->printers) { - empty_printers_label += "\n"; + //Slic3r::GUI::wxGetApp().dark_mode() + const auto bgr_clr = +#if defined(__APPLE__) + wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); +#else + wxSystemSettings::GetColour(wxSYS_COLOUR_MENU); +#endif + const auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()); + const auto text_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); + const auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue()); + wxString first_line = L"Profiles marked with * are not compatible with all installed printers."; + wxString text; + if (all_printers) { + text = wxString::Format( + "" + "" + "" + "" + "" + "%s

All installed printers are compatible with selected profile." + "
" + "
" + "" + "" + , bgr_clr_str + , text_clr_str + , first_line + ); + } else { + wxString second_line = L"Compatible printers:"; + text = wxString::Format( + "" + "" + "" + "" + "" + "%s

%s" + "" + "" + , bgr_clr_str + , text_clr_str + , first_line + , second_line); + for (int i = 0; i < printer_names.size(); ++i) + { + text += wxString::Format("", boost::nowide::widen(printer_names[i])); + if (i % 3 == 2) { + text += wxString::Format( + "" + ""); + } + } + text += wxString::Format( + "" + "
%s
" + "
" + "
" + "" + "" + ); } - clear_compatible_printers_label(); + + wxFont font = get_default_font_for_dpi(get_dpi_for_window(this)); + const int fs = font.GetPointSize(); + int size[] = { fs,fs,fs,fs,fs,fs,fs }; + html_window->SetFonts(font.GetFaceName(), font.GetFaceName(), size); + html_window->SetPage(text); } void PageMaterials::clear_compatible_printers_label() { - compatible_printers->SetLabel(boost::nowide::widen(empty_printers_label)); - compatible_printers->Wrap(compatible_printers_width); - Layout(); + set_compatible_printers_html_window(std::vector(), false); } void PageMaterials::on_material_hovered(int sel_material) { - if ( sel_material == last_hovered_item) + +} + +void PageMaterials::on_material_highlighted(int sel_material) +{ + if (sel_material == last_hovered_item) return; if (sel_material == -1) { clear_compatible_printers_label(); return; } last_hovered_item = sel_material; - std::string compatible_printers_label = "compatible printers:\n"; + std::string compatible_printers_label = "Compatible printers:\n"; + std::vector tabs; + tabs.push_back(std::string()); + tabs.push_back(std::string()); + tabs.push_back(std::string()); //selected material string std::string material_name = list_profile->get_data(sel_material); // get material preset @@ -716,70 +787,16 @@ void PageMaterials::on_material_hovered(int sel_material) return; } //find matching printers - bool first = true; + std::vector names; for (const Preset* printer : materials->printers) { - bool compatible = false; for (const Preset* material : matching_materials) { if (is_compatible_with_printer(PresetWithVendorProfile(*material, material->vendor), PresetWithVendorProfile(*printer, printer->vendor))) { - if (first) - first = false; - else - compatible_printers_label += "\n";//", "; - compatible_printers_label += printer->name; - compatible = true; + names.push_back(printer->name); break; } } } - this->compatible_printers->SetLabel(boost::nowide::widen(compatible_printers_label)); - this->compatible_printers->Wrap(compatible_printers_width); -} - -void PageMaterials::on_material_highlighted(int sel_material) -{ - wxWindowUpdateLocker freeze_guard(this); - (void)freeze_guard; - - //std::string compatible_printers_label = "compatible printers:\n"; - //std::string empty_suplement = std::string(); - //unselect all printers - list_printer->SetSelection(wxNOT_FOUND); - //selected material string - std::string material_name = list_profile->get_data(sel_material); - // get material preset - const std::vector matching_materials = materials->get_presets_by_alias(material_name); - if (matching_materials.empty()) - return; - //find matching printers - //bool first = true; - for (const Preset* printer : materials->printers) { - bool compatible = false; - for (const Preset* material : matching_materials) { - if (is_compatible_with_printer(PresetWithVendorProfile(*material, material->vendor), PresetWithVendorProfile(*printer, printer->vendor))) { - //select printer - int index = list_printer->find(printer->name); - list_printer->SetSelection(index); - /*if (first) - first = false; - else - compatible_printers_label += "\n";//", "; - compatible_printers_label += printer->name; - compatible = true; - break;*/ - } - } - //if(!compatible) - // empty_suplement += std::string(printer->name.length() + 2, ' '); - } - // fill rest of label with blanks so it maintains legth - //compatible_printers_label += empty_suplement; - - update_lists(0,0,0); - list_profile->SetSelection(list_profile->find(material_name)); - - //this->compatible_printers->SetLabel(boost::nowide::widen(compatible_printers_label)); - //this->compatible_printers->Wrap(compatible_printers_width); - //Refresh(); + set_compatible_printers_html_window(names, names.size() == materials->printers.size()); } void PageMaterials::update_lists(int sel_printer, int sel_type, int sel_vendor) @@ -790,7 +807,7 @@ void PageMaterials::update_lists(int sel_printer, int sel_type, int sel_vendor) wxArrayInt sel_printers; int sel_printers_count = list_printer->GetSelections(sel_printers); - if (sel_printers_count != sel_printer_prev) { + if (sel_printers_count != sel_printer_count_prev || (sel_printers_count == 1 && sel_printer_item_prev != sel_printer && sel_printer != -1)) { // Refresh type list list_type->Clear(); list_type->append(_(L("(All)")), &EMPTY); @@ -827,6 +844,7 @@ void PageMaterials::update_lists(int sel_printer, int sel_type, int sel_vendor) //clear selection except "ALL" list_printer->SetSelection(wxNOT_FOUND); list_printer->SetSelection(0); + sel_printers_count = list_printer->GetSelections(sel_printers); materials->filter_presets(nullptr, EMPTY, EMPTY, [this](const Preset* p) { const std::string& type = this->materials->get_type(p); @@ -835,10 +853,11 @@ void PageMaterials::update_lists(int sel_printer, int sel_type, int sel_vendor) } }); } - + sort_list_data(list_type, true, true); } - sel_printer_prev = sel_printers_count; + sel_printer_count_prev = sel_printers_count; + sel_printer_item_prev = sel_printer; sel_type = 0; sel_type_prev = wxNOT_FOUND; list_type->SetSelection(sel_type); @@ -872,6 +891,7 @@ void PageMaterials::update_lists(int sel_printer, int sel_type, int sel_vendor) } }); } + sort_list_data(list_vendor, true, false); } sel_type_prev = sel_type; @@ -905,7 +925,6 @@ void PageMaterials::update_lists(int sel_printer, int sel_type, int sel_vendor) //size_t printer_counter = materials->get_printer_counter(p); int cur_i = list_profile->find(p->alias); if (cur_i == wxNOT_FOUND) - //cur_i = list_profile->append(p->alias + " " + std::to_string(printer_counter)/*+ (omnipresent ? "" : " ONLY SOME PRINTERS")*/, &p->alias); cur_i = list_profile->append(p->alias + (materials->get_omnipresent(p) ? "" : " *"), &p->alias); else was_checked = list_profile->IsChecked(cur_i); @@ -925,12 +944,103 @@ void PageMaterials::update_lists(int sel_printer, int sel_type, int sel_vendor) wizard_p()->appconfig_new.set(section, p->name, "1"); }); } + sort_list_data(list_profile); } sel_vendor_prev = sel_vendor; } } +void PageMaterials::sort_list_data(StringList* list, bool add_All_item, bool material_type_ordering) +{ +// get data from list +// sort data +// first should be +// then prusa profiles +// then the rest +// in alphabetical order + + std::vector> prusa_profiles; + std::vector> other_profiles; + for (int i = 0 ; i < list->size(); ++i) { + const std::string& data = list->get_data(i); + if (data == EMPTY) // do not sort item + continue; + if (!material_type_ordering && data.find("Prusa") != std::string::npos) + prusa_profiles.push_back(data); + else + other_profiles.push_back(data); + } + if(material_type_ordering) { + + const ConfigOptionDef* def = print_config_def.get("filament_type"); + std::vectorenum_values = def->enum_values; + int end_of_sorted = 0; + for (size_t vals = 0; vals < enum_values.size(); vals++) { + for (size_t profs = end_of_sorted; profs < other_profiles.size(); profs++) + { + // find instead compare because PET vs PETG + if (other_profiles[profs].get().find(enum_values[vals]) != std::string::npos) { + //swap + if(profs != end_of_sorted) { + std::reference_wrapper aux = other_profiles[end_of_sorted]; + other_profiles[end_of_sorted] = other_profiles[profs]; + other_profiles[profs] = aux; + } + end_of_sorted++; + break; + } + } + } + } else { + std::sort(prusa_profiles.begin(), prusa_profiles.end(), [](std::reference_wrapper a, std::reference_wrapper b) { + return a.get() < b.get(); + }); + std::sort(other_profiles.begin(), other_profiles.end(), [](std::reference_wrapper a, std::reference_wrapper b) { + return a.get() < b.get(); + }); + } + + list->Clear(); + if (add_All_item) + list->append(_(L("(All)")), &EMPTY); + for (const auto& item : prusa_profiles) + list->append(item, &const_cast(item.get())); + for (const auto& item : other_profiles) + list->append(item, &const_cast(item.get())); +} + +void PageMaterials::sort_list_data(PresetList* list) +{ + // sort data + // then prusa profiles + // then the rest + // in alphabetical order + std::vector> prusa_profiles; + std::vector> other_profiles; + for (int i = 0; i < list->size(); ++i) { + const std::string& data = list->get_data(i); + if (data == EMPTY) // do not sort item + continue; + if (data.find("Prusa") != std::string::npos) + prusa_profiles.push_back(data); + else + other_profiles.push_back(data); + } + std::sort(prusa_profiles.begin(), prusa_profiles.end(), [](std::reference_wrapper a, std::reference_wrapper b) { + return a.get() < b.get(); + }); + std::sort(other_profiles.begin(), other_profiles.end(), [](std::reference_wrapper a, std::reference_wrapper b) { + return a.get() < b.get(); + }); + list->Clear(); + for (const auto& item : prusa_profiles) + list->append(item, &const_cast(item.get())); + for (const auto& item : other_profiles) + list->append(item, &const_cast(item.get())); + +} + void PageMaterials::select_material(int i) { const bool checked = list_profile->IsChecked(i); @@ -959,7 +1069,8 @@ void PageMaterials::clear() list_type->Clear(); list_vendor->Clear(); list_profile->Clear(); - sel_printer_prev = wxNOT_FOUND; + sel_printer_count_prev = wxNOT_FOUND; + sel_printer_item_prev = wxNOT_FOUND; sel_type_prev = wxNOT_FOUND; sel_vendor_prev = wxNOT_FOUND; presets_loaded = false; @@ -1546,7 +1657,7 @@ const std::string Materials::UNKNOWN = "(Unknown)"; void Materials::push(const Preset *preset) { - presets.emplace_back(preset, 0); + presets.emplace_back(preset); types.insert(technology & T_FFF ? Materials::get_filament_type(preset) : Materials::get_material_type(preset)); @@ -1562,6 +1673,7 @@ void Materials::clear() presets.clear(); types.clear(); printers.clear(); + compatibility_counter.clear(); } const std::string& Materials::appconfig_section() const @@ -1855,13 +1967,45 @@ void ConfigWizard::priv::update_materials(Technology technology) if (!filament.alias.empty()) aliases_fff[filament.alias].insert(filament.name); } - filaments.add_printer_counter(&filament); filaments.add_printer(&printer); } } } } + // count compatible printers + for (const auto& preset : filaments.presets) { + + const auto filter = [preset](const std::pair element) { + return preset->alias == element.first; + }; + if (std::find_if(filaments.compatibility_counter.begin(), filaments.compatibility_counter.end(), filter) != filaments.compatibility_counter.end()) { + continue; + } + std::vector idx_with_same_alias; + for (size_t i = 0; i < filaments.presets.size(); ++i) { + if (preset->alias == filaments.presets[i]->alias) + idx_with_same_alias.push_back(i); + } + size_t counter = 0; + for (const auto& printer : filaments.printers) { + if (!(*printer).is_visible || (*printer).printer_technology() != ptFFF) + continue; + bool compatible = false; + // Test otrher materials with same alias + for (size_t i = 0; i < idx_with_same_alias.size() && !compatible; ++i) { + const Preset& prst = *(filaments.presets[idx_with_same_alias[i]]); + const Preset& prntr = *printer; + if (is_compatible_with_printer(PresetWithVendorProfile(prst, prst.vendor), PresetWithVendorProfile(prntr, prntr.vendor))) { + compatible = true; + break; + } + } + if (compatible) + counter++; + } + filaments.compatibility_counter.emplace_back(preset->alias, counter); + } } if (any_sla_selected && (technology & T_SLA)) { @@ -1887,12 +2031,44 @@ void ConfigWizard::priv::update_materials(Technology technology) if (!material.alias.empty()) aliases_sla[material.alias].insert(material.name); } - sla_materials.add_printer_counter(&material); sla_materials.add_printer(&printer); } } } } + // count compatible printers + for (const auto& preset : sla_materials.presets) { + + const auto filter = [preset](const std::pair element) { + return preset->alias == element.first; + }; + if (std::find_if(sla_materials.compatibility_counter.begin(), sla_materials.compatibility_counter.end(), filter) != sla_materials.compatibility_counter.end()) { + continue; + } + std::vector idx_with_same_alias; + for (size_t i = 0; i < sla_materials.presets.size(); ++i) { + if(preset->alias == sla_materials.presets[i]->alias) + idx_with_same_alias.push_back(i); + } + size_t counter = 0; + for (const auto& printer : sla_materials.printers) { + if (!(*printer).is_visible || (*printer).printer_technology() != ptSLA) + continue; + bool compatible = false; + // Test otrher materials with same alias + for (size_t i = 0; i < idx_with_same_alias.size() && !compatible; ++i) { + const Preset& prst = *(sla_materials.presets[idx_with_same_alias[i]]); + const Preset& prntr = *printer; + if (is_compatible_with_printer(PresetWithVendorProfile(prst, prst.vendor), PresetWithVendorProfile(prntr, prntr.vendor))) { + compatible = true; + break; + } + } + if (compatible) + counter++; + } + sla_materials.compatibility_counter.emplace_back(preset->alias, counter); + } } } diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp index 260eeb22c..850f8fd46 100644 --- a/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/src/slic3r/GUI/ConfigWizard_private.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "libslic3r/PrintConfig.hpp" #include "libslic3r/PresetBundle.hpp" @@ -86,9 +87,9 @@ struct Materials { Technology technology; // use vector for the presets to purpose of save of presets sorting in the bundle - // bool is true if material is present in all printers (omnipresent) - // size_t is counter of printers compatible with material - std::vector> presets; + std::vector presets; + // String is alias of material, size_t number of compatible counters + std::vector> compatibility_counter; std::set types; std::set printers; @@ -100,7 +101,7 @@ struct Materials bool containts(const Preset *preset) const { //return std::find(presets.begin(), presets.end(), preset) != presets.end(); return std::find_if(presets.begin(), presets.end(), - [preset](const std::pair& element) { return element.first == preset; }) != presets.end(); + [preset](const Preset* element) { return element == preset; }) != presets.end(); } @@ -111,42 +112,35 @@ struct Materials const std::vector get_presets_by_alias(const std::string name) { std::vector ret_vec; for (auto it = presets.begin(); it != presets.end(); ++it) { - if ((*it).first->alias == name) - ret_vec.push_back((*it).first); + if ((*it)->alias == name) + ret_vec.push_back((*it)); } return ret_vec; } - void add_printer_counter(const Preset* preset) { - for (auto it = presets.begin(); it != presets.end(); ++it) { - if ((*it).first->alias == preset->alias) - (*it).second += 1; - } - } + size_t get_printer_counter(const Preset* preset) { - size_t highest = 0; - for (auto it : presets) { - if (it.first->alias == preset->alias && it.second > highest) - highest = it.second; - } - return highest; + for (auto it : compatibility_counter) { + if (it.first == preset->alias) + return it.second; + } + return 0; } const std::string& appconfig_section() const; const std::string& get_type(const Preset *preset) const; const std::string& get_vendor(const Preset *preset) const; - template void filter_presets(const Preset* printer, const std::string& type, const std::string& vendor, F cb) { for (auto preset : presets) { - const Preset& prst = *(preset.first); + const Preset& prst = *(preset); const Preset& prntr = *printer; if ((printer == nullptr || is_compatible_with_printer(PresetWithVendorProfile(prst, prst.vendor), PresetWithVendorProfile(prntr, prntr.vendor))) && - (type.empty() || get_type(preset.first) == type) && - (vendor.empty() || get_vendor(preset.first) == vendor)) { + (type.empty() || get_type(preset) == type) && + (vendor.empty() || get_vendor(preset) == vendor)) { - cb(preset.first); + cb(preset); } } } @@ -325,11 +319,12 @@ struct PageMaterials: ConfigWizardPage Materials *materials; StringList *list_printer, *list_type, *list_vendor; PresetList *list_profile; - int sel_printer_prev, sel_type_prev, sel_vendor_prev; + int sel_printer_count_prev, sel_printer_item_prev, sel_type_prev, sel_vendor_prev; bool presets_loaded; wxFlexGridSizer *grid; - wxStaticText *compatible_printers; + wxHtmlWindow* html_window; + int compatible_printers_width = { 100 }; std::string empty_printers_label; bool first_paint = { false }; @@ -345,9 +340,12 @@ struct PageMaterials: ConfigWizardPage void select_material(int i); void select_all(bool select); void clear(); - void prepare_compatible_printers_label(); + void set_compatible_printers_html_window(const std::vector& printer_names, bool all_printers = false); void clear_compatible_printers_label(); + void sort_list_data(StringList* list, bool add_All_item, bool material_type_ordering); + void sort_list_data(PresetList* list); + void on_paint(); void on_mouse_move_on_profiles(wxMouseEvent& evt); void on_mouse_enter_profiles(wxMouseEvent& evt); From a47178557fcb6fd562ab6c6e96b008823e0945d8 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Mon, 21 Sep 2020 09:14:47 +0200 Subject: [PATCH 11/14] notification orange color for hypertext --- src/slic3r/GUI/NotificationManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 47962f4b2..d5ab9ee1a 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -362,7 +362,7 @@ void NotificationManager::PopNotification::render_hypertext(ImGuiWrapper& imgui, ImGui::PopStyleColor(); //hover color - ImVec4 orange_color = ImGui::GetStyleColorVec4(ImGuiCol_Button); + ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f);//ImGui::GetStyleColorVec4(ImGuiCol_Button); if (ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly)) orange_color.y += 0.2f; From 661534042b683bdb8d2624eaa7a5a140da271965 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Mon, 21 Sep 2020 13:47:18 +0200 Subject: [PATCH 12/14] notifications: changed some plater warnings into errors, fixed not showing plater warnings in preview. --- src/slic3r/GUI/GLCanvas3D.cpp | 6 +++--- src/slic3r/GUI/NotificationManager.cpp | 9 +++++---- src/slic3r/GUI/NotificationManager.hpp | 5 +++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a3b4be9a7..c138b937c 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -628,8 +628,8 @@ void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool bool error = false; switch (warning) { case ObjectOutside: text = L("An object outside the print area was detected."); break; - case ToolpathOutside: text = L("A toolpath outside the print area was detected."); break; - case SlaSupportsOutside: text = L("SLA supports outside the print area were detected."); break; + case ToolpathOutside: text = L("A toolpath outside the print area was detected."); error = true; break; + case SlaSupportsOutside: text = L("SLA supports outside the print area were detected."); error = true; break; case SomethingNotShown: text = L("Some objects are not visible."); break; case ObjectClashed: text = L( "An object outside the print area was detected.\n" @@ -644,7 +644,7 @@ void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool wxGetApp().plater()->get_notification_manager()->push_plater_warning_notification(text, *(wxGetApp().plater()->get_current_canvas3D())); } else { if (error) - wxGetApp().plater()->get_notification_manager()->close_plater_error_notification(); + wxGetApp().plater()->get_notification_manager()->close_plater_error_notification(text); else wxGetApp().plater()->get_notification_manager()->close_plater_warning_notification(text); } diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index d5ab9ee1a..b9e7c7a6f 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -56,8 +56,7 @@ NotificationManager::PopNotification::~PopNotification() } NotificationManager::PopNotification::RenderResult NotificationManager::PopNotification::render(GLCanvas3D& canvas, const float& initial_y) { - if (!m_initialized) - { + if (!m_initialized) { init(); } if (m_finished) @@ -682,11 +681,13 @@ void NotificationManager::push_plater_error_notification(const std::string& text void NotificationManager::push_plater_warning_notification(const std::string& text, GLCanvas3D& canvas) { push_notification_data({ NotificationType::PlaterWarning, NotificationLevel::WarningNotification, 0, _u8L("WARNING:") + "\n" + text }, canvas, 0); + // dissaper if in preview + set_in_preview(m_in_preview); } -void NotificationManager::close_plater_error_notification() +void NotificationManager::close_plater_error_notification(const std::string& text) { for (PopNotification* notification : m_pop_notifications) { - if (notification->get_type() == NotificationType::PlaterError) { + if (notification->get_type() == NotificationType::PlaterError && notification->compare_text(_u8L("ERROR:") + "\n" + text)) { notification->close(); } } diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index a11d08394..c2cbc242c 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -220,7 +220,8 @@ public: void compare_warning_oids(const std::vector& living_oids); void push_plater_error_notification(const std::string& text, GLCanvas3D& canvas); void push_plater_warning_notification(const std::string& text, GLCanvas3D& canvas); - void close_plater_error_notification(); + // Closes error or warning of same text + void close_plater_error_notification(const std::string& text); void close_plater_warning_notification(const std::string& text); // creates special notification slicing complete // if large = true prints printing time and export button @@ -250,7 +251,7 @@ private: bool m_hovered { false }; //timestamps used for slining finished - notification could be gone so it needs to be stored here std::unordered_set m_used_timestamps; - bool m_in_preview; + bool m_in_preview { false }; //prepared (basic) notifications const std::vector basic_notifications = { From 8ded9dc0fdb80305955cd52a81b0e4c2eaaa9af8 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 1 Oct 2020 09:33:05 +0200 Subject: [PATCH 13/14] Improved performance of progress dialog shown while generating toolpaths for render --- src/slic3r/GUI/GCodeViewer.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 8ab17717c..a6914f768 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -863,6 +863,8 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) if (m_moves_count == 0) return; + unsigned int progress_count = 0; + static const unsigned int progress_threshold = 1000; wxProgressDialog progress_dialog(_L("Generating toolpaths"), "...", 100, wxGetApp().plater(), wxPD_AUTO_HIDE | wxPD_APP_MODAL); @@ -1245,10 +1247,13 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) if (i == 0) continue; - progress_dialog.Update(int(100.0f * float(i) / (2.0f * float(m_moves_count))), - _L("Generating vertex buffer") + " (" + wxNumberFormatter::ToString((long)i, wxNumberFormatter::Style_None) + "/" + - wxNumberFormatter::ToString((long)m_moves_count, wxNumberFormatter::Style_None) + ")"); - progress_dialog.Fit(); + ++progress_count; + if (progress_count % progress_threshold == 0) { + progress_dialog.Update(int(100.0f * float(i) / (2.0f * float(m_moves_count))), + _L("Generating vertex buffer") + ": " + wxNumberFormatter::ToString(100.0 * double(i) / double(m_moves_count), 0, wxNumberFormatter::Style_None) + "%"); + progress_dialog.Fit(); + progress_count = 0; + } const GCodeProcessor::MoveVertex& prev = gcode_result.moves[i - 1]; const GCodeProcessor::MoveVertex& curr = gcode_result.moves[i]; @@ -1316,10 +1321,13 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) if (i == 0) continue; - progress_dialog.Update(int(100.0f * float(m_moves_count + i) / (2.0f * float(m_moves_count))), - _L("Generating index buffers") + " (" + wxNumberFormatter::ToString((long)i, wxNumberFormatter::Style_None) + "/" + - wxNumberFormatter::ToString((long)m_moves_count, wxNumberFormatter::Style_None) + ")"); - progress_dialog.Fit(); + ++progress_count; + if (progress_count % progress_threshold == 0) { + progress_dialog.Update(int(100.0f * float(m_moves_count + i) / (2.0f * float(m_moves_count))), + _L("Generating index buffers") + ": " + wxNumberFormatter::ToString(100.0 * double(i) / double(m_moves_count), 0, wxNumberFormatter::Style_None) + "%"); + progress_dialog.Fit(); + progress_count = 0; + } const GCodeProcessor::MoveVertex& prev = gcode_result.moves[i - 1]; const GCodeProcessor::MoveVertex& curr = gcode_result.moves[i]; From 6a46708608a0114cfb64953f773402fe54d8de82 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 1 Oct 2020 09:45:36 +0200 Subject: [PATCH 14/14] fix in ConfigWizard.cpp --- src/slic3r/GUI/ConfigWizard.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 9c4338d86..cfc81f5a7 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -746,7 +746,7 @@ void PageMaterials::set_compatible_printers_html_window(const std::vectorSetFonts(font.GetFaceName(), font.GetFaceName(), size);