From 76784441be56794478948c23f02e5ee174d01d34 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 9 Feb 2022 16:11:53 +0100 Subject: [PATCH] Cut: next UI improvements --- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 522 +++++++++++++++++----- src/slic3r/GUI/Gizmos/GLGizmoCut.hpp | 195 +++++--- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 9 + src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp | 3 + src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 +- 5 files changed, 559 insertions(+), 172 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 3d5d1cd481..3688b10f96 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -28,20 +28,6 @@ static const ColorRGBA GRABBER_COLOR = ColorRGBA::ORANGE(); GLGizmoCut::GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) { - m_modes = { _u8L("Planar"), _u8L("Grid") -// , _u8L("Radial"), _u8L("Modular") - }; - - m_connector_types = { _u8L("Plug"), _u8L("Dowel") }; - - m_connector_styles = { _u8L("Prizm"), _u8L("Frustrum") -// , _u8L("Claw") - }; - - m_connector_shapes = { _u8L("Triangle"), _u8L("Square"), _u8L("Circle"), _u8L("Hexagon") -// , _u8L("D-shape") - }; - } std::string GLGizmoCut::get_tooltip() const @@ -56,7 +42,7 @@ std::string GLGizmoCut::get_tooltip() const bool GLGizmoCut::on_init() { m_grabbers.emplace_back(); - m_shortcut_key = WXK_CONTROL_C; +// m_shortcut_key = WXK_CONTROL_C; return true; } @@ -68,7 +54,7 @@ std::string GLGizmoCut::on_get_name() const void GLGizmoCut::on_set_state() { // Reset m_cut_z on gizmo activation - if (get_state() == On) + if (get_state() == On && m_cut_z == 0.0) m_cut_z = bounding_box().center().z(); } @@ -107,14 +93,20 @@ void GLGizmoCut::on_render() update_contours(); - const float min_x = box.min.x() - Margin; - const float max_x = box.max.x() + Margin; - const float min_y = box.min.y() - Margin; - const float max_y = box.max.y() + Margin; - glsafe(::glEnable(GL_DEPTH_TEST)); - glsafe(::glDisable(GL_CULL_FACE)); - glsafe(::glEnable(GL_BLEND)); - glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + //const float min_x = box.min.x() - Margin - plane_center.x(); + //const float max_x = box.max.x() + Margin - plane_center.x(); + //const float min_y = box.min.y() - Margin - plane_center.y(); + //const float max_y = box.max.y() + Margin - plane_center.y(); +// glsafe(::glEnable(GL_DEPTH_TEST)); +// glsafe(::glDisable(GL_CULL_FACE)); +// glsafe(::glEnable(GL_BLEND)); +// glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); +// +//#if ENABLE_GLBEGIN_GLEND_REMOVAL +//#endif // ENABLE_GLBEGIN_GLEND_REMOVAL +// +// glsafe(::glEnable(GL_CULL_FACE)); +// glsafe(::glDisable(GL_BLEND)); #if ENABLE_GLBEGIN_GLEND_REMOVAL GLShaderProgram* shader = wxGetApp().get_shader("flat"); @@ -229,13 +221,80 @@ void GLGizmoCut::on_render() #endif // ENABLE_GLBEGIN_GLEND_REMOVAL } + glsafe(::glPushMatrix()); + glsafe(::glTranslated(m_cut_contours.shift.x(), m_cut_contours.shift.y(), m_cut_contours.shift.z())); +// glsafe(::glTranslated(plane_center.x(), plane_center.y(), plane_center.z())); + glsafe(::glRotated(Geometry::rad2deg(m_angles.z()), 0.0, 0.0, 1.0)); + glsafe(::glRotated(Geometry::rad2deg(m_angles.y()), 0.0, 1.0, 0.0)); + glsafe(::glRotated(Geometry::rad2deg(m_angles.x()), 1.0, 0.0, 0.0)); + + glsafe(::glLineWidth(2.0f)); + m_cut_contours.contours.render(); + glsafe(::glPopMatrix()); +} + void GLGizmoCut::on_render_for_picking() { glsafe(::glDisable(GL_DEPTH_TEST)); render_grabbers_for_picking(m_parent.get_selection().get_bounding_box()); } -void GLGizmoCut::render_combo(const std::string& label, const std::vector& lines, size_t& selection_idx) +void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit) +{ + static float last_y = 0.0f; + static float last_h = 0.0f; + + m_imgui->begin(_L("Cut"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + + const bool imperial_units = wxGetApp().app_config->get("use_inches") == "1"; + + // adjust window position to avoid overlap the view toolbar + const float win_h = ImGui::GetWindowHeight(); + y = std::min(y, bottom_limit - win_h); + ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always); + if (last_h != win_h || last_y != y) { + // ask canvas for another frame to render the window in the correct position + m_imgui->set_requires_extra_frame(); + if (last_h != win_h) + last_h = win_h; + if (last_y != y) + last_y = y; + } + + ImGui::AlignTextToFramePadding(); + m_imgui->text("Z"); + ImGui::SameLine(); + ImGui::PushItemWidth(m_imgui->get_style_scaling() * 150.0f); + + double cut_z = m_cut_z; + if (imperial_units) + cut_z *= ObjectManipulation::mm_to_in; + ImGui::InputDouble("", &cut_z, 0.0f, 0.0f, "%.2f", ImGuiInputTextFlags_CharsDecimal); + + ImGui::SameLine(); + m_imgui->text(imperial_units ? _L("in") : _L("mm")); + + m_cut_z = cut_z * (imperial_units ? ObjectManipulation::in_to_mm : 1.0); + + ImGui::Separator(); + + m_imgui->checkbox(_L("Keep upper part"), m_keep_upper); + m_imgui->checkbox(_L("Keep lower part"), m_keep_lower); + m_imgui->checkbox(_L("Rotate lower part upwards"), m_rotate_lower); + + ImGui::Separator(); + + m_imgui->disabled_begin((!m_keep_upper && !m_keep_lower) || m_cut_z <= 0.0 || m_max_z <= m_cut_z); + const bool cut_clicked = m_imgui->button(_L("Perform cut")); + m_imgui->disabled_end(); + + m_imgui->end(); + + if (cut_clicked && (m_keep_upper || m_keep_lower)) + perform_cut(m_parent.get_selection()); +} + +void GLGizmoCut3D::render_combo(const std::string& label, const std::vector& lines, size_t& selection_idx) { ImGui::AlignTextToFramePadding(); m_imgui->text(label); @@ -273,7 +332,7 @@ void GLGizmoCut::render_combo(const std::string& label, const std::vectortext(label); @@ -291,22 +350,46 @@ void GLGizmoCut::render_double_input(const std::string& label, double& value_in) value_in = value * (m_imperial_units ? ObjectManipulation::in_to_mm : 1.0); } -void GLGizmoCut::render_rotation_input(const std::string& label, double& value_in) +void GLGizmoCut3D::render_move_center_input(int axis) { - m_imgui->text(label); + ImGui::AlignTextToFramePadding(); + m_imgui->text(m_axis_names[axis]+":"); + ImGui::SameLine(); + ImGui::PushItemWidth(0.3*m_control_width); + + double value = axis == Z ? m_cut_plane_gizmo.get_cut_z() : 0.0; + if (m_imperial_units) + value *= ObjectManipulation::mm_to_in; + ImGui::InputDouble(("##move_" + m_axis_names[axis]).c_str(), &value, 0.0f, 0.0f, "%.2f", ImGuiInputTextFlags_CharsDecimal); ImGui::SameLine(); - double value = value_in; + if (axis == Z) { + double val = value * (m_imperial_units ? ObjectManipulation::in_to_mm : 1.0); + m_cut_plane_gizmo.set_cut_z(val); + set_center_z(val); + } +} + +void GLGizmoCut3D::render_rotation_input(int axis) +{ + m_imgui->text(m_axis_names[axis] + ":"); + ImGui::SameLine(); + + Vec3d rotation = get_rotation(); + double value = rotation[axis]; if (value > 360) value -= 360; ImGui::PushItemWidth(0.3*m_control_width); - ImGui::InputDouble(("##" + label).c_str(), &value, 0.0f, 0.0f, "%.2f", ImGuiInputTextFlags_CharsDecimal); + ImGui::InputDouble(("##rotate_" + m_axis_names[axis]).c_str(), &value, 0.0f, 0.0f, "%.2f", ImGuiInputTextFlags_CharsDecimal); + ImGui::SameLine(); - value_in = value; + rotation[axis] = value; + set_rotation(rotation); + m_cut_plane_gizmo.set_angles(rotation); } -void GLGizmoCut::render_radio_button(ConnectorType type) +void GLGizmoCut3D::render_connect_type_radio_button(ConnectorType type) { ImGui::SameLine(type == ConnectorType::Plug ? m_label_width : 2*m_label_width); ImGui::PushItemWidth(m_control_width); @@ -314,88 +397,93 @@ void GLGizmoCut::render_radio_button(ConnectorType type) m_connector_type = type; } - -void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit) +void GLGizmoCut3D::render_connect_mode_radio_button(ConnectorMode mode) { - static float last_y = 0.0f; - static float last_h = 0.0f; + ImGui::SameLine(mode == ConnectorMode::Auto ? m_label_width : 2*m_label_width); + ImGui::PushItemWidth(m_control_width); + if (m_imgui->radio_button(m_connector_modes[int(mode)], m_connector_mode == mode)) + m_connector_mode = mode; +} - m_imgui->begin(_L("Cut"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); +void GLGizmoCut3D::render_cut_plane() +{ + const BoundingBoxf3 box = m_cut_plane_gizmo.bounding_box(); + Vec3d plane_center = box.center(); + plane_center.z() = m_cut_plane_gizmo.get_cut_z(); - m_imperial_units = wxGetApp().app_config->get("use_inches") == "1"; - m_label_width = m_imgui->get_style_scaling() * 100.0f; - m_control_width = m_imgui->get_style_scaling() * 150.0f; + const float min_x = box.min.x() - GLGizmoCut::Margin - plane_center.x(); + const float max_x = box.max.x() + GLGizmoCut::Margin - plane_center.x(); + const float min_y = box.min.y() - GLGizmoCut::Margin - plane_center.y(); + const float max_y = box.max.y() + GLGizmoCut::Margin - plane_center.y(); + glsafe(::glEnable(GL_DEPTH_TEST)); + glsafe(::glDisable(GL_CULL_FACE)); + glsafe(::glEnable(GL_BLEND)); + glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - // adjust window position to avoid overlap the view toolbar - const float win_h = ImGui::GetWindowHeight(); - y = std::min(y, bottom_limit - win_h); - ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always); - if (last_h != win_h || last_y != y) { - // ask canvas for another frame to render the window in the correct position - m_imgui->set_requires_extra_frame(); - if (last_h != win_h) - last_h = win_h; - if (last_y != y) - last_y = y; +#if ENABLE_GLBEGIN_GLEND_REMOVAL + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + shader->start_using(); + +// bool z_changed = std::abs(plane_center.z() - m_old_z) > EPSILON; +// m_old_z = plane_center.z(); + + Vec3d angles = get_rotation(); + + glsafe(::glPushMatrix()); + glsafe(::glTranslated(plane_center.x(), plane_center.y(), plane_center.z())); + glsafe(::glRotated(Geometry::rad2deg(angles.z()), 0.0, 0.0, 1.0)); + glsafe(::glRotated(Geometry::rad2deg(angles.y()), 0.0, 1.0, 0.0)); + glsafe(::glRotated(Geometry::rad2deg(angles.x()), 1.0, 0.0, 0.0)); + + if (!m_plane.is_initialized()/* || z_changed*/) { + m_plane.reset(); + + GLModel::InitializationData init_data; + GLModel::InitializationData::Entity entity; + entity.type = GLModel::PrimitiveType::Triangles; + entity.positions.reserve(4); + entity.positions.emplace_back(Vec3f(min_x, min_y, 0.0)); + entity.positions.emplace_back(Vec3f(max_x, min_y, 0.0)); + entity.positions.emplace_back(Vec3f(max_x, max_y, 0.0)); + entity.positions.emplace_back(Vec3f(min_x, max_y, 0.0)); + + entity.normals.reserve(4); + for (size_t i = 0; i < 4; ++i) { + entity.normals.emplace_back(Vec3f::UnitZ()); + } + + entity.indices.reserve(6); + entity.indices.emplace_back(0); + entity.indices.emplace_back(1); + entity.indices.emplace_back(2); + entity.indices.emplace_back(2); + entity.indices.emplace_back(3); + entity.indices.emplace_back(0); + + init_data.entities.emplace_back(entity); + m_plane.init_from(init_data); + m_plane.set_color(-1, PLANE_COLOR); } - render_combo(_u8L("Mode"), m_modes, m_mode); + m_plane.render(); + glsafe(::glPopMatrix()); +#else + // Draw the cutting plane + ::glBegin(GL_QUADS); + ::glColor4fv(PLANE_COLOR.data()); + ::glVertex3f(min_x, min_y, plane_center.z()); + ::glVertex3f(max_x, min_y, plane_center.z()); + ::glVertex3f(max_x, max_y, plane_center.z()); + ::glVertex3f(min_x, max_y, plane_center.z()); + glsafe(::glEnd()); +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL - if (m_mode == CutMode::cutPlanar) { - ImGui::Separator(); + glsafe(::glEnable(GL_CULL_FACE)); + glsafe(::glDisable(GL_BLEND)); - render_double_input("Z", m_cut_z); - - ImGui::AlignTextToFramePadding(); - m_imgui->text(_L("Rotation")); - ImGui::SameLine(m_label_width); - - render_rotation_input("X:", m_rotation_x); - ImGui::SameLine(); - render_rotation_input("Y:", m_rotation_y); - ImGui::SameLine(); - render_rotation_input("Z:", m_rotation_z); - - ImGui::SameLine(); - m_imgui->text(_L("°")); - - ImGui::AlignTextToFramePadding(); - m_imgui->text(_L("After cut")); - ImGui::SameLine(m_label_width); - m_imgui->checkbox(_L("Keep upper part"), m_keep_upper); - m_imgui->text(""); - ImGui::SameLine(m_label_width); - m_imgui->checkbox(_L("Keep lower part"), m_keep_lower); - m_imgui->text(""); - ImGui::SameLine(m_label_width); - m_imgui->disabled_begin(!m_keep_lower); - m_imgui->checkbox(_L("Rotate lower part upwards"), m_rotate_lower); - m_imgui->disabled_end(); - } - - // Connectors section - ImGui::Separator(); - - m_imgui->text(_L("Connectors")); - render_radio_button(ConnectorType::Plug); - render_radio_button(ConnectorType::Dowel); - - render_combo(_u8L("Style"), m_connector_styles, m_connector_style); - render_combo(_u8L("Shape"), m_connector_shapes, m_connector_shape); - - render_double_input(_u8L("Depth ratio"), m_connector_depth_ratio); - render_double_input(_u8L("Size"), m_connector_size); - - ImGui::Separator(); - - m_imgui->disabled_begin((!m_keep_upper && !m_keep_lower) || m_cut_z <= 0.0 || m_max_z <= m_cut_z); - const bool cut_clicked = m_imgui->button(_L("Perform cut")); - m_imgui->disabled_end(); - - m_imgui->end(); - - if (cut_clicked && (m_keep_upper || m_keep_lower)) - perform_cut(m_parent.get_selection()); + shader->stop_using(); } void GLGizmoCut::set_cut_z(double cut_z) @@ -481,18 +569,28 @@ void GLGizmoCut::update_contours() if (m_cut_contours.object_id != model_object->id() || m_cut_contours.volumes_idxs != volumes_idxs) m_cut_contours.mesh = model_object->raw_mesh(); - m_cut_contours.position = box.center(); - m_cut_contours.shift = Vec3d::Zero(); + m_cut_contours.position = Vec3d::Zero();//box.center(); + m_cut_contours.shift = box.center();//Vec3d::Zero(); m_cut_contours.object_id = model_object->id(); m_cut_contours.instance_idx = instance_idx; m_cut_contours.volumes_idxs = volumes_idxs; m_cut_contours.contours.reset(); + // addition back transformation + Geometry::Transformation m_transformation = Geometry::Transformation(); + m_transformation.set_offset(-first_glvolume->get_instance_transformation().get_offset()); + m_transformation.set_rotation(-m_angles); + auto cut_params = m_transformation.get_matrix(); + + MeshSlicingParams slicing_params; - slicing_params.trafo = first_glvolume->get_instance_transformation().get_matrix(); - const Polygons polys = slice_mesh(m_cut_contours.mesh.its, m_cut_z, slicing_params); + slicing_params.trafo = first_glvolume->get_instance_transformation().get_matrix() * cut_params; + + auto cut_z = m_cut_z - box.center().z(); + + const Polygons polys = slice_mesh(m_cut_contours.mesh.its, /*m_*/cut_z, slicing_params); if (!polys.empty()) { - m_cut_contours.contours.init_from(polys, static_cast(m_cut_z)); + m_cut_contours.contours.init_from(polys, static_cast(/*m_*/cut_z)); #if ENABLE_GLBEGIN_GLEND_REMOVAL m_cut_contours.contours.set_color(ColorRGBA::WHITE()); #else @@ -500,13 +598,211 @@ void GLGizmoCut::update_contours() #endif // ENABLE_GLBEGIN_GLEND_REMOVAL } } - else if (box.center() != m_cut_contours.position) { - m_cut_contours.shift = box.center() - m_cut_contours.position; + else if (box.center() != m_cut_contours.shift) { + m_cut_contours.shift = box.center();// -m_cut_contours.position; } + //else if (box.center() != m_cut_contours.position) { + // m_cut_contours.shift = -box.center();// -m_cut_contours.position; + //} } else m_cut_contours.contours.reset(); } +GLGizmoCut3D::GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) + : GLGizmoRotate3D(parent, icon_filename, sprite_id) + , m_cut_plane_gizmo(GLGizmoCut(parent, "", -1)) +{ + m_cut_plane_gizmo.set_group_id(3); + + m_modes = { _u8L("Planar"), _u8L("By Line"),_u8L("Grid") +// , _u8L("Radial"), _u8L("Modular") + }; + + m_connector_modes = { _u8L("Auto"), _u8L("Manual") }; + m_connector_types = { _u8L("Plug"), _u8L("Dowel") }; + + m_connector_styles = { _u8L("Prizm"), _u8L("Frustrum") +// , _u8L("Claw") + }; + + m_connector_shapes = { _u8L("Triangle"), _u8L("Square"), _u8L("Circle"), _u8L("Hexagon") +// , _u8L("D-shape") + }; + + m_axis_names = {"X", "Y", "Z"}; +} + +bool GLGizmoCut3D::on_init() +{ + if(!GLGizmoRotate3D::on_init()) + return false; + + if (!m_cut_plane_gizmo.init()) + return false; + + m_shortcut_key = WXK_CONTROL_C; + return true; +} + +std::string GLGizmoCut3D::on_get_name() const +{ + return _u8L("Cut"); +} + +bool GLGizmoCut3D::on_is_activable() const +{ + return m_cut_plane_gizmo.is_activable(); +} + +void GLGizmoCut3D::on_start_dragging() +{ + GLGizmoRotate3D::on_start_dragging(); + if (m_hover_id == 3) + m_cut_plane_gizmo.start_dragging(); +} + +void GLGizmoCut3D::on_stop_dragging() +{ + GLGizmoRotate3D::on_stop_dragging(); + if (m_hover_id == 3) + m_cut_plane_gizmo.stop_dragging(); +} + +void GLGizmoCut3D::on_render() +{ + render_cut_plane(); + if (m_mode == CutMode::cutPlanar) { + GLGizmoRotate3D::on_render(); +// if (m_hover_id == -1 || m_hover_id == 3) + } + m_cut_plane_gizmo.render(); +} + +void GLGizmoCut3D::on_render_input_window(float x, float y, float bottom_limit) +{ + static float last_y = 0.0f; + static float last_h = 0.0f; + + m_imgui->begin(_L("Cut"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + + m_imperial_units = wxGetApp().app_config->get("use_inches") == "1"; + m_label_width = m_imgui->get_style_scaling() * 100.0f; + m_control_width = m_imgui->get_style_scaling() * 150.0f; + + // adjust window position to avoid overlap the view toolbar + const float win_h = ImGui::GetWindowHeight(); + y = std::min(y, bottom_limit - win_h); + ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always); + if (last_h != win_h || last_y != y) { + // ask canvas for another frame to render the window in the correct position + m_imgui->set_requires_extra_frame(); + if (last_h != win_h) + last_h = win_h; + if (last_y != y) + last_y = y; + } + + render_combo(_u8L("Mode"), m_modes, m_mode); + + if (m_mode <= CutMode::cutByLine) { + ImGui::Separator(); + + if (m_mode == CutMode::cutPlanar) { + ImGui::AlignTextToFramePadding(); + m_imgui->text(_L("Move center")); + ImGui::SameLine(m_label_width); + for (Axis axis : {X, Y, Z}) + render_move_center_input(axis); + m_imgui->text(m_imperial_units ? _L("in") : _L("mm")); + + ImGui::AlignTextToFramePadding(); + m_imgui->text(_L("Rotation")); + ImGui::SameLine(m_label_width); + for (Axis axis : {X, Y, Z}) + render_rotation_input(axis); + m_imgui->text(_L("°")); + } + else { + ImGui::AlignTextToFramePadding(); + ImGui::AlignTextToFramePadding(); + ImGui::AlignTextToFramePadding(); + ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + 3*m_control_width); + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _L("Connect some two points of object to cteate a cut plane")); + ImGui::PopTextWrapPos(); + ImGui::AlignTextToFramePadding(); + ImGui::AlignTextToFramePadding(); + } + + ImGui::AlignTextToFramePadding(); + m_imgui->text(_L("After cut")); + ImGui::SameLine(m_label_width); + m_imgui->checkbox(_L("Keep upper part"), m_keep_upper); + m_imgui->text(""); + ImGui::SameLine(m_label_width); + m_imgui->checkbox(_L("Keep lower part"), m_keep_lower); + m_imgui->text(""); + ImGui::SameLine(m_label_width); + m_imgui->disabled_begin(!m_keep_lower); + m_imgui->checkbox(_L("Rotate lower part upwards"), m_rotate_lower); + m_imgui->disabled_end(); + } + + m_imgui->disabled_begin(!m_keep_lower || !m_keep_upper); + // Connectors section + ImGui::Separator(); + + ImGui::AlignTextToFramePadding(); + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _L("Connectors")); + + m_imgui->text(_L("Mode")); + render_connect_mode_radio_button(ConnectorMode::Auto); + render_connect_mode_radio_button(ConnectorMode::Manual); + + m_imgui->text(_L("Type")); + render_connect_type_radio_button(ConnectorType::Plug); + render_connect_type_radio_button(ConnectorType::Dowel); + + render_combo(_u8L("Style"), m_connector_styles, m_connector_style); + render_combo(_u8L("Shape"), m_connector_shapes, m_connector_shape); + + render_double_input(_u8L("Depth ratio"), m_connector_depth_ratio); + render_double_input(_u8L("Size"), m_connector_size); + + m_imgui->disabled_end(); + + ImGui::Separator(); + + m_imgui->disabled_begin((!m_keep_upper && !m_keep_lower) /*|| m_cut_z <= 0.0 || m_max_z <= m_cut_z*/); + const bool cut_clicked = m_imgui->button(_L("Perform cut")); + m_imgui->disabled_end(); + + m_imgui->end(); + + if (cut_clicked && (m_keep_upper || m_keep_lower)) + perform_cut(m_parent.get_selection()); +} + +void GLGizmoCut3D::perform_cut(const Selection& selection) +{ + const int instance_idx = selection.get_instance_idx(); + const int object_idx = selection.get_object_idx(); + + wxCHECK_RET(instance_idx >= 0 && object_idx >= 0, "GLGizmoCut: Invalid object selection"); + + // m_cut_z is the distance from the bed. Subtract possible SLA elevation. + const GLVolume* first_glvolume = selection.get_volume(*selection.get_volume_idxs().begin()); + const double object_cut_z = m_cut_plane_gizmo.get_cut_z() - first_glvolume->get_sla_shift_z(); + + if (0.0 < object_cut_z/* && object_cut_z < m_max_z*/) + wxGetApp().plater()->cut(object_idx, instance_idx, object_cut_z, + only_if(m_keep_upper, ModelObjectCutAttribute::KeepUpper) | + only_if(m_keep_lower, ModelObjectCutAttribute::KeepLower) | + only_if(m_rotate_lower, ModelObjectCutAttribute::FlipLower)); + else { + // the object is SLA-elevated and the plane is under it. + } +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index 14f305c03d..f8d7570a43 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -2,6 +2,7 @@ #define slic3r_GLGizmoCut_hpp_ #include "GLGizmoBase.hpp" +#include "GLGizmoRotate.hpp" #include "slic3r/GUI/GLModel.hpp" #include "libslic3r/TriangleMesh.hpp" #include "libslic3r/ObjectID.hpp" @@ -11,13 +12,11 @@ namespace GUI { class GLGizmoCut : public GLGizmoBase { +public: static const double Offset; static const double Margin; - +private: double m_cut_z{ 0.0 }; - double m_rotation_x{ 0.0 }; - double m_rotation_y{ 0.0 }; - double m_rotation_z{ 0.0 }; double m_max_z{ 0.0 }; double m_start_z{ 0.0 }; Vec3d m_drag_pos; @@ -26,57 +25,11 @@ class GLGizmoCut : public GLGizmoBase bool m_keep_lower{ true }; bool m_rotate_lower{ false }; #if ENABLE_GLBEGIN_GLEND_REMOVAL - GLModel m_plane; GLModel m_grabber_connection; float m_old_z{ 0.0f }; #endif // ENABLE_GLBEGIN_GLEND_REMOVAL - double m_connector_depth_ratio{ 1.5 }; - double m_connector_size{ 5.0 }; - float m_label_width{ 150.0 }; - float m_control_width{ 200.0 }; - bool m_imperial_units{ false }; - -public: - enum CutMode { - cutPlanar = 0 - ,cutGrig - //,cutRadial - //,cutModular - }; - - enum ConnectorType { - Plug = 0 - ,Dowel - }; - - enum ConnectorStyle { - Prizm = 0 - ,Frustrum - //,Claw - }; - - enum ConnectorShape { - Triangle = 0 - ,Square - ,Circle - ,Hexagon -// ,D-shape - }; - -private: - - std::vector m_modes; - size_t m_mode{ size_t(cutPlanar) }; - - std::vector m_connector_types; - ConnectorType m_connector_type{ Plug }; - - std::vector m_connector_styles; - size_t m_connector_style{ size_t(Prizm) }; - - std::vector m_connector_shapes; - size_t m_connector_shape{ size_t(Hexagon) }; + Vec3d m_angles{ Vec3d::Zero() }; struct CutContours { @@ -95,8 +48,9 @@ private: public: GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); - double get_cut_z() const { return m_cut_z; } - void set_cut_z(double cut_z); + double get_cut_z() const { return m_cut_z; } + void set_cut_z(double cut_z); + void set_angles(const Vec3d& angles) { m_angles = angles; } std::string get_tooltip() const override; @@ -113,18 +67,143 @@ protected: virtual void on_render_for_picking() override; virtual void on_render_input_window(float x, float y, float bottom_limit) override; - void render_combo(const std::string& label, const std::vector& lines, size_t& selection_idx); - void render_double_input(const std::string& label, double& value_in); - void render_rotation_input(const std::string& label, double& value_in); - void render_radio_button(ConnectorType type); - private: void perform_cut(const Selection& selection); double calc_projection(const Linef3& mouse_ray) const; + +public: BoundingBoxf3 bounding_box() const; void update_contours(); }; +class GLGizmoCut3D : public GLGizmoRotate3D +{ + GLGizmoCut m_cut_plane_gizmo; + +#if ENABLE_GLBEGIN_GLEND_REMOVAL + GLModel m_plane; + float m_old_z{ 0.0f }; +#endif // ENABLE_GLBEGIN_GLEND_REMOVAL + + bool m_keep_upper{ true }; + bool m_keep_lower{ true }; + bool m_rotate_lower{ false }; + + double m_connector_depth_ratio{ 1.5 }; + double m_connector_size{ 5.0 }; + + float m_label_width{ 150.0 }; + float m_control_width{ 200.0 }; + bool m_imperial_units{ false }; + + enum CutMode { + cutPlanar + , cutByLine + , cutGrig + //,cutRadial + //,cutModular + }; + + enum ConnectorMode { + Auto + , Manual + }; + + enum ConnectorType { + Plug + , Dowel + }; + + enum ConnectorStyle { + Prizm + , Frustrum + //,Claw + }; + + enum ConnectorShape { + Triangle + , Square + , Circle + , Hexagon + //,D-shape + }; + + std::vector m_modes; + size_t m_mode{ size_t(cutPlanar) }; + + std::vector m_connector_modes; + ConnectorMode m_connector_mode{ Auto }; + + std::vector m_connector_types; + ConnectorType m_connector_type{ Plug }; + + std::vector m_connector_styles; + size_t m_connector_style{ size_t(Prizm) }; + + std::vector m_connector_shapes; + size_t m_connector_shape{ size_t(Hexagon) }; + + std::vector m_axis_names; + +public: + GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); + + std::string get_tooltip() const override { + std::string tooltip = GLGizmoRotate3D::get_tooltip(); + if (tooltip.empty()) + tooltip = m_cut_plane_gizmo.get_tooltip(); + return tooltip; + } + +protected: + bool on_init() override; + std::string on_get_name() const override; + void on_set_state() override { + GLGizmoRotate3D::on_set_state(); + m_cut_plane_gizmo.set_state(m_state); + } + void on_set_hover_id() override { + GLGizmoRotate3D::on_set_hover_id(); + m_cut_plane_gizmo.set_hover_id((m_hover_id == 3) ? 0 : -1); + } + void on_enable_grabber(unsigned int id) override { + GLGizmoRotate3D::on_enable_grabber(id); + if (id == 3) + m_cut_plane_gizmo.enable_grabber(0); + } + void on_disable_grabber(unsigned int id) override { + GLGizmoRotate3D::on_disable_grabber(id); + if (id == 3) + m_cut_plane_gizmo.disable_grabber(0); + } + bool on_is_activable() const override; + void on_start_dragging() override; + void on_stop_dragging() override; + void on_update(const UpdateData& data) override { + GLGizmoRotate3D::on_update(data); + m_cut_plane_gizmo.update(data); + } + void on_render() override; + void on_render_for_picking() override { + GLGizmoRotate3D::on_render_for_picking(); + m_cut_plane_gizmo.render_for_picking(); + } + + void on_render_input_window(float x, float y, float bottom_limit) override; + +private: + + void render_combo(const std::string& label, const std::vector& lines, size_t& selection_idx); + void render_double_input(const std::string& label, double& value_in); + void render_move_center_input(int axis); + void render_rotation_input(int axis); + void render_connect_mode_radio_button(ConnectorMode mode); + void render_connect_type_radio_button(ConnectorType type); + + void render_cut_plane(); + void perform_cut(const Selection& selection); +}; + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index dca578bd76..9869634cc2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -38,6 +38,11 @@ void GLGizmoRotate::set_angle(double angle) m_angle = angle; } +void GLGizmoRotate::set_center_z(double center_z) +{ + m_center_z = center_z; +} + std::string GLGizmoRotate::get_tooltip() const { std::string axis; @@ -60,6 +65,8 @@ void GLGizmoRotate::on_start_dragging() { const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box(); m_center = box.center(); + if (m_center_z >= 0) + m_center[Z] = m_center_z; m_radius = Offset + box.radius(); m_snap_coarse_in_radius = m_radius / 3.0f; m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius; @@ -112,6 +119,8 @@ void GLGizmoRotate::on_render() if (m_hover_id != 0 && !m_grabbers.front().dragging) { m_center = box.center(); + if (m_center_z >= 0) + m_center[Z] = m_center_z; m_radius = Offset + box.radius(); m_snap_coarse_in_radius = m_radius / 3.0f; m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index bb33e0f731..0c291cbef1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -28,6 +28,7 @@ public: private: Axis m_axis; double m_angle{ 0.0 }; + double m_center_z{ -1.0 }; Vec3d m_center{ Vec3d::Zero() }; float m_radius{ 0.0f }; float m_snap_coarse_in_radius{ 0.0f }; @@ -58,6 +59,7 @@ public: double get_angle() const { return m_angle; } void set_angle(double angle); + void set_center_z(double center_z); std::string get_tooltip() const override; @@ -101,6 +103,7 @@ public: Vec3d get_rotation() const { return Vec3d(m_gizmos[X].get_angle(), m_gizmos[Y].get_angle(), m_gizmos[Z].get_angle()); } void set_rotation(const Vec3d& rotation) { m_gizmos[X].set_angle(rotation(0)); m_gizmos[Y].set_angle(rotation(1)); m_gizmos[Z].set_angle(rotation(2)); } + void set_center_z(double center_z) { m_gizmos[X].set_center_z(center_z); m_gizmos[Y].set_center_z(center_z); m_gizmos[Z].set_center_z(center_z); } std::string get_tooltip() const override { std::string tooltip = m_gizmos[X].get_tooltip(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 55cbb0c308..3a144a65d1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -97,7 +97,7 @@ bool GLGizmosManager::init() m_gizmos.emplace_back(new GLGizmoScale3D(m_parent, "scale.svg", 1)); m_gizmos.emplace_back(new GLGizmoRotate3D(m_parent, "rotate.svg", 2)); m_gizmos.emplace_back(new GLGizmoFlatten(m_parent, "place.svg", 3)); - m_gizmos.emplace_back(new GLGizmoCut(m_parent, "cut.svg", 4)); + m_gizmos.emplace_back(new GLGizmoCut3D(m_parent, "cut.svg", 4)); m_gizmos.emplace_back(new GLGizmoHollow(m_parent, "hollow.svg", 5)); m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 6)); m_gizmos.emplace_back(new GLGizmoFdmSupports(m_parent, "fdm_supports.svg", 7));