diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index c85ff2db60..c838b898f6 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -2400,7 +2400,7 @@ void MenuFactory::append_menu_item_drop(wxMenu* menu) if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D) return false; else { - return (std::abs(plater()->get_view3D_canvas3D()->get_selection().get_bounding_box().min.z()) > -SINKING_Z_THRESHOLD); + return plater()->get_view3D_canvas3D()->get_selection().can_drop(); } //disable if model is on the bed / not in View3D }, m_parent); } diff --git a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp index 406c7e258c..5c009dd8c5 100644 --- a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp +++ b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp @@ -57,24 +57,6 @@ const double GizmoObjectManipulation::mm_to_in = 0.0393700787; const double GizmoObjectManipulation::oz_to_g = 28.34952; const double GizmoObjectManipulation::g_to_oz = 0.035274; -// Helper function to be used by drop to bed button. Returns lowest point of this -// volume in world coordinate system. -static double get_volume_min_z(const GLVolume* volume) -{ - const Transform3f& world_matrix = volume->world_matrix().cast(); - - // need to get the ModelVolume pointer - const ModelObject* mo = wxGetApp().model().objects[volume->composite_id.object_id]; - const ModelVolume* mv = mo->volumes[volume->composite_id.volume_id]; - const TriangleMesh& hull = mv->get_convex_hull(); - - float min_z = std::numeric_limits::max(); - for (const stl_vertex& vert : hull.its.vertices) { - min_z = std::min(min_z, Vec3f::UnitZ().dot(world_matrix * vert)); - } - return min_z; -} - GizmoObjectManipulation::GizmoObjectManipulation(GLCanvas3D& glcanvas) : m_glcanvas(glcanvas), m_alignment_helper(glcanvas) { @@ -295,12 +277,14 @@ void GizmoObjectManipulation::update_reset_buttons_visibility() { const Selection& selection = m_glcanvas.get_selection(); + // Assembly view has its own selection and transformations, which drop_selection() doesn't update + m_enable_drop_to_bed = m_glcanvas.get_canvas_type() == GLCanvas3D::ECanvasType::CanvasView3D && selection.can_drop(); + if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) { const GLVolume * volume = selection.get_first_volume(); Vec3d rotation; Vec3d scale; - double min_z = 0.; if (selection.is_single_full_instance()) { rotation = volume->get_instance_rotation(); @@ -309,12 +293,10 @@ void GizmoObjectManipulation::update_reset_buttons_visibility() else { rotation = volume->get_volume_rotation(); scale = volume->get_volume_scaling_factor(); - min_z = get_volume_min_z(volume); } m_show_clear_rotation = !rotation.isApprox(m_init_rotation); m_show_reset_0_rotation = !rotation.isApprox(Vec3d::Zero()); m_show_clear_scale = (m_cache.scale / 100.0f - Vec3d::Ones()).norm() > 0.001; - m_show_drop_to_bed = (std::abs(min_z) > EPSILON); } } @@ -1072,6 +1054,17 @@ void GizmoObjectManipulation::do_render_move_window(ImGuiWrapper *imgui_wrapper, GLGizmoUtils::render_tooltip_button(imgui_wrapper, m_glcanvas, m_shortcuts_move, x, y); + // ORCA use existing function for drop and show button on bottom bar to keep gizmo compact + imgui_wrapper->disabled_begin(!m_enable_drop_to_bed); + ImGui::SameLine(0, space_size * 1.5f); + if (imgui_wrapper->button(_L("Drop"))){ + wxGetApp().plater()->drop_selection(); + UpdateAndShow(true); + } + imgui_wrapper->disabled_end(); + if(ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) + imgui_wrapper->tooltip(_L("Move the selection along Z so that its lowest point touches the bed."), ImGui::GetFontSize() * 20.0f); + ImGui::SameLine(); GLGizmoUtils::begin_right_aligned_buttons({ _L("Done") }); if (imgui_wrapper->button(_L("Done"))) { diff --git a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp index 400f7b7405..7452884146 100644 --- a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp +++ b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp @@ -103,7 +103,7 @@ public: bool m_show_reset_0_rotation{false}; bool m_show_clear_rotation { false }; bool m_show_clear_scale { false }; - bool m_show_drop_to_bed { false }; + bool m_enable_drop_to_bed { false }; enum class RotateType { None, Relative, Absolute }; RotateType m_last_rotate_type{RotateType::None}; // 0:no input 1:relative 2:absolute diff --git a/src/slic3r/GUI/NativeCommands.cpp b/src/slic3r/GUI/NativeCommands.cpp index 4da288d1ea..6f9918dee2 100644 --- a/src/slic3r/GUI/NativeCommands.cpp +++ b/src/slic3r/GUI/NativeCommands.cpp @@ -365,7 +365,7 @@ std::vector build_command_catalog() return object_op(wxGetApp().plater(), [](Plater* p) { return !p->is_selection_empty(); }, [](Plater* p) { p->center_selection(); }); }); add_with_icon("obj_drop", L("Drop to Bed"), L("Object"), "toolbar_flatten", [](const std::string&) { - return object_op(wxGetApp().plater(), [](Plater* p) { return !p->is_selection_empty(); }, [](Plater* p) { p->drop_selection(); }); + return object_op(wxGetApp().plater(), [](Plater* p) { return p->get_selection().can_drop(); }, [](Plater* p) { p->drop_selection(); }); }); add("obj_fit_volume", L("Scale to Fit Print Volume"), L("Object"), [](const std::string&) { return object_op( diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 8978f165b9..58d5e15fe3 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -558,15 +558,37 @@ void Selection::center() return; } +double Selection::get_drop_min_z() const +{ + if (!m_valid) + return 0.; + if (m_mode == Volume) + return get_bounding_box().min.z(); + + double min_z = DBL_MAX; + for (const auto& [obj_idx, inst_idxs] : m_cache.content) { + if (obj_idx >= (int)m_model->objects.size()) + continue; // wipe tower + for (int inst_idx : inst_idxs) + min_z = std::min(min_z, m_model->objects[obj_idx]->get_instance_min_z(inst_idx)); + } + return min_z == DBL_MAX ? 0. : min_z; +} + +bool Selection::can_drop() const +{ + return std::abs(get_drop_min_z()) > -SINKING_Z_THRESHOLD; +} + void Selection::drop() { - if (std::abs(this->get_bounding_box().min.z()) < -SINKING_Z_THRESHOLD) { - return; // shouldnt happen, but better check anyways, already checked in append_menu_item_drop() - } + const double min_z = get_drop_min_z(); + if (std::abs(min_z) < -SINKING_Z_THRESHOLD) + return; // already checked in can_drop() wxGetApp().plater()->take_snapshot(L("Move object")); - this->move_to_center(Vec3d(0, 0, -this->get_bounding_box().min.z())); + this->move_to_center(Vec3d(0, 0, -min_z)); for (unsigned int i : m_list) { GLVolume& volume = *(*m_volumes)[i]; diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index c777c3c291..dcee38a813 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -248,6 +248,9 @@ public: void clone(int numbers = 1); void center(); void drop(); + bool can_drop() const; + // Lowest world Z that drop() moves to the bed; whole objects count model parts only, as auto drop does. + double get_drop_min_z() const; void center_plate(const int plate_idx); void set_printable(bool printable); bool get_auto_drop() const;