From 221770cc94a532d4dd337e0d919d164369226743 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Fri, 6 Jan 2023 12:00:58 +0100 Subject: [PATCH 01/17] Remove convexHull calculation for circular beds when arranging Extremely slow --- src/libslic3r/Arrange.cpp | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index a6aecd205c..e200b7edba 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -425,24 +425,11 @@ template<> std::function AutoArranger::get_objfn() { auto bincenter = m_bin.center(); return [this, bincenter](const Item &item) { - + auto result = objfunc(item, bincenter); - + double score = std::get<0>(result); - - auto isBig = [this](const Item& itm) { - return itm.area() / m_bin_area > BIG_ITEM_TRESHOLD ; - }; - - if(isBig(item)) { - auto mp = m_merged_pile; - mp.push_back(item.transformedShape()); - auto chull = sl::convexHull(mp); - double miss = Placer::overfit(chull, m_bin); - if(miss < 0) miss = 0; - score += miss*miss; - } - + return score; }; } From fcacc7042c9605e79ae2ff556c904ce46e15a498 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 6 Jan 2023 13:27:59 +0100 Subject: [PATCH 02/17] Class Selection - Added method to calculate bounding box aligned to current selected reference system --- src/slic3r/GUI/Selection.cpp | 263 ++++++++++++++++++++++++++--------- src/slic3r/GUI/Selection.hpp | 16 ++- 2 files changed, 208 insertions(+), 71 deletions(-) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 2e92c8b6b0..bd48e14c12 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -801,6 +801,131 @@ const BoundingBoxf3& Selection::get_full_unscaled_instance_local_bounding_box() } return *m_full_unscaled_instance_local_bounding_box; } + +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +const std::pair& Selection::get_bounding_box_in_current_reference_system() const +{ + static int last_coordinates_type = -1; + + assert(!is_empty()); + + ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type(); + if (m_mode == Instance && coordinates_type == ECoordinatesType::Local) + coordinates_type = ECoordinatesType::World; + + if (last_coordinates_type != int(coordinates_type)) + const_cast>*>(&m_bounding_box_in_current_reference_system)->reset(); + + if (!m_bounding_box_in_current_reference_system.has_value()) { + last_coordinates_type = int(coordinates_type); + + BoundingBoxf3 original_box; + Transform3d trafo; + + // + // calculate box aligned to current reference system + // + switch (coordinates_type) + { + case ECoordinatesType::World: + { + original_box = get_bounding_box(); + trafo = Transform3d::Identity(); + break; + } + case ECoordinatesType::Instance: { + for (unsigned int id : m_list) { + const GLVolume& v = *get_volume(id); + original_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix())); + } + trafo = get_first_volume()->get_instance_transformation().get_matrix(); + break; + } + case ECoordinatesType::Local: { + assert(is_single_volume_or_modifier()); + const GLVolume& v = *get_first_volume(); + original_box = v.bounding_box(); + trafo = v.world_matrix(); + break; + } + } + + // + // calculate box size in world coordinates + // + auto point_to_Vec4d = [](const Vec3d& p) { return Vec4d(p.x(), p.y(), p.z(), 1.0); }; + auto Vec4d_to_Vec3d = [](const Vec4d& v) { return Vec3d(v.x(), v.y(), v.z()); }; + + auto apply_transform = [](const std::vector& original, const Transform3d& trafo, bool normalize) { + std::vector transformed(original.size()); + for (size_t i = 0; i < original.size(); ++i) { + transformed[i] = trafo * original[i]; + if (normalize) + transformed[i].normalize(); + } + return transformed; + }; + + auto calc_box_size = [point_to_Vec4d, Vec4d_to_Vec3d, apply_transform](const BoundingBoxf3& box, const Transform3d& trafo) { + Geometry::Transformation transformation(trafo); + + // box aligned to current reference system + std::vector homo_vertices = { + point_to_Vec4d({ box.min.x(), box.min.y(), box.min.z() }), + point_to_Vec4d({ box.max.x(), box.min.y(), box.min.z() }), + point_to_Vec4d({ box.max.x(), box.max.y(), box.min.z() }), + point_to_Vec4d({ box.min.x(), box.max.y(), box.min.z() }), + point_to_Vec4d({ box.min.x(), box.min.y(), box.max.z() }), + point_to_Vec4d({ box.max.x(), box.min.y(), box.max.z() }), + point_to_Vec4d({ box.max.x(), box.max.y(), box.max.z() }), + point_to_Vec4d({ box.min.x(), box.max.y(), box.max.z() }) + }; + + // box vertices in world coordinates + std::vector transformed_homo_vertices = apply_transform(homo_vertices, trafo, false); + + // project back to current reference system + const std::vector homo_axes = { Vec4d::UnitX(), Vec4d::UnitY(), Vec4d::UnitZ() }; + std::vector transformed_homo_axes = apply_transform(homo_axes, Geometry::Transformation(trafo).get_matrix_no_scaling_factor(), true); + std::vector transformed_axes(transformed_homo_axes.size()); + for (size_t i = 0; i < transformed_homo_axes.size(); ++i) { + transformed_axes[i] = Vec4d_to_Vec3d(transformed_homo_axes[i]); + } + + Vec3d min = { DBL_MAX, DBL_MAX, DBL_MAX }; + Vec3d max = { -DBL_MAX, -DBL_MAX, -DBL_MAX }; + + for (const Vec4d& v_homo : transformed_homo_vertices) { + const Vec3d v = Vec4d_to_Vec3d(v_homo); + for (int i = 0; i < 3; ++i) { + const double dot_i = v.dot(transformed_axes[i]); + min(i) = std::min(min(i), dot_i); + max(i) = std::max(max(i), dot_i); + } + } + + // return size + const Vec3d size = max - min; + return size; + }; + + const Vec3d box_size = calc_box_size(original_box, trafo); + const std::vector box_center = { point_to_Vec4d(original_box.center()) }; + std::vector transformed_box_center = apply_transform(box_center, trafo, false); + + // + // return box centered at 0, 0, 0 + // + const Vec3d half_box_size = 0.5 * box_size; + BoundingBoxf3 out_box(-half_box_size, half_box_size); + Geometry::Transformation out_trafo(trafo); + out_trafo.set_offset(Vec4d_to_Vec3d(transformed_box_center[0])); + *const_cast>*>(&m_bounding_box_in_current_reference_system) = { out_box, out_trafo.get_matrix_no_scaling_factor() }; + } + + return *m_bounding_box_in_current_reference_system; +} +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_WORLD_COORDINATE void Selection::setup_cache() @@ -2669,88 +2794,88 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field, GL #if ENABLE_WORLD_COORDINATE_DEBUG void Selection::render_debug_window() const { - if (m_list.empty()) - return; + if (m_list.empty()) + return; - if (get_first_volume()->is_wipe_tower) - return; + if (get_first_volume()->is_wipe_tower) + return; - ImGuiWrapper& imgui = *wxGetApp().imgui(); - imgui.begin(std::string("Selection matrices"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize); + ImGuiWrapper& imgui = *wxGetApp().imgui(); + imgui.begin(std::string("Selection matrices"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize); - auto volume_name = [this](size_t id) { - const GLVolume& v = *(*m_volumes)[id]; - return m_model->objects[v.object_idx()]->volumes[v.volume_idx()]->name; - }; + auto volume_name = [this](size_t id) { + const GLVolume& v = *(*m_volumes)[id]; + return m_model->objects[v.object_idx()]->volumes[v.volume_idx()]->name; + }; - static size_t current_cmb_idx = 0; - static size_t current_vol_idx = *m_list.begin(); + static size_t current_cmb_idx = 0; + static size_t current_vol_idx = *m_list.begin(); - if (m_list.find(current_vol_idx) == m_list.end()) - current_vol_idx = *m_list.begin(); + if (m_list.find(current_vol_idx) == m_list.end()) + current_vol_idx = *m_list.begin(); - if (ImGui::BeginCombo("Volumes", volume_name(current_vol_idx).c_str())) { - size_t count = 0; - for (unsigned int id : m_list) { - const GLVolume& v = *(*m_volumes)[id]; - const bool is_selected = (current_cmb_idx == count); - if (ImGui::Selectable(volume_name(id).c_str(), is_selected)) { - current_cmb_idx = count; - current_vol_idx = id; - } - if (is_selected) - ImGui::SetItemDefaultFocus(); - ++count; - } - ImGui::EndCombo(); - } - - static int current_method_idx = 0; - ImGui::Combo("Decomposition method", ¤t_method_idx, "computeRotationScaling\0computeScalingRotation\0"); - - const GLVolume& v = *get_volume(current_vol_idx); - - auto add_matrix = [&imgui](const std::string& name, const Transform3d& m, unsigned int size) { - ImGui::BeginGroup(); - imgui.text(name); - if (ImGui::BeginTable(name.c_str(), size, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInner)) { - for (unsigned int r = 0; r < size; ++r) { - ImGui::TableNextRow(); - for (unsigned int c = 0; c < size; ++c) { - ImGui::TableSetColumnIndex(c); - imgui.text(std::to_string(m(r, c))); + if (ImGui::BeginCombo("Volumes", volume_name(current_vol_idx).c_str())) { + size_t count = 0; + for (unsigned int id : m_list) { + const GLVolume& v = *(*m_volumes)[id]; + const bool is_selected = (current_cmb_idx == count); + if (ImGui::Selectable(volume_name(id).c_str(), is_selected)) { + current_cmb_idx = count; + current_vol_idx = id; + } + if (is_selected) + ImGui::SetItemDefaultFocus(); + ++count; } - } - ImGui::EndTable(); + ImGui::EndCombo(); } - ImGui::EndGroup(); - }; - auto add_matrices_set = [add_matrix](const std::string& name, const Transform3d& m, size_t method) { - static unsigned int counter = 0; - ++counter; - if (ImGui::CollapsingHeader(name.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { - add_matrix("Full", m, 4); + static int current_method_idx = 0; + ImGui::Combo("Decomposition method", ¤t_method_idx, "computeRotationScaling\0computeScalingRotation\0"); - Matrix3d rotation; - Matrix3d scale; - if (method == 0) - m.computeRotationScaling(&rotation, &scale); - else - m.computeScalingRotation(&scale, &rotation); + const GLVolume& v = *get_volume(current_vol_idx); - ImGui::SameLine(); - add_matrix("Rotation component", Transform3d(rotation), 3); - ImGui::SameLine(); - add_matrix("Scale component", Transform3d(scale), 3); - } - }; + auto add_matrix = [&imgui](const std::string& name, const Transform3d& m, unsigned int size) { + ImGui::BeginGroup(); + imgui.text(name); + if (ImGui::BeginTable(name.c_str(), size, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInner)) { + for (unsigned int r = 0; r < size; ++r) { + ImGui::TableNextRow(); + for (unsigned int c = 0; c < size; ++c) { + ImGui::TableSetColumnIndex(c); + imgui.text(std::to_string(m(r, c))); + } + } + ImGui::EndTable(); + } + ImGui::EndGroup(); + }; - add_matrices_set("World", v.world_matrix(), current_method_idx); - add_matrices_set("Instance", v.get_instance_transformation().get_matrix(), current_method_idx); - add_matrices_set("Volume", v.get_volume_transformation().get_matrix(), current_method_idx); + auto add_matrices_set = [add_matrix](const std::string& name, const Transform3d& m, size_t method) { + static unsigned int counter = 0; + ++counter; + if (ImGui::CollapsingHeader(name.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { + add_matrix("Full", m, 4); - imgui.end(); + Matrix3d rotation; + Matrix3d scale; + if (method == 0) + m.computeRotationScaling(&rotation, &scale); + else + m.computeScalingRotation(&scale, &rotation); + + ImGui::SameLine(); + add_matrix("Rotation component", Transform3d(rotation), 3); + ImGui::SameLine(); + add_matrix("Scale component", Transform3d(scale), 3); + } + }; + + add_matrices_set("World", v.world_matrix(), current_method_idx); + add_matrices_set("Instance", v.get_instance_transformation().get_matrix(), current_method_idx); + add_matrices_set("Volume", v.get_volume_transformation().get_matrix(), current_method_idx); + + imgui.end(); } #endif // ENABLE_WORLD_COORDINATE_DEBUG diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index d2c483c6e6..cb2c461ef1 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -242,6 +242,11 @@ private: // Bounding box of a single full instance selection, in local coordinates, with no instance scaling applied. // Modifiers are taken in account std::optional m_full_unscaled_instance_local_bounding_box; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + // Bounding box aligned to the axis of the currently selected reference system (World/Object/Part) + // and transform to place and orient it in world coordinates + std::optional> m_bounding_box_in_current_reference_system; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_WORLD_COORDINATE #if ENABLE_RENDER_SELECTION_CENTER @@ -385,10 +390,14 @@ public: // Bounding box of a single full instance selection, in world coordinates. // Modifiers are taken in account const BoundingBoxf3& get_full_scaled_instance_bounding_box() const; - // Bounding box of a single full instance selection, in local coordinates, with no instance scaling applied. // Modifiers are taken in account const BoundingBoxf3& get_full_unscaled_instance_local_bounding_box() const; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + // Returns the bounding box aligned to the axis of the currently selected reference system (World/Object/Part) + // and the transform to place and orient it in world coordinates + const std::pair& get_bounding_box_in_current_reference_system() const; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_WORLD_COORDINATE void setup_cache(); @@ -464,7 +473,10 @@ private: m_bounding_box.reset(); m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset(); m_full_unscaled_instance_bounding_box.reset(); m_full_scaled_instance_bounding_box.reset(); - m_full_unscaled_instance_local_bounding_box.reset();; + m_full_unscaled_instance_local_bounding_box.reset(); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + m_bounding_box_in_current_reference_system.reset(); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } #else void set_bounding_boxes_dirty() { m_bounding_box.reset(); m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset(); } From 49fdf013196a8fa53852779f3d9b1eaffb85e4ce Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 6 Jan 2023 13:41:43 +0100 Subject: [PATCH 03/17] Tech ENABLE_WORLD_COORDINATE - Fixed size of Move Gizmo in 3D scene --- src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 32 ++++----------------------- src/slic3r/GUI/Gizmos/GLGizmoMove.hpp | 1 - src/slic3r/GUI/Selection.cpp | 5 ++--- src/slic3r/GUI/Selection.hpp | 6 ----- 4 files changed, 6 insertions(+), 38 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index 69fcc54147..7656226b59 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -149,7 +149,10 @@ void GLGizmoMove3D::on_render() glsafe(::glEnable(GL_DEPTH_TEST)); #if ENABLE_WORLD_COORDINATE - calc_selection_box_and_center(); + const Selection& selection = m_parent.get_selection(); + const auto& [box, box_trafo] = selection.get_bounding_box_in_current_reference_system(); + m_bounding_box = box; + m_center = box_trafo.translation(); const Transform3d base_matrix = local_transform(m_parent.get_selection()); for (int i = 0; i < 3; ++i) { m_grabbers[i].matrix = base_matrix; @@ -363,33 +366,6 @@ Transform3d GLGizmoMove3D::local_transform(const Selection& selection) const } return ret; } - -void GLGizmoMove3D::calc_selection_box_and_center() -{ - const Selection& selection = m_parent.get_selection(); - const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type(); - if (coordinates_type == ECoordinatesType::World) { - m_bounding_box = selection.get_bounding_box(); - m_center = m_bounding_box.center(); - } - else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) { - const GLVolume& v = *selection.get_first_volume(); - m_bounding_box = v.transformed_convex_hull_bounding_box( - v.get_instance_transformation().get_scaling_factor_matrix() * v.get_volume_transformation().get_scaling_factor_matrix()); - m_center = v.world_matrix() * m_bounding_box.center(); - } - else { - m_bounding_box.reset(); - const Selection::IndicesList& ids = selection.get_volume_idxs(); - for (unsigned int id : ids) { - const GLVolume& v = *selection.get_volume(id); - m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix())); - } - const Geometry::Transformation inst_trafo = selection.get_first_volume()->get_instance_transformation(); - m_bounding_box = m_bounding_box.transformed(inst_trafo.get_scaling_factor_matrix()); - m_center = inst_trafo.get_matrix_no_scaling_factor() * m_bounding_box.center(); - } -} #endif // ENABLE_WORLD_COORDINATE } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp index 5f1d562e9c..cd92d74721 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp @@ -67,7 +67,6 @@ private: double calc_projection(const UpdateData& data) const; #if ENABLE_WORLD_COORDINATE Transform3d local_transform(const Selection& selection) const; - void calc_selection_box_and_center(); #endif // ENABLE_WORLD_COORDINATE }; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index bd48e14c12..6d57541617 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -802,7 +802,6 @@ const BoundingBoxf3& Selection::get_full_unscaled_instance_local_bounding_box() return *m_full_unscaled_instance_local_bounding_box; } -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ const std::pair& Selection::get_bounding_box_in_current_reference_system() const { static int last_coordinates_type = -1; @@ -925,7 +924,6 @@ const std::pair& Selection::get_bounding_box_in_curr return *m_bounding_box_in_current_reference_system; } -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_WORLD_COORDINATE void Selection::setup_cache() @@ -961,7 +959,8 @@ void Selection::translate(const Vec3d& displacement, TransformationType transfor else { if (transformation_type.local()) { const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform(); - v.set_volume_offset(vol_trafo.get_offset() + vol_trafo.get_rotation_matrix() * displacement); + const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform(); + v.set_volume_offset(vol_trafo.get_offset() + inst_trafo.get_scaling_factor_matrix().inverse() * vol_trafo.get_rotation_matrix() * displacement); } else { Vec3d relative_disp = displacement; diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index cb2c461ef1..67b28ac785 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -242,11 +242,9 @@ private: // Bounding box of a single full instance selection, in local coordinates, with no instance scaling applied. // Modifiers are taken in account std::optional m_full_unscaled_instance_local_bounding_box; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // Bounding box aligned to the axis of the currently selected reference system (World/Object/Part) // and transform to place and orient it in world coordinates std::optional> m_bounding_box_in_current_reference_system; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_WORLD_COORDINATE #if ENABLE_RENDER_SELECTION_CENTER @@ -393,11 +391,9 @@ public: // Bounding box of a single full instance selection, in local coordinates, with no instance scaling applied. // Modifiers are taken in account const BoundingBoxf3& get_full_unscaled_instance_local_bounding_box() const; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // Returns the bounding box aligned to the axis of the currently selected reference system (World/Object/Part) // and the transform to place and orient it in world coordinates const std::pair& get_bounding_box_in_current_reference_system() const; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_WORLD_COORDINATE void setup_cache(); @@ -474,9 +470,7 @@ private: m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset(); m_full_unscaled_instance_bounding_box.reset(); m_full_scaled_instance_bounding_box.reset(); m_full_unscaled_instance_local_bounding_box.reset(); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ m_bounding_box_in_current_reference_system.reset(); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } #else void set_bounding_boxes_dirty() { m_bounding_box.reset(); m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset(); } From 0f302a71064a7a181235d11e87cccadde8a7a0a2 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 6 Jan 2023 14:00:49 +0100 Subject: [PATCH 04/17] Tech ENABLE_WORLD_COORDINATE - Fixed rendering of selection bounding box --- src/slic3r/GUI/Selection.cpp | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 6d57541617..fb7fa51700 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1848,27 +1848,7 @@ void Selection::render(float scale_factor) m_scale_factor = scale_factor; // render cumulative bounding box of selected volumes #if ENABLE_WORLD_COORDINATE - BoundingBoxf3 box; - Transform3d trafo; - const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type(); - if (coordinates_type == ECoordinatesType::World) { - box = get_bounding_box(); - trafo = Transform3d::Identity(); - } - else if (coordinates_type == ECoordinatesType::Local && is_single_volume_or_modifier()) { - const GLVolume& v = *get_first_volume(); - box = v.bounding_box(); - trafo = v.world_matrix(); - } - else { - const Selection::IndicesList& ids = get_volume_idxs(); - for (unsigned int id : ids) { - const GLVolume& v = *get_volume(id); - box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix())); - } - trafo = get_first_volume()->get_instance_transformation().get_matrix(); - } - + const auto [box, trafo] = get_bounding_box_in_current_reference_system(); render_bounding_box(box, trafo, ColorRGB::WHITE()); #else render_bounding_box(get_bounding_box(), ColorRGB::WHITE()); From 74b391218d617d874ab65923b4b61414d8b3afa8 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 6 Jan 2023 14:35:54 +0100 Subject: [PATCH 05/17] Tech ENABLE_WORLD_COORDINATE - Fixed size of selection shown in sidebar panel --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 0ab4f166b0..94ab206962 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -714,13 +714,14 @@ void ObjectManipulation::update_settings_value(const Selection& selection) m_new_position = volume->get_instance_offset(); m_new_scale_label_string = L("Scale"); m_new_scale = Vec3d(100.0, 100.0, 100.0); + m_new_size = selection.get_bounding_box_in_current_reference_system().first.size(); #else if (m_world_coordinates) { m_new_scale = m_new_size.cwiseQuotient(selection.get_unscaled_instance_bounding_box().size()) * 100.0; + m_new_size = selection.get_scaled_instance_bounding_box().size(); #endif // ENABLE_WORLD_COORDINATE m_new_rotate_label_string = L("Rotate"); m_new_rotation = Vec3d::Zero(); - m_new_size = selection.get_scaled_instance_bounding_box().size(); } else { #if ENABLE_WORLD_COORDINATE @@ -729,11 +730,12 @@ void ObjectManipulation::update_settings_value(const Selection& selection) m_new_position = Vec3d::Zero(); m_new_rotation = Vec3d::Zero(); m_new_scale = Vec3d(100.0, 100.0, 100.0); + m_new_size = selection.get_bounding_box_in_current_reference_system().first.size(); #else m_new_rotation = volume->get_instance_rotation() * (180.0 / M_PI); + m_new_size = volume->get_instance_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size()); #endif // ENABLE_WORLD_COORDINATE m_new_scale = volume->get_instance_scaling_factor() * 100.0; - m_new_size = volume->get_instance_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size()); } m_new_enabled = true; @@ -743,7 +745,11 @@ void ObjectManipulation::update_settings_value(const Selection& selection) m_new_position = box.center(); m_new_rotation = Vec3d::Zero(); m_new_scale = Vec3d(100.0, 100.0, 100.0); - m_new_size = box.size(); +#if ENABLE_WORLD_COORDINATE + m_new_size = selection.get_bounding_box_in_current_reference_system().first.size(); +#else + m_new_size = box.size(); +#endif // ENABLE_WORLD_COORDINATE m_new_rotate_label_string = L("Rotate"); m_new_scale_label_string = L("Scale"); m_new_enabled = true; @@ -766,7 +772,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection) m_new_scale_label_string = L("Scale"); m_new_scale = Vec3d(100.0, 100.0, 100.0); m_new_rotation = Vec3d::Zero(); - m_new_size = volume->transformed_convex_hull_bounding_box(trafo.get_matrix()).size(); + m_new_size = selection.get_bounding_box_in_current_reference_system().first.size(); } else if (is_local_coordinates()) { m_new_move_label_string = L("Translate"); @@ -774,7 +780,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection) m_new_position = Vec3d::Zero(); m_new_rotation = Vec3d::Zero(); m_new_scale = volume->get_volume_scaling_factor() * 100.0; - m_new_size = volume->get_volume_scaling_factor().cwiseProduct(volume->bounding_box().size()); + m_new_size = selection.get_bounding_box_in_current_reference_system().first.size(); } else { #endif // ENABLE_WORLD_COORDINATE @@ -783,8 +789,8 @@ void ObjectManipulation::update_settings_value(const Selection& selection) m_new_rotation = Vec3d::Zero(); #if ENABLE_WORLD_COORDINATE m_new_scale_label_string = L("Scale"); - m_new_size = volume->transformed_convex_hull_bounding_box(volume->get_volume_transformation().get_matrix()).size(); m_new_scale = Vec3d(100.0, 100.0, 100.0); + m_new_size = selection.get_bounding_box_in_current_reference_system().first.size(); } #else m_new_scale = volume->get_volume_scaling_factor() * 100.0; @@ -797,7 +803,11 @@ void ObjectManipulation::update_settings_value(const Selection& selection) m_new_move_label_string = L("Translate"); m_new_rotate_label_string = L("Rotate"); m_new_scale_label_string = L("Scale"); +#if ENABLE_WORLD_COORDINATE + m_new_size = selection.get_bounding_box_in_current_reference_system().first.size(); +#else m_new_size = selection.get_bounding_box().size(); +#endif // ENABLE_WORLD_COORDINATE m_new_enabled = true; } else { From 4bb768c1ce9c6504843f8805d8806f16e6f4552a Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 9 Jan 2023 08:14:47 +0100 Subject: [PATCH 06/17] Tech ENABLE_WORLD_COORDINATE - Fixed size of Scale Gizmo in 3D scene --- src/slic3r/GUI/Gizmos/GLGizmoScale.cpp | 417 ++++++++++++++++--------- src/slic3r/GUI/Selection.cpp | 2 +- 2 files changed, 272 insertions(+), 147 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index 1787e5cf89..173585ec00 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -206,6 +206,7 @@ void GLGizmoScale3D::on_dragging(const UpdateData& data) do_scale_uniform(data); } +#if ENABLE_WORLD_COORDINATE void GLGizmoScale3D::on_render() { const Selection& selection = m_parent.get_selection(); @@ -213,98 +214,20 @@ void GLGizmoScale3D::on_render() glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); glsafe(::glEnable(GL_DEPTH_TEST)); - m_bounding_box.reset(); -#if ENABLE_WORLD_COORDINATE - m_grabbers_transform = Transform3d::Identity(); - m_center = Vec3d::Zero(); + const auto& [box, box_trafo] = selection.get_bounding_box_in_current_reference_system(); + m_bounding_box = box; + m_center = box_trafo.translation(); + m_grabbers_transform = box_trafo; m_instance_center = Vec3d::Zero(); - if (selection.is_single_full_instance() && !wxGetApp().obj_manipul()->is_world_coordinates()) { -#else - m_transform = Transform3d::Identity(); - // Transforms grabbers' offsets to world refefence system - Transform3d offsets_transform = Transform3d::Identity(); - m_offsets_transform = Transform3d::Identity(); - Vec3d angles = Vec3d::Zero(); - - if (selection.is_single_full_instance()) { -#endif // ENABLE_WORLD_COORDINATE - // calculate bounding box in instance local reference system - const Selection::IndicesList& idxs = selection.get_volume_idxs(); - for (unsigned int idx : idxs) { - const GLVolume& v = *selection.get_volume(idx); - m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix())); - } - -#if ENABLE_WORLD_COORDINATE - m_bounding_box = m_bounding_box.transformed(selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix()); -#endif // ENABLE_WORLD_COORDINATE - - // gets transform from first selected volume - const GLVolume& v = *selection.get_first_volume(); -#if ENABLE_WORLD_COORDINATE - const Transform3d inst_trafo = v.get_instance_transformation().get_matrix_no_scaling_factor(); - m_grabbers_transform = inst_trafo * Geometry::translation_transform(m_bounding_box.center()); - m_center = inst_trafo * m_bounding_box.center(); - m_instance_center = v.get_instance_offset(); - } - else if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_instance_coordinates()) { -#else - m_transform = v.get_instance_transformation().get_matrix(); - - // gets angles from first selected volume - angles = v.get_instance_rotation(); - // consider rotation+mirror only components of the transform for offsets - offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v.get_instance_mirror()); - m_offsets_transform = offsets_transform; - } - else if (selection.is_single_modifier() || selection.is_single_volume()) { -#endif // ENABLE_WORLD_COORDINATE - const GLVolume& v = *selection.get_first_volume(); -#if ENABLE_WORLD_COORDINATE - m_bounding_box.merge(v.transformed_convex_hull_bounding_box( - v.get_instance_transformation().get_scaling_factor_matrix() * v.get_volume_transformation().get_matrix_no_offset())); - Geometry::Transformation trafo(v.get_instance_transformation().get_rotation_matrix()); - trafo.set_offset(v.world_matrix().translation()); - m_grabbers_transform = trafo.get_matrix(); - m_center = v.world_matrix() * m_bounding_box.center(); + if (selection.is_single_full_instance() && !wxGetApp().obj_manipul()->is_world_coordinates()) + m_instance_center = selection.get_first_volume()->get_instance_offset(); + else if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_instance_coordinates()) m_instance_center = m_center; - } - else if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates()) { - const GLVolume& v = *selection.get_first_volume(); - m_bounding_box.merge(v.transformed_convex_hull_bounding_box( - v.get_instance_transformation().get_scaling_factor_matrix() * v.get_volume_transformation().get_scaling_factor_matrix())); - Geometry::Transformation trafo(v.get_instance_transformation().get_rotation_matrix() * v.get_volume_transformation().get_rotation_matrix()); - trafo.set_offset(v.world_matrix().translation()); - m_grabbers_transform = trafo.get_matrix(); - m_center = v.world_matrix() * m_bounding_box.center(); + else if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates()) m_instance_center = m_center; - } - else { - m_bounding_box = selection.get_bounding_box(); - m_grabbers_transform = Geometry::translation_transform(m_bounding_box.center()); - m_center = m_bounding_box.center(); - m_instance_center = selection.is_single_full_instance() ? selection.get_first_volume()->get_instance_offset() : m_center; - } -#else - m_bounding_box = v.bounding_box(); - m_transform = v.world_matrix(); - angles = Geometry::extract_rotation(m_transform); - // consider rotation+mirror only components of the transform for offsets - offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v.get_instance_mirror()); - m_offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), v.get_volume_rotation(), Vec3d::Ones(), v.get_volume_mirror()); - } else - m_bounding_box = selection.get_bounding_box(); + m_instance_center = selection.is_single_full_instance() ? selection.get_first_volume()->get_instance_offset() : m_center; - const Vec3d& center = m_bounding_box.center(); - const Vec3d offset_x = offsets_transform * Vec3d((double)Offset, 0.0, 0.0); - const Vec3d offset_y = offsets_transform * Vec3d(0.0, (double)Offset, 0.0); - const Vec3d offset_z = offsets_transform * Vec3d(0.0, 0.0, (double)Offset); - - const bool ctrl_down = (m_dragging && m_starting.ctrl_down) || (!m_dragging && wxGetKeyState(WXK_CONTROL)); -#endif // ENABLE_WORLD_COORDINATE - -#if ENABLE_WORLD_COORDINATE // x axis const Vec3d box_half_size = 0.5 * m_bounding_box.size(); bool use_constrain = wxGetKeyState(WXK_CONTROL) && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()); @@ -335,57 +258,18 @@ void GLGizmoScale3D::on_render() m_grabbers[8].color = (use_constrain && m_hover_id == 6) ? CONSTRAINED_COLOR : m_highlight_color; m_grabbers[9].center = { -(box_half_size.x() + Offset), box_half_size.y() + Offset, 0.0 }; m_grabbers[9].color = (use_constrain && m_hover_id == 7) ? CONSTRAINED_COLOR : m_highlight_color; -#else - // x axis - m_grabbers[0].center = m_transform * Vec3d(m_bounding_box.min.x(), center.y(), center.z()) - offset_x; - m_grabbers[0].color = (ctrl_down && m_hover_id == 1) ? CONSTRAINED_COLOR : AXES_COLOR[0]; - m_grabbers[1].center = m_transform * Vec3d(m_bounding_box.max.x(), center.y(), center.z()) + offset_x; - m_grabbers[1].color = (ctrl_down && m_hover_id == 0) ? CONSTRAINED_COLOR : AXES_COLOR[0]; - - // y axis - m_grabbers[2].center = m_transform * Vec3d(center.x(), m_bounding_box.min.y(), center.z()) - offset_y; - m_grabbers[2].color = (ctrl_down && m_hover_id == 3) ? CONSTRAINED_COLOR : AXES_COLOR[1]; - m_grabbers[3].center = m_transform * Vec3d(center.x(), m_bounding_box.max.y(), center.z()) + offset_y; - m_grabbers[3].color = (ctrl_down && m_hover_id == 2) ? CONSTRAINED_COLOR : AXES_COLOR[1]; - - // z axis - m_grabbers[4].center = m_transform * Vec3d(center.x(), center.y(), m_bounding_box.min.z()) - offset_z; - m_grabbers[4].color = (ctrl_down && m_hover_id == 5) ? CONSTRAINED_COLOR : AXES_COLOR[2]; - m_grabbers[5].center = m_transform * Vec3d(center.x(), center.y(), m_bounding_box.max.z()) + offset_z; - m_grabbers[5].color = (ctrl_down && m_hover_id == 4) ? CONSTRAINED_COLOR : AXES_COLOR[2]; - - // uniform - m_grabbers[6].center = m_transform * Vec3d(m_bounding_box.min.x(), m_bounding_box.min.y(), center.z()) - offset_x - offset_y; - m_grabbers[7].center = m_transform * Vec3d(m_bounding_box.max.x(), m_bounding_box.min.y(), center.z()) + offset_x - offset_y; - m_grabbers[8].center = m_transform * Vec3d(m_bounding_box.max.x(), m_bounding_box.max.y(), center.z()) + offset_x + offset_y; - m_grabbers[9].center = m_transform * Vec3d(m_bounding_box.min.x(), m_bounding_box.max.y(), center.z()) - offset_x + offset_y; - - for (int i = 6; i < 10; ++i) { - m_grabbers[i].color = m_highlight_color; - } - - // sets grabbers orientation - for (int i = 0; i < 10; ++i) { - m_grabbers[i].angles = angles; - } -#endif // ENABLE_WORLD_COORDINATE #if ENABLE_GL_CORE_PROFILE if (!OpenGLManager::get_gl_info().is_core_profile()) #endif // ENABLE_GL_CORE_PROFILE glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); -#if ENABLE_WORLD_COORDINATE const Transform3d base_matrix = local_transform(selection); for (int i = 0; i < 10; ++i) { m_grabbers[i].matrix = base_matrix; } const float grabber_mean_size = (float)((m_bounding_box.size().x() + m_bounding_box.size().y() + m_bounding_box.size().z()) / 3.0); -#else - const BoundingBoxf3& selection_box = selection.get_bounding_box(); - const float grabber_mean_size = (float)((selection_box.size().x() + selection_box.size().y() + selection_box.size().z()) / 3.0); -#endif // ENABLE_WORLD_COORDINATE if (m_hover_id == -1) { // draw connections @@ -397,11 +281,7 @@ void GLGizmoScale3D::on_render() if (shader != nullptr) { shader->start_using(); const Camera& camera = wxGetApp().plater()->get_camera(); -#if ENABLE_WORLD_COORDINATE shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix); -#else - shader->set_uniform("view_model_matrix", camera.get_view_matrix()); -#endif // ENABLE_WORLD_COORDINATE shader->set_uniform("projection_matrix", camera.get_projection_matrix()); #if ENABLE_GL_CORE_PROFILE const std::array& viewport = camera.get_viewport(); @@ -435,11 +315,7 @@ void GLGizmoScale3D::on_render() if (shader != nullptr) { shader->start_using(); const Camera& camera = wxGetApp().plater()->get_camera(); -#if ENABLE_WORLD_COORDINATE shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix); -#else - shader->set_uniform("view_model_matrix", camera.get_view_matrix()); -#endif // ENABLE_WORLD_COORDINATE shader->set_uniform("projection_matrix", camera.get_projection_matrix()); #if ENABLE_GL_CORE_PROFILE const std::array& viewport = camera.get_viewport(); @@ -471,11 +347,7 @@ void GLGizmoScale3D::on_render() if (shader != nullptr) { shader->start_using(); const Camera& camera = wxGetApp().plater()->get_camera(); -#if ENABLE_WORLD_COORDINATE shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix); -#else - shader->set_uniform("view_model_matrix", camera.get_view_matrix()); -#endif // ENABLE_WORLD_COORDINATE shader->set_uniform("projection_matrix", camera.get_projection_matrix()); #if ENABLE_GL_CORE_PROFILE const std::array& viewport = camera.get_viewport(); @@ -507,11 +379,7 @@ void GLGizmoScale3D::on_render() if (shader != nullptr) { shader->start_using(); const Camera& camera = wxGetApp().plater()->get_camera(); -#if ENABLE_WORLD_COORDINATE shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix); -#else - shader->set_uniform("view_model_matrix", camera.get_view_matrix()); -#endif // ENABLE_WORLD_COORDINATE shader->set_uniform("projection_matrix", camera.get_projection_matrix()); #if ENABLE_GL_CORE_PROFILE const std::array& viewport = camera.get_viewport(); @@ -543,11 +411,7 @@ void GLGizmoScale3D::on_render() if (shader != nullptr) { shader->start_using(); const Camera& camera = wxGetApp().plater()->get_camera(); -#if ENABLE_WORLD_COORDINATE shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix); -#else - shader->set_uniform("view_model_matrix", camera.get_view_matrix()); -#endif // ENABLE_WORLD_COORDINATE shader->set_uniform("projection_matrix", camera.get_projection_matrix()); #if ENABLE_GL_CORE_PROFILE const std::array& viewport = camera.get_viewport(); @@ -574,6 +438,267 @@ void GLGizmoScale3D::on_render() } } } +#else +void GLGizmoScale3D::on_render() +{ + const Selection& selection = m_parent.get_selection(); + + glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); + glsafe(::glEnable(GL_DEPTH_TEST)); + + m_bounding_box.reset(); + m_transform = Transform3d::Identity(); + // Transforms grabbers' offsets to world refefence system + Transform3d offsets_transform = Transform3d::Identity(); + m_offsets_transform = Transform3d::Identity(); + Vec3d angles = Vec3d::Zero(); + + if (selection.is_single_full_instance()) { + // calculate bounding box in instance local reference system + const Selection::IndicesList& idxs = selection.get_volume_idxs(); + for (unsigned int idx : idxs) { + const GLVolume& v = *selection.get_volume(idx); + m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix())); + } + + // gets transform from first selected volume + const GLVolume& v = *selection.get_first_volume(); + m_transform = v.get_instance_transformation().get_matrix(); + + // gets angles from first selected volume + angles = v.get_instance_rotation(); + // consider rotation+mirror only components of the transform for offsets + offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v.get_instance_mirror()); + m_offsets_transform = offsets_transform; + } + else if (selection.is_single_modifier() || selection.is_single_volume()) { + const GLVolume& v = *selection.get_first_volume(); + m_bounding_box = v.bounding_box(); + m_transform = v.world_matrix(); + angles = Geometry::extract_rotation(m_transform); + // consider rotation+mirror only components of the transform for offsets + offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v.get_instance_mirror()); + m_offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), v.get_volume_rotation(), Vec3d::Ones(), v.get_volume_mirror()); + } + else + m_bounding_box = selection.get_bounding_box(); + + const Vec3d& center = m_bounding_box.center(); + const Vec3d offset_x = offsets_transform * Vec3d((double)Offset, 0.0, 0.0); + const Vec3d offset_y = offsets_transform * Vec3d(0.0, (double)Offset, 0.0); + const Vec3d offset_z = offsets_transform * Vec3d(0.0, 0.0, (double)Offset); + + const bool ctrl_down = (m_dragging && m_starting.ctrl_down) || (!m_dragging && wxGetKeyState(WXK_CONTROL)); + + // x axis + m_grabbers[0].center = m_transform * Vec3d(m_bounding_box.min.x(), center.y(), center.z()) - offset_x; + m_grabbers[0].color = (ctrl_down && m_hover_id == 1) ? CONSTRAINED_COLOR : AXES_COLOR[0]; + m_grabbers[1].center = m_transform * Vec3d(m_bounding_box.max.x(), center.y(), center.z()) + offset_x; + m_grabbers[1].color = (ctrl_down && m_hover_id == 0) ? CONSTRAINED_COLOR : AXES_COLOR[0]; + + // y axis + m_grabbers[2].center = m_transform * Vec3d(center.x(), m_bounding_box.min.y(), center.z()) - offset_y; + m_grabbers[2].color = (ctrl_down && m_hover_id == 3) ? CONSTRAINED_COLOR : AXES_COLOR[1]; + m_grabbers[3].center = m_transform * Vec3d(center.x(), m_bounding_box.max.y(), center.z()) + offset_y; + m_grabbers[3].color = (ctrl_down && m_hover_id == 2) ? CONSTRAINED_COLOR : AXES_COLOR[1]; + + // z axis + m_grabbers[4].center = m_transform * Vec3d(center.x(), center.y(), m_bounding_box.min.z()) - offset_z; + m_grabbers[4].color = (ctrl_down && m_hover_id == 5) ? CONSTRAINED_COLOR : AXES_COLOR[2]; + m_grabbers[5].center = m_transform * Vec3d(center.x(), center.y(), m_bounding_box.max.z()) + offset_z; + m_grabbers[5].color = (ctrl_down && m_hover_id == 4) ? CONSTRAINED_COLOR : AXES_COLOR[2]; + + // uniform + m_grabbers[6].center = m_transform * Vec3d(m_bounding_box.min.x(), m_bounding_box.min.y(), center.z()) - offset_x - offset_y; + m_grabbers[7].center = m_transform * Vec3d(m_bounding_box.max.x(), m_bounding_box.min.y(), center.z()) + offset_x - offset_y; + m_grabbers[8].center = m_transform * Vec3d(m_bounding_box.max.x(), m_bounding_box.max.y(), center.z()) + offset_x + offset_y; + m_grabbers[9].center = m_transform * Vec3d(m_bounding_box.min.x(), m_bounding_box.max.y(), center.z()) - offset_x + offset_y; + + for (int i = 6; i < 10; ++i) { + m_grabbers[i].color = m_highlight_color; + } + + // sets grabbers orientation + for (int i = 0; i < 10; ++i) { + m_grabbers[i].angles = angles; + } + +#if ENABLE_GL_CORE_PROFILE + if (!OpenGLManager::get_gl_info().is_core_profile()) +#endif // ENABLE_GL_CORE_PROFILE + glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); + + const BoundingBoxf3& selection_box = selection.get_bounding_box(); + const float grabber_mean_size = (float)((selection_box.size().x() + selection_box.size().y() + selection_box.size().z()) / 3.0); + + if (m_hover_id == -1) { + // draw connections +#if ENABLE_GL_CORE_PROFILE + GLShaderProgram* shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat"); +#else + GLShaderProgram* shader = wxGetApp().get_shader("flat"); +#endif // ENABLE_GL_CORE_PROFILE + if (shader != nullptr) { + shader->start_using(); + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); +#if ENABLE_GL_CORE_PROFILE + const std::array& viewport = camera.get_viewport(); + shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3]))); + shader->set_uniform("width", 0.25f); + shader->set_uniform("gap_size", 0.0f); +#endif // ENABLE_GL_CORE_PROFILE + if (m_grabbers[0].enabled && m_grabbers[1].enabled) + render_grabbers_connection(0, 1, m_grabbers[0].color); + if (m_grabbers[2].enabled && m_grabbers[3].enabled) + render_grabbers_connection(2, 3, m_grabbers[2].color); + if (m_grabbers[4].enabled && m_grabbers[5].enabled) + render_grabbers_connection(4, 5, m_grabbers[4].color); + render_grabbers_connection(6, 7, m_base_color); + render_grabbers_connection(7, 8, m_base_color); + render_grabbers_connection(8, 9, m_base_color); + render_grabbers_connection(9, 6, m_base_color); + shader->stop_using(); + } + + // draw grabbers + render_grabbers(grabber_mean_size); + } + else if ((m_hover_id == 0 || m_hover_id == 1) && m_grabbers[0].enabled && m_grabbers[1].enabled) { + // draw connections +#if ENABLE_GL_CORE_PROFILE + GLShaderProgram* shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat"); +#else + GLShaderProgram* shader = wxGetApp().get_shader("flat"); +#endif // ENABLE_GL_CORE_PROFILE + if (shader != nullptr) { + shader->start_using(); + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); +#if ENABLE_GL_CORE_PROFILE + const std::array& viewport = camera.get_viewport(); + shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3]))); + shader->set_uniform("width", 0.25f); + shader->set_uniform("gap_size", 0.0f); +#endif // ENABLE_GL_CORE_PROFILE + render_grabbers_connection(0, 1, m_grabbers[0].color); + shader->stop_using(); + } + + // draw grabbers + shader = wxGetApp().get_shader("gouraud_light"); + if (shader != nullptr) { + shader->start_using(); + shader->set_uniform("emission_factor", 0.1f); + m_grabbers[0].render(true, grabber_mean_size); + m_grabbers[1].render(true, grabber_mean_size); + shader->stop_using(); + } + } + else if ((m_hover_id == 2 || m_hover_id == 3) && m_grabbers[2].enabled && m_grabbers[3].enabled) { + // draw connections +#if ENABLE_GL_CORE_PROFILE + GLShaderProgram* shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat"); +#else + GLShaderProgram* shader = wxGetApp().get_shader("flat"); +#endif // ENABLE_GL_CORE_PROFILE + if (shader != nullptr) { + shader->start_using(); + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); +#if ENABLE_GL_CORE_PROFILE + const std::array& viewport = camera.get_viewport(); + shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3]))); + shader->set_uniform("width", 0.25f); + shader->set_uniform("gap_size", 0.0f); +#endif // ENABLE_GL_CORE_PROFILE + render_grabbers_connection(2, 3, m_grabbers[2].color); + shader->stop_using(); + } + + // draw grabbers + shader = wxGetApp().get_shader("gouraud_light"); + if (shader != nullptr) { + shader->start_using(); + shader->set_uniform("emission_factor", 0.1f); + m_grabbers[2].render(true, grabber_mean_size); + m_grabbers[3].render(true, grabber_mean_size); + shader->stop_using(); + } + } + else if ((m_hover_id == 4 || m_hover_id == 5) && m_grabbers[4].enabled && m_grabbers[5].enabled) { + // draw connections +#if ENABLE_GL_CORE_PROFILE + GLShaderProgram* shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat"); +#else + GLShaderProgram* shader = wxGetApp().get_shader("flat"); +#endif // ENABLE_GL_CORE_PROFILE + if (shader != nullptr) { + shader->start_using(); + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); +#if ENABLE_GL_CORE_PROFILE + const std::array& viewport = camera.get_viewport(); + shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3]))); + shader->set_uniform("width", 0.25f); + shader->set_uniform("gap_size", 0.0f); +#endif // ENABLE_GL_CORE_PROFILE + render_grabbers_connection(4, 5, m_grabbers[4].color); + shader->stop_using(); + } + + // draw grabbers + shader = wxGetApp().get_shader("gouraud_light"); + if (shader != nullptr) { + shader->start_using(); + shader->set_uniform("emission_factor", 0.1f); + m_grabbers[4].render(true, grabber_mean_size); + m_grabbers[5].render(true, grabber_mean_size); + shader->stop_using(); + } + } + else if (m_hover_id >= 6) { + // draw connections +#if ENABLE_GL_CORE_PROFILE + GLShaderProgram* shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat"); +#else + GLShaderProgram* shader = wxGetApp().get_shader("flat"); +#endif // ENABLE_GL_CORE_PROFILE + if (shader != nullptr) { + shader->start_using(); + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); +#if ENABLE_GL_CORE_PROFILE + const std::array& viewport = camera.get_viewport(); + shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3]))); + shader->set_uniform("width", 0.25f); + shader->set_uniform("gap_size", 0.0f); +#endif // ENABLE_GL_CORE_PROFILE + render_grabbers_connection(6, 7, m_drag_color); + render_grabbers_connection(7, 8, m_drag_color); + render_grabbers_connection(8, 9, m_drag_color); + render_grabbers_connection(9, 6, m_drag_color); + shader->stop_using(); + } + + // draw grabbers + shader = wxGetApp().get_shader("gouraud_light"); + if (shader != nullptr) { + shader->start_using(); + shader->set_uniform("emission_factor", 0.1f); + for (int i = 6; i < 10; ++i) { + m_grabbers[i].render(true, grabber_mean_size); + } + shader->stop_using(); + } + } +} +#endif // ENABLE_WORLD_COORDINATE void GLGizmoScale3D::on_register_raycasters_for_picking() { diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index fb7fa51700..dd8364c029 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1848,7 +1848,7 @@ void Selection::render(float scale_factor) m_scale_factor = scale_factor; // render cumulative bounding box of selected volumes #if ENABLE_WORLD_COORDINATE - const auto [box, trafo] = get_bounding_box_in_current_reference_system(); + const auto& [box, trafo] = get_bounding_box_in_current_reference_system(); render_bounding_box(box, trafo, ColorRGB::WHITE()); #else render_bounding_box(get_bounding_box(), ColorRGB::WHITE()); From ec6daeb1d3a5ce62281f49a7c9e20bb77ca1b7d1 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 9 Jan 2023 09:00:59 +0100 Subject: [PATCH 07/17] Preferences: Fixed typo after improvements related to Download path --- src/slic3r/GUI/Preferences.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 3c5c11a6bb..106937c46b 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -562,7 +562,7 @@ void PreferencesDialog::build() if (opt_key == "suppress_hyperlinks") m_values[opt_key] = boost::any_cast(value) ? "1" : ""; else - m_values[opt_key] = boost::any_cast(value) ? "1" : "0"; m_values[opt_key] = boost::any_cast(value) ? "1" : "0"; + m_values[opt_key] = boost::any_cast(value) ? "1" : "0"; }; From 2c02db35140612c377ee847b802428dbb0c908f7 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 9 Jan 2023 12:25:26 +0100 Subject: [PATCH 08/17] Tech ENABLE_WORLD_COORDINATE - Fixed size of Rotate Gizmo in 3D scene --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 7 +- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 49 +---- src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp | 4 +- src/slic3r/GUI/Selection.cpp | 210 +++++++++++----------- src/slic3r/GUI/Selection.hpp | 5 +- 6 files changed, 127 insertions(+), 150 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 94ab206962..e502b25d7e 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -884,7 +884,10 @@ void ObjectManipulation::update_if_dirty() m_lock_bnt->SetLock(m_uniform_scale); m_lock_bnt->SetToolTip(wxEmptyString); m_lock_bnt->enable(); -#if !ENABLE_WORLD_COORDINATE +#if ENABLE_WORLD_COORDINATE + if (m_word_local_combo->GetSelection() != (int)m_coordinates_type) + m_word_local_combo->SetSelection((int)m_coordinates_type); +#else } { @@ -892,7 +895,7 @@ void ObjectManipulation::update_if_dirty() if (m_word_local_combo->GetSelection() != new_selection) m_word_local_combo->SetSelection(new_selection); } -#endif // !ENABLE_WORLD_COORDINATE +#endif // ENABLE_WORLD_COORDINATE if (m_new_enabled) m_og->enable(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index dc0b9fed79..5651ac190c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -129,7 +129,7 @@ GLGizmoEmboss::GLGizmoEmboss(GLCanvas3D &parent) , m_update_job_cancel(nullptr) { m_rotate_gizmo.set_group_id(0); - m_rotate_gizmo.set_using_local_coordinate(true); + m_rotate_gizmo.set_force_local_coordinate(true); // TODO: add suggestion to use https://fontawesome.com/ // (copy & paste) unicode symbols from web // paste HEX unicode into notepad move cursor after unicode press [alt] + [x] diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index 0be1d16551..345d733afd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -234,50 +234,17 @@ void GLGizmoRotate::on_render() #if ENABLE_WORLD_COORDINATE void GLGizmoRotate::init_data_from_selection(const Selection& selection) { - ECoordinatesType coordinates_type; - if (m_using_local_coordinate || - selection.is_wipe_tower()) - coordinates_type = ECoordinatesType::Local; - else - coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type(); - if (coordinates_type == ECoordinatesType::World) { - m_bounding_box = selection.get_bounding_box(); - m_center = m_bounding_box.center(); - } - else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) { - const GLVolume& v = *selection.get_first_volume(); - m_bounding_box = v.transformed_convex_hull_bounding_box( - v.get_instance_transformation().get_scaling_factor_matrix() * v.get_volume_transformation().get_scaling_factor_matrix()); - m_center = v.world_matrix() * m_bounding_box.center(); - } - else { - m_bounding_box.reset(); - const Selection::IndicesList& ids = selection.get_volume_idxs(); - for (unsigned int id : ids) { - const GLVolume& v = *selection.get_volume(id); - m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix())); - } - const Geometry::Transformation inst_trafo = selection.get_first_volume()->get_instance_transformation(); - m_bounding_box = m_bounding_box.transformed(inst_trafo.get_scaling_factor_matrix()); - m_center = inst_trafo.get_matrix_no_scaling_factor() * m_bounding_box.center(); - } + const auto [box, box_trafo] = m_force_local_coordinate ? + selection.get_bounding_box_in_reference_system(ECoordinatesType::Local) : selection.get_bounding_box_in_current_reference_system(); + m_bounding_box = box; + m_center = box_trafo.translation(); + m_orient_matrix = box_trafo; m_radius = Offset + m_bounding_box.radius(); m_snap_coarse_in_radius = m_radius / 3.0f; m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius; m_snap_fine_in_radius = m_radius; m_snap_fine_out_radius = m_snap_fine_in_radius + m_radius * ScaleLongTooth; - - if (coordinates_type == ECoordinatesType::World) - m_orient_matrix = Transform3d::Identity(); - else if (coordinates_type == ECoordinatesType::Local && (selection.is_wipe_tower() || selection.is_single_volume_or_modifier())) { - const GLVolume& v = *selection.get_first_volume(); - m_orient_matrix = v.get_instance_transformation().get_rotation_matrix() * v.get_volume_transformation().get_rotation_matrix(); - } - else { - const GLVolume& v = *selection.get_first_volume(); - m_orient_matrix = v.get_instance_transformation().get_rotation_matrix(); - } } #endif // ENABLE_WORLD_COORDINATE @@ -531,7 +498,7 @@ Transform3d GLGizmoRotate::local_transform(const Selection& selection) const } #if ENABLE_WORLD_COORDINATE - return Geometry::translation_transform(m_center) * m_orient_matrix * ret; + return m_orient_matrix * ret; #else if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) ret = selection.get_first_volume()->get_instance_transformation().get_matrix(true, false, true, true) * ret; @@ -546,7 +513,7 @@ Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray) cons Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, const Selection& selection) const #endif // ENABLE_WORLD_COORDINATE { - double half_pi = 0.5 * double(PI); + const double half_pi = 0.5 * double(PI); Transform3d m = Transform3d::Identity(); @@ -573,7 +540,7 @@ Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, cons } #if ENABLE_WORLD_COORDINATE - m = m * m_orient_matrix.inverse(); + m = m * Geometry::Transformation(m_orient_matrix).get_matrix_no_offset().inverse(); #else if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) m = m * selection.get_first_volume()->get_instance_transformation().get_matrix(true, false, true, true).inverse(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index fa52e3a787..ebfed19205 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -56,7 +56,7 @@ private: float m_old_angle{ 0.0f }; // emboss need to draw rotation gizmo in local coordinate systems - bool m_using_local_coordinate{false}; + bool m_force_local_coordinate{ false }; ColorRGBA m_drag_color; ColorRGBA m_highlight_color; @@ -71,7 +71,7 @@ public: std::string get_tooltip() const override; void set_group_id(int group_id) { m_group_id = group_id; } - void set_using_local_coordinate(bool use) { m_using_local_coordinate =use;} + void set_force_local_coordinate(bool use) { m_force_local_coordinate = use; } void start_dragging(); void stop_dragging(); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index dd8364c029..461a009794 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -817,113 +817,117 @@ const std::pair& Selection::get_bounding_box_in_curr if (!m_bounding_box_in_current_reference_system.has_value()) { last_coordinates_type = int(coordinates_type); - - BoundingBoxf3 original_box; - Transform3d trafo; - - // - // calculate box aligned to current reference system - // - switch (coordinates_type) - { - case ECoordinatesType::World: - { - original_box = get_bounding_box(); - trafo = Transform3d::Identity(); - break; - } - case ECoordinatesType::Instance: { - for (unsigned int id : m_list) { - const GLVolume& v = *get_volume(id); - original_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix())); - } - trafo = get_first_volume()->get_instance_transformation().get_matrix(); - break; - } - case ECoordinatesType::Local: { - assert(is_single_volume_or_modifier()); - const GLVolume& v = *get_first_volume(); - original_box = v.bounding_box(); - trafo = v.world_matrix(); - break; - } - } - - // - // calculate box size in world coordinates - // - auto point_to_Vec4d = [](const Vec3d& p) { return Vec4d(p.x(), p.y(), p.z(), 1.0); }; - auto Vec4d_to_Vec3d = [](const Vec4d& v) { return Vec3d(v.x(), v.y(), v.z()); }; - - auto apply_transform = [](const std::vector& original, const Transform3d& trafo, bool normalize) { - std::vector transformed(original.size()); - for (size_t i = 0; i < original.size(); ++i) { - transformed[i] = trafo * original[i]; - if (normalize) - transformed[i].normalize(); - } - return transformed; - }; - - auto calc_box_size = [point_to_Vec4d, Vec4d_to_Vec3d, apply_transform](const BoundingBoxf3& box, const Transform3d& trafo) { - Geometry::Transformation transformation(trafo); - - // box aligned to current reference system - std::vector homo_vertices = { - point_to_Vec4d({ box.min.x(), box.min.y(), box.min.z() }), - point_to_Vec4d({ box.max.x(), box.min.y(), box.min.z() }), - point_to_Vec4d({ box.max.x(), box.max.y(), box.min.z() }), - point_to_Vec4d({ box.min.x(), box.max.y(), box.min.z() }), - point_to_Vec4d({ box.min.x(), box.min.y(), box.max.z() }), - point_to_Vec4d({ box.max.x(), box.min.y(), box.max.z() }), - point_to_Vec4d({ box.max.x(), box.max.y(), box.max.z() }), - point_to_Vec4d({ box.min.x(), box.max.y(), box.max.z() }) - }; - - // box vertices in world coordinates - std::vector transformed_homo_vertices = apply_transform(homo_vertices, trafo, false); - - // project back to current reference system - const std::vector homo_axes = { Vec4d::UnitX(), Vec4d::UnitY(), Vec4d::UnitZ() }; - std::vector transformed_homo_axes = apply_transform(homo_axes, Geometry::Transformation(trafo).get_matrix_no_scaling_factor(), true); - std::vector transformed_axes(transformed_homo_axes.size()); - for (size_t i = 0; i < transformed_homo_axes.size(); ++i) { - transformed_axes[i] = Vec4d_to_Vec3d(transformed_homo_axes[i]); - } - - Vec3d min = { DBL_MAX, DBL_MAX, DBL_MAX }; - Vec3d max = { -DBL_MAX, -DBL_MAX, -DBL_MAX }; - - for (const Vec4d& v_homo : transformed_homo_vertices) { - const Vec3d v = Vec4d_to_Vec3d(v_homo); - for (int i = 0; i < 3; ++i) { - const double dot_i = v.dot(transformed_axes[i]); - min(i) = std::min(min(i), dot_i); - max(i) = std::max(max(i), dot_i); - } - } - - // return size - const Vec3d size = max - min; - return size; - }; - - const Vec3d box_size = calc_box_size(original_box, trafo); - const std::vector box_center = { point_to_Vec4d(original_box.center()) }; - std::vector transformed_box_center = apply_transform(box_center, trafo, false); - - // - // return box centered at 0, 0, 0 - // - const Vec3d half_box_size = 0.5 * box_size; - BoundingBoxf3 out_box(-half_box_size, half_box_size); - Geometry::Transformation out_trafo(trafo); - out_trafo.set_offset(Vec4d_to_Vec3d(transformed_box_center[0])); - *const_cast>*>(&m_bounding_box_in_current_reference_system) = { out_box, out_trafo.get_matrix_no_scaling_factor() }; + *const_cast>*>(&m_bounding_box_in_current_reference_system) = get_bounding_box_in_reference_system(coordinates_type); } return *m_bounding_box_in_current_reference_system; } + +std::pair Selection::get_bounding_box_in_reference_system(ECoordinatesType type) const +{ + BoundingBoxf3 original_box; + Transform3d trafo; + + // + // calculate box aligned to current reference system + // + switch (type) + { + case ECoordinatesType::World: + { + original_box = get_bounding_box(); + trafo = Transform3d::Identity(); + break; + } + case ECoordinatesType::Instance: { + for (unsigned int id : m_list) { + const GLVolume& v = *get_volume(id); + original_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix())); + } + trafo = get_first_volume()->get_instance_transformation().get_matrix(); + break; + } + case ECoordinatesType::Local: { + assert(is_single_volume_or_modifier()); + const GLVolume& v = *get_first_volume(); + original_box = v.bounding_box(); + trafo = v.world_matrix(); + break; + } + } + + // + // calculate box size in world coordinates + // + auto point_to_Vec4d = [](const Vec3d& p) { return Vec4d(p.x(), p.y(), p.z(), 1.0); }; + auto Vec4d_to_Vec3d = [](const Vec4d& v) { return Vec3d(v.x(), v.y(), v.z()); }; + + auto apply_transform = [](const std::vector& original, const Transform3d& trafo, bool normalize) { + std::vector transformed(original.size()); + for (size_t i = 0; i < original.size(); ++i) { + transformed[i] = trafo * original[i]; + if (normalize) + transformed[i].normalize(); + } + return transformed; + }; + + auto calc_box_size = [point_to_Vec4d, Vec4d_to_Vec3d, apply_transform](const BoundingBoxf3& box, const Transform3d& trafo) { + Geometry::Transformation transformation(trafo); + + // box aligned to current reference system + std::vector homo_vertices = { + point_to_Vec4d({ box.min.x(), box.min.y(), box.min.z() }), + point_to_Vec4d({ box.max.x(), box.min.y(), box.min.z() }), + point_to_Vec4d({ box.max.x(), box.max.y(), box.min.z() }), + point_to_Vec4d({ box.min.x(), box.max.y(), box.min.z() }), + point_to_Vec4d({ box.min.x(), box.min.y(), box.max.z() }), + point_to_Vec4d({ box.max.x(), box.min.y(), box.max.z() }), + point_to_Vec4d({ box.max.x(), box.max.y(), box.max.z() }), + point_to_Vec4d({ box.min.x(), box.max.y(), box.max.z() }) + }; + + // box vertices in world coordinates + std::vector transformed_homo_vertices = apply_transform(homo_vertices, trafo, false); + + // project back to current reference system + const std::vector homo_axes = { Vec4d::UnitX(), Vec4d::UnitY(), Vec4d::UnitZ() }; + std::vector transformed_homo_axes = apply_transform(homo_axes, Geometry::Transformation(trafo).get_matrix_no_scaling_factor(), true); + std::vector transformed_axes(transformed_homo_axes.size()); + for (size_t i = 0; i < transformed_homo_axes.size(); ++i) { + transformed_axes[i] = Vec4d_to_Vec3d(transformed_homo_axes[i]); + } + + Vec3d min = { DBL_MAX, DBL_MAX, DBL_MAX }; + Vec3d max = { -DBL_MAX, -DBL_MAX, -DBL_MAX }; + + for (const Vec4d& v_homo : transformed_homo_vertices) { + const Vec3d v = Vec4d_to_Vec3d(v_homo); + for (int i = 0; i < 3; ++i) { + const double dot_i = v.dot(transformed_axes[i]); + min(i) = std::min(min(i), dot_i); + max(i) = std::max(max(i), dot_i); + } + } + + // return size + const Vec3d size = max - min; + return size; + }; + + const Vec3d box_size = calc_box_size(original_box, trafo); + const std::vector box_center = { point_to_Vec4d(original_box.center()) }; + std::vector transformed_box_center = apply_transform(box_center, trafo, false); + + // + // return box centered at 0, 0, 0 + // + const Vec3d half_box_size = 0.5 * box_size; + BoundingBoxf3 out_box(-half_box_size, half_box_size); + Geometry::Transformation out_trafo(trafo); + out_trafo.set_offset(Vec4d_to_Vec3d(transformed_box_center[0])); + return { out_box, out_trafo.get_matrix_no_scaling_factor() }; +} #endif // ENABLE_WORLD_COORDINATE void Selection::setup_cache() diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 67b28ac785..36f973839d 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -391,9 +391,12 @@ public: // Bounding box of a single full instance selection, in local coordinates, with no instance scaling applied. // Modifiers are taken in account const BoundingBoxf3& get_full_unscaled_instance_local_bounding_box() const; - // Returns the bounding box aligned to the axis of the currently selected reference system (World/Object/Part) + // Returns the bounding box aligned to the axes of the currently selected reference system (World/Object/Part) // and the transform to place and orient it in world coordinates const std::pair& get_bounding_box_in_current_reference_system() const; + // Returns the bounding box aligned to the axes of the given reference system + // and the transform to place and orient it in world coordinates + std::pair get_bounding_box_in_reference_system(ECoordinatesType type) const; #endif // ENABLE_WORLD_COORDINATE void setup_cache(); From f2e998de9b2b31c4deeda400cc4bcddd24b0c310 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 9 Jan 2023 12:47:53 +0100 Subject: [PATCH 09/17] Follow-up of 2c02db35140612c377ee847b802428dbb0c908f7 - Fixed assert --- src/slic3r/GUI/Selection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 461a009794..6242fcb5cb 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -848,7 +848,7 @@ std::pair Selection::get_bounding_box_in_reference_s break; } case ECoordinatesType::Local: { - assert(is_single_volume_or_modifier()); + assert(is_single_volume_or_modifier() || is_single_volume_instance()); const GLVolume& v = *get_first_volume(); original_box = v.bounding_box(); trafo = v.world_matrix(); From 6b16eb506820708770c3e8e296397522c56136e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Mon, 9 Jan 2023 11:45:08 +0100 Subject: [PATCH 10/17] Added a test case for missing infill that is probably caused by PolylineStitcher, which produced an open polyline. --- tests/libslic3r/test_arachne.cpp | 37 ++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/libslic3r/test_arachne.cpp b/tests/libslic3r/test_arachne.cpp index e952695e98..2334fbc62a 100644 --- a/tests/libslic3r/test_arachne.cpp +++ b/tests/libslic3r/test_arachne.cpp @@ -414,3 +414,40 @@ TEST_CASE("Arachne - #8597 - removeSmallAreas", "[ArachneRemoveSmallAreas8597]") REQUIRE(perimeters.size() == 1); } + +// Test case for missing infill that is probably caused by PolylineStitcher, which produced an open polyline. +TEST_CASE("Arachne - Missing infill", "[ArachneMissingInfill]") { + const Polygon poly_0 = { + Point( 5525881, 3649657), + Point( 452351, -2035297), + Point(-1014702, -2144286), + Point(-5142096, -9101108), + Point( 5525882, -9101108), + }; + + const Polygon poly_1 = { + Point(1415524, -2217520), + Point(1854189, -2113857), + Point(1566974, -2408538), + }; + + const Polygon poly_2 = { + Point(-42854, -3771357), + Point(310500, -3783332), + Point( 77735, -4059215), + }; + + Polygons polygons = {poly_0, poly_1, poly_2}; + coord_t spacing = 357079; + coord_t inset_count = 2; + + Arachne::WallToolPaths wallToolPaths(polygons, spacing, spacing, inset_count, 0, 0.2, PrintObjectConfig::defaults(), PrintConfig::defaults()); + wallToolPaths.generate(); + std::vector perimeters = wallToolPaths.getToolPaths(); + +#ifdef ARACHNE_DEBUG_OUT + export_perimeters_to_svg(debug_out_path("arachne-missing-infill.svg"), polygons, perimeters, union_ex(wallToolPaths.getInnerContour())); +#endif + +// REQUIRE(wallToolPaths.getInnerContour().size() == 1); +} From d97d174b6a11ad3a498f75af35c34c6c7d3dd326 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 9 Jan 2023 13:00:09 +0100 Subject: [PATCH 11/17] Fix for #9365 - Send System Info pop-up --- src/slic3r/GUI/SendSystemInfoDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/SendSystemInfoDialog.cpp b/src/slic3r/GUI/SendSystemInfoDialog.cpp index dfb442d18c..ffa1474789 100644 --- a/src/slic3r/GUI/SendSystemInfoDialog.cpp +++ b/src/slic3r/GUI/SendSystemInfoDialog.cpp @@ -658,7 +658,7 @@ SendSystemInfoDialog::SendSystemInfoDialog(wxWindow* parent) wxString message; bool success = send_info(message); if (! message.IsEmpty()) - InfoDialog(nullptr, wxEmptyString, message).ShowModal(); + InfoDialog(this, wxEmptyString, message).ShowModal(); if (success) { save_version(); EndModal(0); From ba730922e6fac124ff37e25d2896364fb0a6e5bd Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 9 Jan 2023 13:04:46 +0100 Subject: [PATCH 12/17] TabPrinter: Change field height for Start/Stop G-codes --- src/slic3r/GUI/Tab.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index cf3b96d803..796ce622ba 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2373,7 +2373,7 @@ void TabPrinter::build_fff() option = optgroup->get_option("start_gcode"); option.opt.full_width = true; option.opt.is_code = true; - option.opt.height = gcode_field_height;//150; + option.opt.height = 3 * gcode_field_height;//150; optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("End G-code"), 0); @@ -2383,7 +2383,7 @@ void TabPrinter::build_fff() option = optgroup->get_option("end_gcode"); option.opt.full_width = true; option.opt.is_code = true; - option.opt.height = gcode_field_height;//150; + option.opt.height = 1.75 * gcode_field_height;//150; optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("Before layer change G-code"), 0); From abf918e7281d912f7d432b8fb460f8599b2db604 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 9 Jan 2023 13:18:24 +0100 Subject: [PATCH 13/17] Fixed selection type for text volumes --- src/slic3r/GUI/Selection.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 6242fcb5cb..9fb232c7e4 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -2159,8 +2159,7 @@ void Selection::update_type() if (!m_valid) m_type = Invalid; - else - { + else { if (m_list.empty()) m_type = Empty; else if (m_list.size() == 1) { @@ -2176,12 +2175,19 @@ void Selection::update_type() unsigned int volumes_count = (unsigned int)model_object->volumes.size(); unsigned int instances_count = (unsigned int)model_object->instances.size(); if (volumes_count * instances_count == 1) { - m_type = SingleFullObject; - // ensures the correct mode is selected - m_mode = Instance; + const ModelVolume* model_volume = model_object->volumes[first->volume_idx()]; + if (model_volume->text_configuration.has_value()) { // text volume + m_type = SingleVolume; + // ensures the correct mode is selected + m_mode = Volume; + } + else { + m_type = SingleFullObject; + // ensures the correct mode is selected + m_mode = Instance; + } } - else if (volumes_count == 1) // instances_count > 1 - { + else if (volumes_count == 1) { // instances_count > 1 m_type = SingleFullInstance; // ensures the correct mode is selected m_mode = Instance; From 4a223396217b9bd8905841d28a0b688b87fd92e0 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 9 Jan 2023 14:13:35 +0100 Subject: [PATCH 14/17] Tech ENABLE_WORLD_COORDINATE - Fixed enable/disabled state of mirror context menu item and sidebar mirror buttons --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 10 ++++++++-- src/slic3r/GUI/Plater.cpp | 5 +++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index e502b25d7e..41f4cf0604 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -1040,7 +1040,13 @@ void ObjectManipulation::update_mirror_buttons_visibility() #endif // !ENABLE_WORLD_COORDINATE } } -#if !ENABLE_WORLD_COORDINATE + +#if ENABLE_WORLD_COORDINATE + const bool can_mirror = wxGetApp().plater()->can_mirror(); + for (ScalableButton* button : m_mirror_buttons) { + button->Enable(can_mirror); + } +#else else { // the mirroring buttons should be hidden in world coordinates, // unless we make it actually mirror in world coords. @@ -1062,7 +1068,7 @@ void ObjectManipulation::update_mirror_buttons_visibility() } } }); -#endif // !ENABLE_WORLD_COORDINATE +#endif // ENABLE_WORLD_COORDINATE } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index ed280697ac..b55f6299a3 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4837,9 +4837,14 @@ bool Plater::priv::layers_height_allowed() const bool Plater::priv::can_mirror() const { +#if ENABLE_WORLD_COORDINATE + return !sidebar->obj_list()->has_selected_cut_object(); +#else return !sidebar->obj_list()->has_selected_cut_object() && get_selection().is_from_single_instance(); +#endif // ENABLE_WORLD_COORDINATE } + bool Plater::priv::can_replace_with_stl() const { return !sidebar->obj_list()->has_selected_cut_object() && get_selection().get_volume_idxs().size() == 1; From cafdbb47efa2eeefa14ca2b6045173e392f94a80 Mon Sep 17 00:00:00 2001 From: denis-itskovich Date: Tue, 22 Nov 2022 11:40:11 +0200 Subject: [PATCH 15/17] Enabling 3DConnexion polling thread in windows, when working in remote session, Adding ability to force hw rendering in remote session --- src/PrusaSlicer_app_msvc.cpp | 5 +++-- src/slic3r/GUI/Mouse3DController.cpp | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/PrusaSlicer_app_msvc.cpp b/src/PrusaSlicer_app_msvc.cpp index 83f24c3075..90bd2d89f2 100644 --- a/src/PrusaSlicer_app_msvc.cpp +++ b/src/PrusaSlicer_app_msvc.cpp @@ -242,13 +242,14 @@ int wmain(int argc, wchar_t **argv) #ifdef SLIC3R_GUI // Here one may push some additional parameters based on the wrapper type. bool force_mesa = false; + bool force_hw = false; #endif /* SLIC3R_GUI */ for (int i = 1; i < argc; ++ i) { #ifdef SLIC3R_GUI if (wcscmp(argv[i], L"--sw-renderer") == 0) force_mesa = true; else if (wcscmp(argv[i], L"--no-sw-renderer") == 0) - force_mesa = false; + force_hw = true; #endif /* SLIC3R_GUI */ argv_extended.emplace_back(argv[i]); } @@ -261,7 +262,7 @@ int wmain(int argc, wchar_t **argv) force_mesa || // Running over a rempote desktop, and the RemoteFX is not enabled, therefore Windows will only provide SW OpenGL 1.1 context. // In that case, use Mesa. - ::GetSystemMetrics(SM_REMOTESESSION) || + (::GetSystemMetrics(SM_REMOTESESSION) && !force_hw) || // Try to load the default OpenGL driver and test its context version. ! opengl_version_check.load_opengl_dll() || ! opengl_version_check.is_version_greater_or_equal_to(2, 0); #endif /* SLIC3R_GUI */ diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index e5ad5d64f4..1ce6717539 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -668,6 +668,11 @@ void Mouse3DController::init() #ifndef _WIN32 // Don't start the background thread on Windows, as the HID messages are sent as Windows messages. m_thread = std::thread(&Mouse3DController::run, this); +#else + // For some reason, HID message routing does not work well with remote session. Requires further investigation + if (::GetSystemMetrics(SM_REMOTESESSION)) { + m_thread = std::thread(&Mouse3DController::run, this); + } #endif // _WIN32 } } From e4ee0d927d113df6a33963c11159b10f738f2cc6 Mon Sep 17 00:00:00 2001 From: rtyr <36745189+rtyr@users.noreply.github.com> Date: Mon, 9 Jan 2023 15:38:05 +0100 Subject: [PATCH 16/17] Sermoon V1 PRO thumbnail --- .../Creality/SERMOONV1PRO_thumbnail.png | Bin 0 -> 24742 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 resources/profiles/Creality/SERMOONV1PRO_thumbnail.png diff --git a/resources/profiles/Creality/SERMOONV1PRO_thumbnail.png b/resources/profiles/Creality/SERMOONV1PRO_thumbnail.png new file mode 100644 index 0000000000000000000000000000000000000000..adbd421621ec1ab5391e8b22f2e1af405a36a7b4 GIT binary patch literal 24742 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 literal 0 HcmV?d00001 From bb8a0019639dcaf8b4056fd4e4808c47a08d880b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 10 Jan 2023 08:25:05 +0100 Subject: [PATCH 17/17] Replace abf918e7281d912f7d432b8fb460f8599b2db604 with a better fix --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 3 ++- src/slic3r/GUI/Selection.cpp | 13 +++---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 5651ac190c..87c72b6462 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -300,7 +300,8 @@ bool GLGizmoEmboss::on_mouse_for_rotation(const wxMouseEvent &mouse_event) angle -= PI / 2; // Grabber is upward // temporary rotation - TransformationType transformation_type = TransformationType::Local_Relative_Joint; + const TransformationType transformation_type = m_parent.get_selection().is_single_text() ? + TransformationType::Local_Relative_Joint : TransformationType::World_Relative_Joint; m_parent.get_selection().rotate(Vec3d(0., 0., angle), transformation_type); angle += *m_rotate_start_angle; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 9fb232c7e4..fda11421fd 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -2176,16 +2176,9 @@ void Selection::update_type() unsigned int instances_count = (unsigned int)model_object->instances.size(); if (volumes_count * instances_count == 1) { const ModelVolume* model_volume = model_object->volumes[first->volume_idx()]; - if (model_volume->text_configuration.has_value()) { // text volume - m_type = SingleVolume; - // ensures the correct mode is selected - m_mode = Volume; - } - else { - m_type = SingleFullObject; - // ensures the correct mode is selected - m_mode = Instance; - } + m_type = SingleFullObject; + // ensures the correct mode is selected + m_mode = Instance; } else if (volumes_count == 1) { // instances_count > 1 m_type = SingleFullInstance;