From b40473be51fd1050fa4d7b2c3297230758085d46 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 9 Feb 2023 08:52:07 +0100 Subject: [PATCH 1/5] CutGizmo: Improvements to identify Upper/Lower parts_count + Rework CutDialog + Added "Cut to" section (Idea from #9564[Cut: Keep results as parts of current idea] was used, but there is other implementation) + Fix for #9657 - Inconvenient gizma, blocks the view of the cut of small parts + Add functionality "Flip cut plane" = Fix for #9632 - Adding connectors to either split cut part + ImGuiWrapper: added tooltip for button --- src/libslic3r/Model.cpp | 57 +++-- src/libslic3r/Model.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 334 ++++++++++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoCut.hpp | 25 +- src/slic3r/GUI/ImGuiWrapper.cpp | 11 +- src/slic3r/GUI/ImGuiWrapper.hpp | 2 +- 6 files changed, 295 insertions(+), 136 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index bab2e5bc86..9c074ef1e9 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1477,6 +1477,12 @@ void ModelObject::process_solid_part_cut(ModelVolume* volume, const Transform3d& // Add required cut parts to the objects + if (attributes.has(ModelObjectCutAttribute::KeepAsParts)) { + add_cut_volume(lower_mesh, lower, volume, cut_matrix); + add_cut_volume(upper_mesh, lower, volume, cut_matrix); + return; + } + if (attributes.has(ModelObjectCutAttribute::KeepUpper)) add_cut_volume(upper_mesh, upper, volume, cut_matrix); @@ -1608,34 +1614,39 @@ ModelObjectPtrs ModelObject::cut(size_t instance, const Transform3d& cut_matrix, ModelObjectPtrs res; - if (attributes.has(ModelObjectCutAttribute::KeepUpper) && !upper->volumes.empty()) { - invalidate_translations(upper, instances[instance]); - - reset_instance_transformation(upper, instance, cut_matrix, - attributes.has(ModelObjectCutAttribute::PlaceOnCutUpper), - attributes.has(ModelObjectCutAttribute::FlipUpper), - local_displace); - res.push_back(upper); - } - - if (attributes.has(ModelObjectCutAttribute::KeepLower) && !lower->volumes.empty()) { - invalidate_translations(lower, instances[instance]); - - reset_instance_transformation(lower, instance, cut_matrix, - attributes.has(ModelObjectCutAttribute::PlaceOnCutLower), - attributes.has(ModelObjectCutAttribute::PlaceOnCutLower) ? true : attributes.has(ModelObjectCutAttribute::FlipLower)); + if (attributes.has(ModelObjectCutAttribute::KeepAsParts) && !lower->volumes.empty()) { res.push_back(lower); } + else { + if (attributes.has(ModelObjectCutAttribute::KeepUpper) && !upper->volumes.empty()) { + invalidate_translations(upper, instances[instance]); - if (attributes.has(ModelObjectCutAttribute::CreateDowels) && !dowels.empty()) { - for (auto dowel : dowels) { - invalidate_translations(dowel, instances[instance]); + reset_instance_transformation(upper, instance, cut_matrix, + attributes.has(ModelObjectCutAttribute::PlaceOnCutUpper), + attributes.has(ModelObjectCutAttribute::FlipUpper), + local_displace); + res.push_back(upper); + } - reset_instance_transformation(dowel, instance, Transform3d::Identity(), false, false, local_dowels_displace); + if (attributes.has(ModelObjectCutAttribute::KeepLower) && !lower->volumes.empty()) { + invalidate_translations(lower, instances[instance]); - local_dowels_displace += dowel->full_raw_mesh_bounding_box().size().cwiseProduct(Vec3d(-1.5, -1.5, 0.0)); - dowel->name += "-Dowel-" + dowel->volumes[0]->name; - res.push_back(dowel); + reset_instance_transformation(lower, instance, cut_matrix, + attributes.has(ModelObjectCutAttribute::PlaceOnCutLower), + attributes.has(ModelObjectCutAttribute::PlaceOnCutLower) ? true : attributes.has(ModelObjectCutAttribute::FlipLower)); + res.push_back(lower); + } + + if (attributes.has(ModelObjectCutAttribute::CreateDowels) && !dowels.empty()) { + for (auto dowel : dowels) { + invalidate_translations(dowel, instances[instance]); + + reset_instance_transformation(dowel, instance, Transform3d::Identity(), false, false, local_dowels_displace); + + local_dowels_displace += dowel->full_raw_mesh_bounding_box().size().cwiseProduct(Vec3d(-1.5, -1.5, 0.0)); + dowel->name += "-Dowel-" + dowel->volumes[0]->name; + res.push_back(dowel); + } } } diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 6e444fe491..a1ae950d18 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -316,7 +316,7 @@ enum class ModelVolumeType : int { SUPPORT_ENFORCER, }; -enum class ModelObjectCutAttribute : int { KeepUpper, KeepLower, FlipUpper, FlipLower, PlaceOnCutUpper, PlaceOnCutLower, CreateDowels }; +enum class ModelObjectCutAttribute : int { KeepUpper, KeepLower, KeepAsParts, FlipUpper, FlipLower, PlaceOnCutUpper, PlaceOnCutLower, CreateDowels }; using ModelObjectCutAttributes = enum_bitmask; ENABLE_ENUM_BITMASK_OPERATORS(ModelObjectCutAttribute); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 0798b61f49..6fd74c2400 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -21,6 +21,8 @@ namespace Slic3r { namespace GUI { static const ColorRGBA GRABBER_COLOR = ColorRGBA::YELLOW(); +static const ColorRGBA ABOVE_GRABBER_COLOR = ColorRGBA::CYAN(); +static const ColorRGBA BELOW_GRABBER_COLOR = ColorRGBA::MAGENTA(); // connector colors static const ColorRGBA PLAG_COLOR = ColorRGBA::YELLOW(); @@ -196,7 +198,7 @@ static void init_from_angle_arc(GLModel& model, double angle, double radius) GLGizmoCut3D::GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) - , m_connectors_group_id (3) + , m_connectors_group_id (GrabberID::Count) , m_connector_type (CutConnectorType::Plug) , m_connector_style (size_t(CutConnectorStyle::Prizm)) , m_connector_shape_id (size_t(CutConnectorShape::Circle)) @@ -227,13 +229,19 @@ GLGizmoCut3D::GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, m_axis_names = { "X", "Y", "Z" }; + m_part_orientation_names = { + {"none", _L("Keep orientation")}, + {"on_cut", _L("Place on cut")}, + {"flip", _L("Flip upside down")}, + }; + update_connector_shape(); } std::string GLGizmoCut3D::get_tooltip() const { std::string tooltip; - if (m_hover_id == Z) { + if (m_hover_id == Z || (m_dragging && m_hover_id == CutPlane)) { double koef = m_imperial_units ? ObjectManipulation::mm_to_in : 1.0; std::string unit_str = " " + (m_imperial_units ? _u8L("inch") : _u8L("mm")); const BoundingBoxf3 tbb = transformed_bounding_box(m_plane_center); @@ -249,6 +257,11 @@ std::string GLGizmoCut3D::get_tooltip() const } return tooltip; } + + if (!m_dragging && m_hover_id == CutPlane) + return _u8L("Click to flip the cut plane\n" + "Drag to move the cut plane"); + if (tooltip.empty() && (m_hover_id == X || m_hover_id == Y)) { std::string axis = m_hover_id == X ? "X" : "Y"; return axis + ": " + format(float(rad2deg(m_angle)), 1) + _u8L("°"); @@ -278,11 +291,17 @@ bool GLGizmoCut3D::on_mouse(const wxMouseEvent &mouse_event) if (use_grabbers(mouse_event)) { if (m_hover_id >= m_connectors_group_id) { - if (mouse_event.LeftDown() && !mouse_event.CmdDown()&& !mouse_event.AltDown()) + if (mouse_event.LeftDown() && !mouse_event.CmdDown() && !mouse_event.AltDown()) unselect_all_connectors(); if (mouse_event.LeftUp() && !mouse_event.ShiftDown()) gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), mouse_event.CmdDown()); } + else if (m_hover_id == CutPlane) { + if (mouse_event.LeftDown()) + m_was_cut_plane_dragged = false; + else if (mouse_event.LeftUp() && !m_was_cut_plane_dragged) + flip_cut_plane(); + } return true; } @@ -656,12 +675,11 @@ void GLGizmoCut3D::render_cut_plane() shader->set_uniform("view_model_matrix", view_model_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - if (can_perform_cut() && has_valid_contour()) -// m_plane.set_color({ 0.8f, 0.8f, 0.8f, 0.5f }); - m_plane.set_color({ 0.9f, 0.9f, 0.9f, 0.5f }); + if (can_perform_cut() && has_valid_contour()) + m_plane.model.set_color({ 0.8f, 0.8f, 0.8f, 0.5f }); else - m_plane.set_color({ 1.0f, 0.8f, 0.8f, 0.5f }); - m_plane.render(); + m_plane.model.set_color({ 1.0f, 0.8f, 0.8f, 0.5f }); + m_plane.model.render(); glsafe(::glEnable(GL_CULL_FACE)); glsafe(::glDisable(GL_BLEND)); @@ -717,7 +735,7 @@ void GLGizmoCut3D::render_line(GLModel& line_model, const ColorRGBA& color, Tran } } -void GLGizmoCut3D::render_rotation_snapping(Axis axis, const ColorRGBA& color) +void GLGizmoCut3D::render_rotation_snapping(GrabberID axis, const ColorRGBA& color) { GLShaderProgram* line_shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat"); if (!line_shader) @@ -760,49 +778,34 @@ void GLGizmoCut3D::render_cut_plane_grabbers() { glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); - ColorRGBA color = m_hover_id == Z ? complementary(GRABBER_COLOR) : GRABBER_COLOR; + ColorRGBA color = ColorRGBA::GRAY(); const Transform3d view_matrix = wxGetApp().plater()->get_camera().get_view_matrix() * translation_transform(m_plane_center) * m_rotation_m; const double mean_size = get_grabber_mean_size(bounding_box()); + double size; - double size = m_dragging && m_hover_id == Z ? get_dragging_half_size(mean_size) : get_half_size(mean_size); + const bool dragging_by_cut_plane = m_dragging && m_hover_id == CutPlane; - Vec3d cone_scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size); - Vec3d offset = 1.25 * size * Vec3d::UnitZ(); + if (!dragging_by_cut_plane) { + render_grabber_connection(GRABBER_COLOR, view_matrix); - // render Z grabber - - if (!m_dragging && m_hover_id < 0) - render_grabber_connection(color, view_matrix); - render_model(m_sphere.model, color, view_matrix * scale_transform(size)); - - if ((!m_dragging && m_hover_id < 0) || m_hover_id == Z) - { - const BoundingBoxf3 tbb = transformed_bounding_box(m_plane_center); - if (tbb.min.z() <= 0.0) - render_model(m_cone.model, color, view_matrix * translation_transform(-offset) * rotation_transform(PI * Vec3d::UnitX()) * scale_transform(cone_scale)); - - if (tbb.max.z() >= 0.0) - render_model(m_cone.model, color, view_matrix * translation_transform(offset) * scale_transform(cone_scale)); - } - - // render top sphere for X/Y grabbers - - if ((!m_dragging && m_hover_id < 0) || m_hover_id == X || m_hover_id == Y) - { + // render sphere grabber size = m_dragging ? get_dragging_half_size(mean_size) : get_half_size(mean_size); - color = m_hover_id == Y ? complementary(ColorRGBA::GREEN()) : - m_hover_id == X ? complementary(ColorRGBA::RED()) : ColorRGBA::GRAY(); + color = m_hover_id == Y ? complementary(ColorRGBA::GREEN()) : + m_hover_id == X ? complementary(ColorRGBA::RED()) : + m_hover_id == Z ? GRABBER_COLOR : ColorRGBA::GRAY(); render_model(m_sphere.model, color, view_matrix * translation_transform(m_grabber_connection_len * Vec3d::UnitZ()) * scale_transform(size)); } + const bool no_one_grabber_hovered = !m_dragging && (m_hover_id < 0 || m_hover_id == CutPlane); + // render X grabber - if ((!m_dragging && m_hover_id < 0) || m_hover_id == X) + if (no_one_grabber_hovered || m_hover_id == X) { size = m_dragging && m_hover_id == X ? get_dragging_half_size(mean_size) : get_half_size(mean_size); - cone_scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size); + const Vec3d cone_scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size); color = m_hover_id == X ? complementary(ColorRGBA::RED()) : ColorRGBA::RED(); if (m_hover_id == X) { @@ -810,7 +813,7 @@ void GLGizmoCut3D::render_cut_plane_grabbers() render_rotation_snapping(X, color); } - offset = Vec3d(0.0, 1.25 * size, m_grabber_connection_len); + Vec3d offset = Vec3d(0.0, 1.25 * size, m_grabber_connection_len); render_model(m_cone.model, color, view_matrix * translation_transform(offset) * rotation_transform(-0.5 * PI * Vec3d::UnitX()) * scale_transform(cone_scale)); offset = Vec3d(0.0, -1.25 * size, m_grabber_connection_len); render_model(m_cone.model, color, view_matrix * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitX()) * scale_transform(cone_scale)); @@ -818,10 +821,10 @@ void GLGizmoCut3D::render_cut_plane_grabbers() // render Y grabber - if ((!m_dragging && m_hover_id < 0) || m_hover_id == Y) + if (no_one_grabber_hovered || m_hover_id == Y) { size = m_dragging && m_hover_id == Y ? get_dragging_half_size(mean_size) : get_half_size(mean_size); - cone_scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size); + const Vec3d cone_scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size); color = m_hover_id == Y ? complementary(ColorRGBA::GREEN()) : ColorRGBA::GREEN(); if (m_hover_id == Y) { @@ -829,7 +832,7 @@ void GLGizmoCut3D::render_cut_plane_grabbers() render_rotation_snapping(Y, color); } - offset = Vec3d(1.25 * size, 0.0, m_grabber_connection_len); + Vec3d offset = Vec3d(1.25 * size, 0.0, m_grabber_connection_len); render_model(m_cone.model, color, view_matrix * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitY()) * scale_transform(cone_scale)); offset = Vec3d(-1.25 * size, 0.0, m_grabber_connection_len); render_model(m_cone.model, color, view_matrix * translation_transform(offset)* rotation_transform(-0.5 * PI * Vec3d::UnitY()) * scale_transform(cone_scale)); @@ -940,8 +943,8 @@ void GLGizmoCut3D::on_register_raycasters_for_picking() m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, Y, *m_cone.mesh_raycaster, Transform3d::Identity())); m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, Z, *m_sphere.mesh_raycaster, Transform3d::Identity())); - m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, Z, *m_cone.mesh_raycaster, Transform3d::Identity())); - m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, Z, *m_cone.mesh_raycaster, Transform3d::Identity())); + + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CutPlane, *m_plane.mesh_raycaster, Transform3d::Identity())); } update_raycasters_for_picking_transform(); @@ -1018,20 +1021,22 @@ void GLGizmoCut3D::update_raycasters_for_picking_transform() const double size = get_half_size(get_grabber_mean_size(box)); Vec3d scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size); + int id = 0; + Vec3d offset = Vec3d(0.0, 1.25 * size, m_grabber_connection_len); - m_raycasters[0]->set_transform(trafo * translation_transform(offset) * rotation_transform(-0.5 * PI * Vec3d::UnitX()) * scale_transform(scale)); + m_raycasters[id++]->set_transform(trafo * translation_transform(offset) * rotation_transform(-0.5 * PI * Vec3d::UnitX()) * scale_transform(scale)); offset = Vec3d(0.0, -1.25 * size, m_grabber_connection_len); - m_raycasters[1]->set_transform(trafo * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitX()) * scale_transform(scale)); + m_raycasters[id++]->set_transform(trafo * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitX()) * scale_transform(scale)); offset = Vec3d(1.25 * size, 0.0, m_grabber_connection_len); - m_raycasters[2]->set_transform(trafo * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitY()) * scale_transform(scale)); + m_raycasters[id++]->set_transform(trafo * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitY()) * scale_transform(scale)); offset = Vec3d(-1.25 * size, 0.0, m_grabber_connection_len); - m_raycasters[3]->set_transform(trafo * translation_transform(offset) * rotation_transform(-0.5 * PI * Vec3d::UnitY()) * scale_transform(scale)); + m_raycasters[id++]->set_transform(trafo * translation_transform(offset) * rotation_transform(-0.5 * PI * Vec3d::UnitY()) * scale_transform(scale)); offset = 1.25 * size * Vec3d::UnitZ(); - m_raycasters[4]->set_transform(trafo * scale_transform(size)); - m_raycasters[5]->set_transform(trafo * translation_transform(-offset) * rotation_transform(PI * Vec3d::UnitX()) * scale_transform(scale)); - m_raycasters[6]->set_transform(trafo * translation_transform(offset) * scale_transform(scale)); + m_raycasters[id++]->set_transform(trafo * translation_transform(m_grabber_connection_len * Vec3d::UnitZ()) * scale_transform(size)); + + m_raycasters[id++]->set_transform(trafo); } } @@ -1072,7 +1077,7 @@ bool GLGizmoCut3D::on_is_selectable() const return wxGetApp().get_mode() != comSimple; } -Vec3d GLGizmoCut3D::mouse_position_in_local_plane(Axis axis, const Linef3& mouse_ray) const +Vec3d GLGizmoCut3D::mouse_position_in_local_plane(GrabberID axis, const Linef3& mouse_ray) const { double half_pi = 0.5 * PI; @@ -1108,13 +1113,11 @@ Vec3d GLGizmoCut3D::mouse_position_in_local_plane(Axis axis, const Linef3& mouse void GLGizmoCut3D::dragging_grabber_z(const GLGizmoBase::UpdateData &data) { - Vec3d starting_box_center = m_plane_center - Vec3d::UnitZ(); // some Margin - rotate_vec3d_around_plane_center(starting_box_center); + const Vec3d grabber_init_pos = (m_hover_id == CutPlane ? 0. : m_grabber_connection_len) * Vec3d::UnitZ(); + const Vec3d starting_drag_position = translation_transform(m_plane_center) * m_rotation_m * grabber_init_pos; + double projection = 0.0; - const Vec3d&starting_drag_position = m_plane_center; - double projection = 0.0; - - Vec3d starting_vec = starting_drag_position - starting_box_center; + Vec3d starting_vec = m_rotation_m * Vec3d::UnitZ(); if (starting_vec.norm() != 0.0) { Vec3d mouse_dir = data.mouse_ray.unit_vector(); // finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position @@ -1130,17 +1133,19 @@ void GLGizmoCut3D::dragging_grabber_z(const GLGizmoBase::UpdateData &data) projection = inters_vec.dot(starting_vec); } if (wxGetKeyState(WXK_SHIFT)) - projection = m_snap_step * (double)std::round(projection / m_snap_step); + projection = m_snap_step * std::round(projection / m_snap_step); const Vec3d shift = starting_vec * projection; // move cut plane center set_center(m_plane_center + shift); + + m_was_cut_plane_dragged = true; } void GLGizmoCut3D::dragging_grabber_xy(const GLGizmoBase::UpdateData &data) { - const Vec2d mouse_pos = to_2d(mouse_position_in_local_plane((Axis)m_hover_id, data.mouse_ray)); + const Vec2d mouse_pos = to_2d(mouse_position_in_local_plane((GrabberID)m_hover_id, data.mouse_ray)); const Vec2d orig_dir = Vec2d::UnitX(); const Vec2d new_dir = mouse_pos.normalized(); @@ -1197,7 +1202,7 @@ void GLGizmoCut3D::on_dragging(const UpdateData& data) { if (m_hover_id < 0) return; - if (m_hover_id == Z) + if (m_hover_id == Z || m_hover_id == CutPlane) dragging_grabber_z(data); else if (m_hover_id == X || m_hover_id == Y) dragging_grabber_xy(data); @@ -1223,8 +1228,9 @@ void GLGizmoCut3D::on_stop_dragging() Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Rotate cut plane"), UndoRedo::SnapshotType::GizmoAction); m_start_dragging_m = m_rotation_m; } - else if (m_hover_id == Z) { - Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Move cut plane"), UndoRedo::SnapshotType::GizmoAction); + else if (m_hover_id == Z || m_hover_id == CutPlane) { + if (m_was_cut_plane_dragged) + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Move cut plane"), UndoRedo::SnapshotType::GizmoAction); m_ar_plane_center = m_plane_center; } } @@ -1332,7 +1338,7 @@ bool GLGizmoCut3D::update_bb() set_center_pos(m_bb_center, true); m_radius = box.radius(); - m_grabber_connection_len = 0.75 * m_radius;// std::min(0.75 * m_radius, 35.0); + m_grabber_connection_len = 0.5 * m_radius;// std::min(0.75 * m_radius, 35.0); m_grabber_radius = m_grabber_connection_len * 0.85; m_snap_coarse_in_radius = m_grabber_radius / 3.0; @@ -1372,6 +1378,14 @@ void GLGizmoCut3D::init_picking_models() m_sphere.model.init_from(its); m_sphere.mesh_raycaster = std::make_unique(std::make_shared(std::move(its))); } + + if (!m_plane.model.is_initialized() && !m_hide_cut_plane && !m_connectors_editing) { + const double cp_width = 0.02 * get_grabber_mean_size(bounding_box()); + indexed_triangle_set its = its_make_frustum_dowel((double)m_cut_plane_radius_koef * m_radius, cp_width, m_cut_plane_as_circle ? 180 : 4); + m_plane.model.init_from(its); + m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(its))); + } + if (m_shapes.empty()) init_connector_shapes(); } @@ -1392,18 +1406,6 @@ void GLGizmoCut3D::init_rendering_items() } if (!m_angle_arc.is_initialized() || m_angle != 0.0) init_from_angle_arc(m_angle_arc, m_angle, m_grabber_connection_len); - - if (!m_plane.is_initialized() && !m_hide_cut_plane && !m_connectors_editing) { -#if 1 - const double cp_width = 0.02 * get_grabber_mean_size(bounding_box()); - m_plane.init_from(its_make_frustum_dowel((double)m_cut_plane_radius_koef * m_radius, cp_width, m_cut_plane_as_circle ? 180 : 4)); -#else - if (m_cut_plane_as_circle) - m_plane.init_from(its_make_frustum_dowel(2. * m_radius, 0.3, 180)); - else - m_plane.init_from(its_make_square_plane(float(m_radius))); -#endif - } } void GLGizmoCut3D::render_clipper_cut() @@ -1566,6 +1568,8 @@ void GLGizmoCut3D::render_connectors_input_window(CutConnectors &connectors) reset_connectors(); m_imgui->disabled_end(); + render_flip_plane_button(m_connectors_editing && connectors.empty()); + m_imgui->text(_L("Type")); bool type_changed = render_connect_type_radio_button(CutConnectorType::Plug); type_changed |= render_connect_type_radio_button(CutConnectorType::Dowel); @@ -1660,6 +1664,58 @@ void GLGizmoCut3D::set_connectors_editing(bool connectors_editing) m_parent.request_extra_frame(); } +void GLGizmoCut3D::flip_cut_plane() +{ + m_rotation_m = m_start_dragging_m * rotation_transform(PI * Vec3d::UnitX()); + + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Flip cut plane"), UndoRedo::SnapshotType::GizmoAction); + m_start_dragging_m = m_rotation_m; + + update_clipper(); +} + +void GLGizmoCut3D::render_flip_plane_button(bool disable_pred /*=false*/) +{ + ImGui::SameLine(2.5 * m_label_width); + + if (m_hover_id == CutPlane) + ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_ButtonHovered)); + + m_imgui->disabled_begin(disable_pred); + if (m_imgui->button(_L("Flip cut plane"))) + flip_cut_plane(); + m_imgui->disabled_end(); + + if (m_hover_id == CutPlane) + ImGui::PopStyleColor(); +} + +void GLGizmoCut3D::add_vertical_scaled_interval(float interval) +{ + ImGui::GetCurrentWindow()->DC.CursorPos.y += m_imgui->scaled(interval); +} + +void GLGizmoCut3D::add_horizontal_scaled_interval(float interval) +{ + ImGui::GetCurrentWindow()->DC.CursorPos.x += m_imgui->scaled(interval); +} + +void GLGizmoCut3D::add_horizontal_shift(float shift) +{ + ImGui::GetCurrentWindow()->DC.CursorPos.x += shift; +} + +void GLGizmoCut3D::render_color_marker(float size, const ImU32& color) +{ + ImGui::SameLine(); + const float radius = 0.5f * size; + ImVec2 pos = ImGui::GetCurrentWindow()->DC.CursorPos; + pos.x += size; + pos.y += 1.25f * radius; + ImGui::GetCurrentWindow()->DrawList->AddNgonFilled(pos, radius, color, 6); + ImGuiWrapper::text(" "); +} + void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors) { // WIP : cut plane mode @@ -1667,65 +1723,130 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors) if (m_mode == size_t(CutMode::cutPlanar)) { ImGui::AlignTextToFramePadding(); - m_imgui->text(wxString(ImGui::InfoMarkerSmall)); + ImGuiWrapper::text(wxString(ImGui::InfoMarkerSmall)); ImGui::SameLine(); - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, - get_wraped_wxString(_L("Hold SHIFT key and connect some two points of an object to cut by line"), 40)); + ImGuiWrapper::text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, + get_wraped_wxString(_L("Hold SHIFT key to draw a cut line"), 40)); ImGui::Separator(); render_build_size(); ImGui::AlignTextToFramePadding(); - m_imgui->text(_L("Cut position: ")); + ImGuiWrapper::text(_L("Cut position: ")); ImGui::SameLine(m_label_width); render_move_center_input(Z); ImGui::SameLine(); + const bool has_connectors = !connectors.empty(); + const bool is_cut_plane_init = m_rotation_m.isApprox(Transform3d::Identity()) && bounding_box().center() == m_plane_center; m_imgui->disabled_begin(is_cut_plane_init); - if (render_reset_button("cut_plane", _u8L("Reset cutting plane"))) - reset_cut_plane(); + if (render_reset_button("cut_plane", _u8L("Reset cutting plane"))) + reset_cut_plane(); m_imgui->disabled_end(); +// render_flip_plane_button(); + + add_vertical_scaled_interval(0.75f); + m_imgui->disabled_begin(!m_keep_upper || !m_keep_lower); - if (m_imgui->button(_L("Add/Edit connectors"))) + if (m_imgui->button(has_connectors ? _L("Edit connectors") : _L("Add connectors"))) set_connectors_editing(true); m_imgui->disabled_end(); + ImGui::SameLine(2.5f * m_label_width); + + m_imgui->disabled_begin(is_cut_plane_init && !has_connectors); + if (m_imgui->button(_L("Reset cut"), _L("Reset cutting plane and remove connectors"))) { + reset_cut_plane(); + reset_connectors(); + } + m_imgui->disabled_end(); + ImGui::Separator(); - float label_width = 0; - for (const wxString& label : {_L("Upper part"), _L("Lower part")}) { - const float width = m_imgui->calc_text_size(label).x + m_imgui->scaled(1.5f); - if (label_width < width) - label_width = width; + // render "After Cut" section + + ImVec2 label_size; + for (const auto& item : m_part_orientation_names) { + const ImVec2 text_size = ImGuiWrapper::calc_text_size(item.second); + if (label_size.x < text_size.x) + label_size.x = text_size.x; + if (label_size.y < text_size.y) + label_size.y = text_size.y; } - - auto render_part_action_line = [this, label_width, connectors](const wxString& label, const wxString& suffix, bool& keep_part, bool& place_on_cut_part, bool& rotate_part) { + const float h_shift = label_size.x + m_imgui->scaled(3.f); + const float marker_size = label_size.y; + + auto render_part_name = [this, marker_size, has_connectors](const wxString& name, bool& keep_part, const ImU32& color) { bool keep = true; - ImGui::AlignTextToFramePadding(); - m_imgui->text(label); + add_horizontal_shift(m_imgui->scaled(1.2f)); + m_imgui->checkbox((m_keep_as_parts ? _L("Part") : _L("Object")) + " " + name, has_connectors ? keep : keep_part); + render_color_marker(marker_size, color); + }; - ImGui::SameLine(label_width); - - m_imgui->disabled_begin(!connectors.empty()); - m_imgui->checkbox(_L("Keep") + suffix, connectors.empty() ? keep_part : keep); - m_imgui->disabled_end(); - - ImGui::SameLine(); - - m_imgui->disabled_begin(!keep_part); - if (m_imgui->checkbox(_L("Place on cut") + suffix, place_on_cut_part)) + auto render_part_actions = [this, h_shift] (const wxString& suffix, const bool& keep_part, bool& place_on_cut_part, bool& rotate_part) + { + float shift = m_imgui->scaled(1.2f); + if (suffix == "##lower") + shift += h_shift; + m_imgui->disabled_begin(!keep_part || m_keep_as_parts); + add_horizontal_shift(shift); + if (m_imgui->radio_button(m_part_orientation_names.at("none") + suffix, !place_on_cut_part && !rotate_part)) { rotate_part = false; - ImGui::SameLine(); - if (m_imgui->checkbox(_L("Flip") + suffix, rotate_part)) place_on_cut_part = false; + } + + add_horizontal_shift(shift); + if (m_imgui->radio_button(m_part_orientation_names.at("on_cut") + suffix, place_on_cut_part)) { + place_on_cut_part = !place_on_cut_part; + rotate_part = false; + } + + add_horizontal_shift(shift); + if (m_imgui->radio_button(m_part_orientation_names.at("flip") + suffix, rotate_part)) { + rotate_part = !rotate_part; + place_on_cut_part = false; + } m_imgui->disabled_end(); }; - m_imgui->text(_L("After cut") + ": "); - render_part_action_line( _L("Upper part"), "##upper", m_keep_upper, m_place_on_cut_upper, m_rotate_upper); - render_part_action_line( _L("Lower part"), "##lower", m_keep_lower, m_place_on_cut_lower, m_rotate_lower); + ImGuiWrapper::text(_L("After cut") + ": "); + add_vertical_scaled_interval(0.5f); + + m_imgui->disabled_begin(has_connectors || m_keep_as_parts); + render_part_name("A", m_keep_upper, m_imgui->to_ImU32(ABOVE_GRABBER_COLOR)); + ImGui::SameLine(h_shift + ImGui::GetCurrentWindow()->WindowPadding.x); + render_part_name("B", m_keep_lower, m_imgui->to_ImU32(BELOW_GRABBER_COLOR)); + m_imgui->disabled_end(); + + add_vertical_scaled_interval(0.5f); + + const ImVec2 pos = ImGui::GetCurrentWindow()->DC.CursorPos; + render_part_actions("##upper", m_keep_upper, m_place_on_cut_upper, m_rotate_upper); + + ImGui::GetCurrentWindow()->DC.CursorPos = pos; + render_part_actions("##lower", m_keep_lower, m_place_on_cut_lower, m_rotate_lower); + + add_vertical_scaled_interval(0.75f); + + m_imgui->disabled_begin(has_connectors); + add_horizontal_shift(m_imgui->scaled(/*1*/.2f)); + ImGuiWrapper::text(_L("Cut to") + ":"); + + ImGui::SameLine(); + if (m_imgui->radio_button(_L("Objects"), !m_keep_as_parts)) + m_keep_as_parts = false; + ImGui::SameLine(); + if (m_imgui->radio_button(_L("Parts"), m_keep_as_parts)) + m_keep_as_parts = true; + + if (m_keep_as_parts) { + m_keep_upper = m_keep_lower = true; + m_place_on_cut_upper = m_place_on_cut_lower = false; + m_rotate_upper = m_rotate_lower = false; + } + m_imgui->disabled_end(); } ImGui::Separator(); @@ -2110,6 +2231,7 @@ void GLGizmoCut3D::perform_cut(const Selection& selection) plater->cut(object_idx, instance_idx, translation_transform(cut_center_offset) * m_rotation_m, only_if(has_connectors ? true : m_keep_upper, ModelObjectCutAttribute::KeepUpper) | only_if(has_connectors ? true : m_keep_lower, ModelObjectCutAttribute::KeepLower) | + only_if(has_connectors ? false: m_keep_as_parts, ModelObjectCutAttribute::KeepAsParts) | only_if(m_place_on_cut_upper, ModelObjectCutAttribute::PlaceOnCutUpper) | only_if(m_place_on_cut_lower, ModelObjectCutAttribute::PlaceOnCutLower) | only_if(m_rotate_upper, ModelObjectCutAttribute::FlipUpper) | diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index 3483ae2015..3b7663171a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -6,6 +6,7 @@ #include "slic3r/GUI/GLModel.hpp" #include "libslic3r/TriangleMesh.hpp" #include "libslic3r/Model.hpp" +#include "imgui/imgui.h" namespace Slic3r { @@ -20,6 +21,14 @@ enum class SLAGizmoEventType : unsigned char; class GLGizmoCut3D : public GLGizmoBase { + enum GrabberID { + X = 0, + Y, + Z, + CutPlane, + Count, + }; + Transform3d m_rotation_m{ Transform3d::Identity() }; double m_snap_step{ 1.0 }; int m_connectors_group_id; @@ -57,10 +66,10 @@ class GLGizmoCut3D : public GLGizmoBase Vec2d m_ldown_mouse_position{ Vec2d::Zero() }; - GLModel m_plane; GLModel m_grabber_connection; GLModel m_cut_line; + PickingModel m_plane; PickingModel m_sphere; PickingModel m_cone; std::map m_shapes; @@ -90,6 +99,7 @@ class GLGizmoCut3D : public GLGizmoBase bool m_keep_upper{ true }; bool m_keep_lower{ true }; + bool m_keep_as_parts{ false }; bool m_place_on_cut_upper{ true }; bool m_place_on_cut_lower{ false }; bool m_rotate_upper{ false }; @@ -121,6 +131,7 @@ class GLGizmoCut3D : public GLGizmoBase GLSelectionRectangle m_selection_rectangle; bool m_has_invalid_connector{ false }; + bool m_was_cut_plane_dragged { false }; bool m_show_shortcuts{ false }; std::vector> m_shortcuts; @@ -154,6 +165,8 @@ class GLGizmoCut3D : public GLGizmoBase std::vector m_axis_names; + std::map m_part_orientation_names; + public: GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); @@ -192,7 +205,7 @@ protected: void on_set_hover_id() override; bool on_is_activable() const override; bool on_is_selectable() const override; - Vec3d mouse_position_in_local_plane(Axis axis, const Linef3&mouse_ray) const; + Vec3d mouse_position_in_local_plane(GrabberID axis, const Linef3&mouse_ray) const; void dragging_grabber_z(const GLGizmoBase::UpdateData &data); void dragging_grabber_xy(const GLGizmoBase::UpdateData &data); void dragging_connector(const GLGizmoBase::UpdateData &data); @@ -211,6 +224,12 @@ protected: void render_build_size(); void reset_cut_plane(); void set_connectors_editing(bool connectors_editing); + void flip_cut_plane(); + void render_flip_plane_button(bool disable_pred = false); + void add_vertical_scaled_interval(float interval); + void add_horizontal_scaled_interval(float interval); + void add_horizontal_shift(float shift); + void render_color_marker(float size, const ImU32& color); void render_cut_plane_input_window(CutConnectors &connectors); void init_input_window_data(CutConnectors &connectors); void render_input_window_warning() const; @@ -258,7 +277,7 @@ private: void render_cut_plane(); void render_model(GLModel& model, const ColorRGBA& color, Transform3d view_model_matrix); void render_line(GLModel& line_model, const ColorRGBA& color, Transform3d view_model_matrix, float width); - void render_rotation_snapping(Axis axis, const ColorRGBA& color); + void render_rotation_snapping(GrabberID axis, const ColorRGBA& color); void render_grabber_connection(const ColorRGBA& color, Transform3d view_matrix); void render_cut_plane_grabbers(); void render_cut_line(); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index c92f65f6b9..8908a5ef9d 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -453,10 +453,17 @@ void ImGuiWrapper::end() ImGui::End(); } -bool ImGuiWrapper::button(const wxString &label) +bool ImGuiWrapper::button(const wxString &label, const wxString& tooltip) { auto label_utf8 = into_u8(label); - return ImGui::Button(label_utf8.c_str()); + const bool ret = ImGui::Button(label_utf8.c_str()); + + if (!tooltip.IsEmpty() && ImGui::IsItemHovered()) { + auto tooltip_utf8 = into_u8(tooltip); + ImGui::SetTooltip(tooltip_utf8.c_str()); + } + + return ret; } bool ImGuiWrapper::button(const wxString& label, float width, float height) diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 3365954bab..4d8b4944cd 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -91,7 +91,7 @@ public: bool begin(const wxString& name, bool* close, int flags = 0); void end(); - bool button(const wxString &label); + bool button(const wxString &label, const wxString& tooltip = {}); bool button(const wxString& label, float width, float height); bool button(const wxString& label, const ImVec2 &size, bool enable); // default size = ImVec2(0.f, 0.f) bool radio_button(const wxString &label, bool active); From 224ee922c52334f944b709d600b8cd7f134d2a6d Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 9 Feb 2023 15:03:39 +0100 Subject: [PATCH 2/5] 'gouraud' shader modified to allow to draw an object with two different colors in Cut Gizmo --- resources/shaders/110/gouraud.fs | 24 ++++++++++++++++-------- resources/shaders/110/gouraud.vs | 4 ++++ resources/shaders/140/gouraud.fs | 24 ++++++++++++++++-------- resources/shaders/140/gouraud.vs | 4 ++++ resources/shaders/ES/gouraud.fs | 22 +++++++++++++++------- resources/shaders/ES/gouraud.vs | 4 ++++ src/slic3r/GUI/3DScene.cpp | 4 ++++ src/slic3r/GUI/3DScene.hpp | 10 ++++++++++ src/slic3r/GUI/GLCanvas3D.hpp | 4 ++++ src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 13 ++++++++++++- 10 files changed, 89 insertions(+), 24 deletions(-) diff --git a/resources/shaders/110/gouraud.fs b/resources/shaders/110/gouraud.fs index cf3163fa37..b9fa52bde5 100644 --- a/resources/shaders/110/gouraud.fs +++ b/resources/shaders/110/gouraud.fs @@ -24,6 +24,9 @@ struct SlopeDetection }; uniform vec4 uniform_color; +uniform bool use_color_clip_plane; +uniform vec4 uniform_color_clip_plane_1; +uniform vec4 uniform_color_clip_plane_2; uniform SlopeDetection slope; #ifdef ENABLE_ENVIRONMENT_MAP @@ -34,6 +37,7 @@ uniform SlopeDetection slope; uniform PrintVolumeDetection print_volume; varying vec3 clipping_planes_dots; +varying float color_clip_plane_dot; // x = diffuse, y = specular; varying vec2 intensity; @@ -46,12 +50,16 @@ void main() { if (any(lessThan(clipping_planes_dots, ZERO))) discard; - vec3 color = uniform_color.rgb; - float alpha = uniform_color.a; + + vec4 color; + if (use_color_clip_plane) + color = (color_clip_plane_dot < 0.0) ? uniform_color_clip_plane_1 : uniform_color_clip_plane_2; + else + color = uniform_color; if (slope.actived && world_normal_z < slope.normal_z - EPSILON) { - color = vec3(0.7, 0.7, 1.0); - alpha = 1.0; + color.rgb = vec3(0.7, 0.7, 1.0); + color.a = 1.0; } // if the fragment is outside the print volume -> use darker color @@ -67,13 +75,13 @@ void main() float delta_radius = print_volume.xy_data.z - distance(world_pos.xy, print_volume.xy_data.xy); pv_check_min = vec3(delta_radius, 0.0, world_pos.z - print_volume.z_data.x); pv_check_max = vec3(0.0, 0.0, world_pos.z - print_volume.z_data.y); - } - color = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color, ZERO, 0.3333) : color; + } + color.rgb = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color.rgb, ZERO, 0.3333) : color.rgb; #ifdef ENABLE_ENVIRONMENT_MAP if (use_environment_tex) - gl_FragColor = vec4(0.45 * texture2D(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color * intensity.x, alpha); + gl_FragColor = vec4(0.45 * texture(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color.rgb * intensity.x, color.a); else #endif - gl_FragColor = vec4(vec3(intensity.y) + color * intensity.x, alpha); + gl_FragColor = vec4(vec3(intensity.y) + color.rgb * intensity.x, color.a); } diff --git a/resources/shaders/110/gouraud.vs b/resources/shaders/110/gouraud.vs index 3a451fa79c..d076ca007f 100644 --- a/resources/shaders/110/gouraud.vs +++ b/resources/shaders/110/gouraud.vs @@ -35,6 +35,8 @@ uniform SlopeDetection slope; uniform vec2 z_range; // Clipping plane - general orientation. Used by the SLA gizmo. uniform vec4 clipping_plane; +// Color clip plane - general orientation. Used by the cut gizmo. +uniform vec4 color_clip_plane; attribute vec3 v_position; attribute vec3 v_normal; @@ -43,6 +45,7 @@ attribute vec3 v_normal; varying vec2 intensity; varying vec3 clipping_planes_dots; +varying float color_clip_plane_dot; varying vec4 world_pos; varying float world_normal_z; @@ -74,4 +77,5 @@ void main() gl_Position = projection_matrix * position; // Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded. clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z); + color_clip_plane_dot = dot(world_pos, color_clip_plane); } diff --git a/resources/shaders/140/gouraud.fs b/resources/shaders/140/gouraud.fs index d87e336321..f14bd5b861 100644 --- a/resources/shaders/140/gouraud.fs +++ b/resources/shaders/140/gouraud.fs @@ -24,6 +24,9 @@ struct SlopeDetection }; uniform vec4 uniform_color; +uniform bool use_color_clip_plane; +uniform vec4 uniform_color_clip_plane_1; +uniform vec4 uniform_color_clip_plane_2; uniform SlopeDetection slope; #ifdef ENABLE_ENVIRONMENT_MAP @@ -34,6 +37,7 @@ uniform SlopeDetection slope; uniform PrintVolumeDetection print_volume; in vec3 clipping_planes_dots; +in float color_clip_plane_dot; // x = diffuse, y = specular; in vec2 intensity; @@ -48,12 +52,16 @@ void main() { if (any(lessThan(clipping_planes_dots, ZERO))) discard; - vec3 color = uniform_color.rgb; - float alpha = uniform_color.a; + + vec4 color; + if (use_color_clip_plane) + color = (color_clip_plane_dot < 0.0) ? uniform_color_clip_plane_1 : uniform_color_clip_plane_2; + else + color = uniform_color; if (slope.actived && world_normal_z < slope.normal_z - EPSILON) { - color = vec3(0.7, 0.7, 1.0); - alpha = 1.0; + color.rgb = vec3(0.7, 0.7, 1.0); + color.a = 1.0; } // if the fragment is outside the print volume -> use darker color @@ -69,13 +77,13 @@ void main() float delta_radius = print_volume.xy_data.z - distance(world_pos.xy, print_volume.xy_data.xy); pv_check_min = vec3(delta_radius, 0.0, world_pos.z - print_volume.z_data.x); pv_check_max = vec3(0.0, 0.0, world_pos.z - print_volume.z_data.y); - } - color = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color, ZERO, 0.3333) : color; + } + color.rgb = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color.rgb, ZERO, 0.3333) : color.rgb; #ifdef ENABLE_ENVIRONMENT_MAP if (use_environment_tex) - out_color = vec4(0.45 * texture(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color * intensity.x, alpha); + out_color = vec4(0.45 * texture(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color.rgb * intensity.x, color.a); else #endif - out_color = vec4(vec3(intensity.y) + color * intensity.x, alpha); + out_color = vec4(vec3(intensity.y) + color.rgb * intensity.x, color.a); } diff --git a/resources/shaders/140/gouraud.vs b/resources/shaders/140/gouraud.vs index 83aa27b921..9274524380 100644 --- a/resources/shaders/140/gouraud.vs +++ b/resources/shaders/140/gouraud.vs @@ -35,6 +35,8 @@ uniform SlopeDetection slope; uniform vec2 z_range; // Clipping plane - general orientation. Used by the SLA gizmo. uniform vec4 clipping_plane; +// Color clip plane - general orientation. Used by the cut gizmo. +uniform vec4 color_clip_plane; in vec3 v_position; in vec3 v_normal; @@ -43,6 +45,7 @@ in vec3 v_normal; out vec2 intensity; out vec3 clipping_planes_dots; +out float color_clip_plane_dot; out vec4 world_pos; out float world_normal_z; @@ -74,4 +77,5 @@ void main() gl_Position = projection_matrix * position; // Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded. clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z); + color_clip_plane_dot = dot(world_pos, color_clip_plane); } diff --git a/resources/shaders/ES/gouraud.fs b/resources/shaders/ES/gouraud.fs index 368a502795..7369686647 100644 --- a/resources/shaders/ES/gouraud.fs +++ b/resources/shaders/ES/gouraud.fs @@ -26,6 +26,9 @@ struct SlopeDetection }; uniform vec4 uniform_color; +uniform bool use_color_clip_plane; +uniform vec4 uniform_color_clip_plane_1; +uniform vec4 uniform_color_clip_plane_2; uniform SlopeDetection slope; #ifdef ENABLE_ENVIRONMENT_MAP @@ -36,6 +39,7 @@ uniform SlopeDetection slope; uniform PrintVolumeDetection print_volume; varying vec3 clipping_planes_dots; +varying float color_clip_plane_dot; // x = diffuse, y = specular; varying vec2 intensity; @@ -48,12 +52,16 @@ void main() { if (any(lessThan(clipping_planes_dots, ZERO))) discard; - vec3 color = uniform_color.rgb; - float alpha = uniform_color.a; + + vec4 color; + if (use_color_clip_plane) + color = (color_clip_plane_dot < 0.0) ? uniform_color_clip_plane_1 : uniform_color_clip_plane_2; + else + color = uniform_color; if (slope.actived && world_normal_z < slope.normal_z - EPSILON) { - color = vec3(0.7, 0.7, 1.0); - alpha = 1.0; + color.rgb = vec3(0.7, 0.7, 1.0); + color.a = 1.0; } // if the fragment is outside the print volume -> use darker color @@ -70,12 +78,12 @@ void main() pv_check_min = vec3(delta_radius, 0.0, world_pos.z - print_volume.z_data.x); pv_check_max = vec3(0.0, 0.0, world_pos.z - print_volume.z_data.y); } - color = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color, ZERO, 0.3333) : color; + color.rgb = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color.rgb, ZERO, 0.3333) : color.rgb; #ifdef ENABLE_ENVIRONMENT_MAP if (use_environment_tex) - gl_FragColor = vec4(0.45 * texture2D(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color * intensity.x, alpha); + gl_FragColor = vec4(0.45 * texture(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color.rgb * intensity.x, color.a); else #endif - gl_FragColor = vec4(vec3(intensity.y) + color * intensity.x, alpha); + gl_FragColor = vec4(vec3(intensity.y) + color.rgb * intensity.x, color.a); } diff --git a/resources/shaders/ES/gouraud.vs b/resources/shaders/ES/gouraud.vs index 431e48556b..f5fa01e753 100644 --- a/resources/shaders/ES/gouraud.vs +++ b/resources/shaders/ES/gouraud.vs @@ -35,6 +35,8 @@ uniform SlopeDetection slope; uniform vec2 z_range; // Clipping plane - general orientation. Used by the SLA gizmo. uniform vec4 clipping_plane; +// Color clip plane - general orientation. Used by the cut gizmo. +uniform vec4 color_clip_plane; attribute vec3 v_position; attribute vec3 v_normal; @@ -43,6 +45,7 @@ attribute vec3 v_normal; varying vec2 intensity; varying vec3 clipping_planes_dots; +varying float color_clip_plane_dot; varying vec4 world_pos; varying float world_normal_z; @@ -74,4 +77,5 @@ void main() gl_Position = projection_matrix * position; // Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded. clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z); + color_clip_plane_dot = dot(world_pos, color_clip_plane); } diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 93e274d0d2..b070806f16 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -814,6 +814,10 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab shader->set_uniform("z_range", m_z_range); shader->set_uniform("clipping_plane", m_clipping_plane); + shader->set_uniform("use_color_clip_plane", m_use_color_clip_plane); + shader->set_uniform("color_clip_plane", m_color_clip_plane); + shader->set_uniform("uniform_color_clip_plane_1", m_color_clip_plane_colors[0]); + shader->set_uniform("uniform_color_clip_plane_2", m_color_clip_plane_colors[1]); shader->set_uniform("print_volume.type", static_cast(m_print_volume.type)); shader->set_uniform("print_volume.xy_data", m_print_volume.data); shader->set_uniform("print_volume.z_data", m_print_volume.zs); diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 4c19927ef3..5f2e5a27e3 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -387,6 +387,12 @@ private: // plane coeffs for clipping in shaders std::array m_clipping_plane; + // plane coeffs for render volumes with different colors in shaders + // used by cut gizmo + std::array m_color_clip_plane; + bool m_use_color_clip_plane{ false }; + std::array m_color_clip_plane_colors{ ColorRGBA::RED(), ColorRGBA::BLUE() }; + struct Slope { // toggle for slope rendering @@ -445,6 +451,10 @@ public: const std::array& get_z_range() const { return m_z_range; } const std::array& get_clipping_plane() const { return m_clipping_plane; } + void set_use_color_clip_plane(bool use) { m_use_color_clip_plane = use; } + void set_color_clip_plane(const std::array& coeffs) { m_color_clip_plane = coeffs; } + void set_color_clip_plane_colors(const std::array& colors) { m_color_clip_plane_colors = colors; } + bool is_slope_active() const { return m_slope.active; } void set_slope_active(bool active) { m_slope.active = active; } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 1f31808cd3..b6fd58ad33 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -712,6 +712,10 @@ public: bool get_use_clipping_planes() const { return m_use_clipping_planes; } const std::array &get_clipping_planes() const { return m_clipping_planes; }; + void set_use_color_clip_plane(bool use) { m_volumes.set_use_color_clip_plane(use); } + void set_color_clip_plane(const std::array& coeffs) { m_volumes.set_color_clip_plane(coeffs); } + void set_color_clip_plane_colors(const std::array& colors) { m_volumes.set_color_clip_plane_colors(colors); } + void refresh_camera_scene_box(); BoundingBoxf3 volumes_bounding_box() const; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 6fd74c2400..228a212f49 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -413,7 +413,7 @@ void GLGizmoCut3D::update_clipper() Vec3d normal = m_cut_normal = end - beg; m_cut_normal.normalize(); - if (!is_looking_forward()) { + if (!is_looking_forward() && m_connectors_editing) { end = beg = m_plane_center; beg[Z] = box.center().z() + m_radius; end[Z] = box.center().z() - m_radius; @@ -438,6 +438,13 @@ void GLGizmoCut3D::update_clipper() put_connectors_on_cut_plane(normal, offset); + std::array data = m_c->object_clipper()->get_clipping_plane(true)->get_data(); + // we need to invert the normal for the shader to work properly + for (int i = 0; i < 3; ++i) { + data[i] = -data[i]; + } + m_parent.set_color_clip_plane(data); + if (m_raycasters.empty()) on_register_raycasters_for_picking(); else @@ -901,6 +908,9 @@ std::string GLGizmoCut3D::on_get_name() const void GLGizmoCut3D::on_set_state() { if (m_state == On) { + m_parent.set_use_color_clip_plane(true); + m_parent.set_color_clip_plane_colors({ ABOVE_GRABBER_COLOR , BELOW_GRABBER_COLOR }); + update_bb(); m_connectors_editing = !m_selected.empty(); @@ -916,6 +926,7 @@ void GLGizmoCut3D::on_set_state() oc->release(); } m_selected.clear(); + m_parent.set_use_color_clip_plane(false); } force_update_clipper_on_render = m_state == On; } From 7755231866d8da9922732c88dc8b8db7335d35f8 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 14 Feb 2023 13:07:36 +0100 Subject: [PATCH 3/5] Cut: Fix for a normal for color clipping plane --- src/slic3r/GUI/3DScene.hpp | 6 +++- src/slic3r/GUI/GLCanvas3D.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 44 ++++++++++++++-------------- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 5f2e5a27e3..9791a0fafb 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -452,7 +452,11 @@ public: const std::array& get_clipping_plane() const { return m_clipping_plane; } void set_use_color_clip_plane(bool use) { m_use_color_clip_plane = use; } - void set_color_clip_plane(const std::array& coeffs) { m_color_clip_plane = coeffs; } + void set_color_clip_plane(const Vec3d& cp_normal, double offset) { + for (int i = 0; i < 3; ++i) + m_color_clip_plane[i] = -cp_normal[i]; + m_color_clip_plane[3] = offset; + } void set_color_clip_plane_colors(const std::array& colors) { m_color_clip_plane_colors = colors; } bool is_slope_active() const { return m_slope.active; } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index b6fd58ad33..f8f5a0efcd 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -713,7 +713,7 @@ public: const std::array &get_clipping_planes() const { return m_clipping_planes; }; void set_use_color_clip_plane(bool use) { m_volumes.set_use_color_clip_plane(use); } - void set_color_clip_plane(const std::array& coeffs) { m_volumes.set_color_clip_plane(coeffs); } + void set_color_clip_plane(const Vec3d& cp_normal, double offset) { m_volumes.set_color_clip_plane(cp_normal, offset); } void set_color_clip_plane_colors(const std::array& colors) { m_volumes.set_color_clip_plane_colors(colors); } void refresh_camera_scene_box(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 228a212f49..8b49ca6d3b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -21,8 +21,8 @@ namespace Slic3r { namespace GUI { static const ColorRGBA GRABBER_COLOR = ColorRGBA::YELLOW(); -static const ColorRGBA ABOVE_GRABBER_COLOR = ColorRGBA::CYAN(); -static const ColorRGBA BELOW_GRABBER_COLOR = ColorRGBA::MAGENTA(); +static const ColorRGBA UPPER_PART_COLOR = ColorRGBA::CYAN(); +static const ColorRGBA LOWER_PART_COLOR = ColorRGBA::MAGENTA(); // connector colors static const ColorRGBA PLAG_COLOR = ColorRGBA::YELLOW(); @@ -411,9 +411,18 @@ void GLGizmoCut3D::update_clipper() // calculate normal for cut plane Vec3d normal = m_cut_normal = end - beg; - m_cut_normal.normalize(); - if (!is_looking_forward() && m_connectors_editing) { + // calculate normal and offset for clipping plane + double dist = (m_plane_center - beg).norm(); + dist = std::clamp(dist, 0.0001, normal.norm()); + normal.normalize(); + m_clp_normal = normal; + double offset = normal.dot(beg) + dist; + + m_parent.set_color_clip_plane(normal, offset); + + if (!is_looking_forward()) { + // recalculate normal and offset for clipping plane, if camera is looking downward to cut plane end = beg = m_plane_center; beg[Z] = box.center().z() + m_radius; end[Z] = box.center().z() - m_radius; @@ -421,30 +430,21 @@ void GLGizmoCut3D::update_clipper() rotate_vec3d_around_plane_center(beg); rotate_vec3d_around_plane_center(end); - // recalculate normal for clipping plane, if camera is looking downward to cut plane normal = end - beg; if (normal == Vec3d::Zero()) return; - } - // calculate normal and offset for clipping plane - double dist = (m_plane_center - beg).norm(); - dist = std::clamp(dist, 0.0001, normal.norm()); - normal.normalize(); - m_clp_normal = normal; - const double offset = normal.dot(beg) + dist; + dist = (m_plane_center - beg).norm(); + dist = std::clamp(dist, 0.0001, normal.norm()); + normal.normalize(); + m_clp_normal = normal; + offset = normal.dot(beg) + dist; + } m_c->object_clipper()->set_range_and_pos(normal, offset, dist); put_connectors_on_cut_plane(normal, offset); - std::array data = m_c->object_clipper()->get_clipping_plane(true)->get_data(); - // we need to invert the normal for the shader to work properly - for (int i = 0; i < 3; ++i) { - data[i] = -data[i]; - } - m_parent.set_color_clip_plane(data); - if (m_raycasters.empty()) on_register_raycasters_for_picking(); else @@ -909,7 +909,7 @@ void GLGizmoCut3D::on_set_state() { if (m_state == On) { m_parent.set_use_color_clip_plane(true); - m_parent.set_color_clip_plane_colors({ ABOVE_GRABBER_COLOR , BELOW_GRABBER_COLOR }); + m_parent.set_color_clip_plane_colors({ UPPER_PART_COLOR , LOWER_PART_COLOR }); update_bb(); m_connectors_editing = !m_selected.empty(); @@ -1826,9 +1826,9 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors) add_vertical_scaled_interval(0.5f); m_imgui->disabled_begin(has_connectors || m_keep_as_parts); - render_part_name("A", m_keep_upper, m_imgui->to_ImU32(ABOVE_GRABBER_COLOR)); + render_part_name("A", m_keep_upper, m_imgui->to_ImU32(UPPER_PART_COLOR)); ImGui::SameLine(h_shift + ImGui::GetCurrentWindow()->WindowPadding.x); - render_part_name("B", m_keep_lower, m_imgui->to_ImU32(BELOW_GRABBER_COLOR)); + render_part_name("B", m_keep_lower, m_imgui->to_ImU32(LOWER_PART_COLOR)); m_imgui->disabled_end(); add_vertical_scaled_interval(0.5f); From 8c28b60125942540c031eb9beeb661915e0e4815 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 14 Feb 2023 11:15:02 +0100 Subject: [PATCH 4/5] Follow-up of d02dd9a3b5edc5668fb8535483f91bf3f87cd548 - Fixed rendering of modifiers in Cut Gizmo --- resources/shaders/110/gouraud.fs | 6 ++++-- resources/shaders/140/gouraud.fs | 6 ++++-- resources/shaders/ES/gouraud.fs | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/resources/shaders/110/gouraud.fs b/resources/shaders/110/gouraud.fs index b9fa52bde5..21ca4d6d25 100644 --- a/resources/shaders/110/gouraud.fs +++ b/resources/shaders/110/gouraud.fs @@ -52,8 +52,10 @@ void main() discard; vec4 color; - if (use_color_clip_plane) - color = (color_clip_plane_dot < 0.0) ? uniform_color_clip_plane_1 : uniform_color_clip_plane_2; + if (use_color_clip_plane) { + color.rgb = (color_clip_plane_dot < 0.0) ? uniform_color_clip_plane_1.rgb : uniform_color_clip_plane_2.rgb; + color.a = uniform_color.a; + } else color = uniform_color; diff --git a/resources/shaders/140/gouraud.fs b/resources/shaders/140/gouraud.fs index f14bd5b861..44851a4de3 100644 --- a/resources/shaders/140/gouraud.fs +++ b/resources/shaders/140/gouraud.fs @@ -54,8 +54,10 @@ void main() discard; vec4 color; - if (use_color_clip_plane) - color = (color_clip_plane_dot < 0.0) ? uniform_color_clip_plane_1 : uniform_color_clip_plane_2; + if (use_color_clip_plane) { + color.rgb = (color_clip_plane_dot < 0.0) ? uniform_color_clip_plane_1.rgb : uniform_color_clip_plane_2.rgb; + color.a = uniform_color.a; + } else color = uniform_color; diff --git a/resources/shaders/ES/gouraud.fs b/resources/shaders/ES/gouraud.fs index 7369686647..ddc2e0718c 100644 --- a/resources/shaders/ES/gouraud.fs +++ b/resources/shaders/ES/gouraud.fs @@ -54,8 +54,10 @@ void main() discard; vec4 color; - if (use_color_clip_plane) - color = (color_clip_plane_dot < 0.0) ? uniform_color_clip_plane_1 : uniform_color_clip_plane_2; + if (use_color_clip_plane) { + color.rgb = (color_clip_plane_dot < 0.0) ? uniform_color_clip_plane_1.rgb : uniform_color_clip_plane_2.rgb; + color.a = uniform_color.a; + } else color = uniform_color; From ffd484eb04ace2ac73ae3c5f06f3e728de978de5 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 14 Feb 2023 14:13:25 +0100 Subject: [PATCH 5/5] Cut bug fixing: * Disable "Add/Edit connectors" button then cut to parts * Fixed flip_cut_plane() * Fixed cut by Line, when draw line over the cut plane * Fixed apply of the transformations, when cut to parts Cut improvements: * Process "Ctrl" * Change color of the cut plane when it's hovered * Don't apply Cut information for result object(s), if cut doesn't have any connector or is cut to parts (partially related to #9633 - Add option to Invalidate Cut Info at the time of cutting) --- src/libslic3r/Model.cpp | 19 +++++++++++-------- src/libslic3r/Model.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 20 +++++++++++++------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 9c074ef1e9..ca4b355d80 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1305,7 +1305,9 @@ void ModelObject::synchronize_model_after_cut() void ModelObject::apply_cut_attributes(ModelObjectCutAttributes attributes) { // we don't save cut information, if result will not contains all parts of initial object - if (!attributes.has(ModelObjectCutAttribute::KeepUpper) || !attributes.has(ModelObjectCutAttribute::KeepLower)) + if (!attributes.has(ModelObjectCutAttribute::KeepUpper) || + !attributes.has(ModelObjectCutAttribute::KeepLower) || + attributes.has(ModelObjectCutAttribute::InvalidateCutInfo)) return; if (cut_id.id().invalid()) @@ -1425,7 +1427,7 @@ void ModelObject::process_modifier_cut(ModelVolume* volume, const Transform3d& i lower->add_volume(*volume); } -static void add_cut_volume(TriangleMesh& mesh, ModelObject* object, const ModelVolume* src_volume, const Transform3d& cut_matrix) +static void add_cut_volume(TriangleMesh& mesh, ModelObject* object, const ModelVolume* src_volume, const Transform3d& cut_matrix, const std::string& suffix = {}) { if (mesh.empty()) return; @@ -1433,7 +1435,7 @@ static void add_cut_volume(TriangleMesh& mesh, ModelObject* object, const ModelV mesh.transform(cut_matrix); ModelVolume* vol = object->add_volume(mesh); - vol->name = src_volume->name; + vol->name = src_volume->name + suffix; // Don't copy the config's ID. vol->config.assign_config(src_volume->config); assert(vol->config.id().valid()); @@ -1478,8 +1480,8 @@ void ModelObject::process_solid_part_cut(ModelVolume* volume, const Transform3d& // Add required cut parts to the objects if (attributes.has(ModelObjectCutAttribute::KeepAsParts)) { - add_cut_volume(lower_mesh, lower, volume, cut_matrix); - add_cut_volume(upper_mesh, lower, volume, cut_matrix); + add_cut_volume(upper_mesh, upper, volume, cut_matrix, "_A"); + add_cut_volume(lower_mesh, upper, volume, cut_matrix, "_B"); return; } @@ -1566,7 +1568,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, const Transform3d& cut_matrix, clone_for_cut(&upper); ModelObject* lower{ nullptr }; - if (attributes.has(ModelObjectCutAttribute::KeepLower)) + if (attributes.has(ModelObjectCutAttribute::KeepLower) && !attributes.has(ModelObjectCutAttribute::KeepAsParts)) clone_for_cut(&lower); std::vector dowels; @@ -1614,8 +1616,9 @@ ModelObjectPtrs ModelObject::cut(size_t instance, const Transform3d& cut_matrix, ModelObjectPtrs res; - if (attributes.has(ModelObjectCutAttribute::KeepAsParts) && !lower->volumes.empty()) { - res.push_back(lower); + if (attributes.has(ModelObjectCutAttribute::KeepAsParts) && !upper->volumes.empty()) { + reset_instance_transformation(upper, instance, cut_matrix); + res.push_back(upper); } else { if (attributes.has(ModelObjectCutAttribute::KeepUpper) && !upper->volumes.empty()) { diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index a1ae950d18..0e47cbe5c5 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -316,7 +316,7 @@ enum class ModelVolumeType : int { SUPPORT_ENFORCER, }; -enum class ModelObjectCutAttribute : int { KeepUpper, KeepLower, KeepAsParts, FlipUpper, FlipLower, PlaceOnCutUpper, PlaceOnCutLower, CreateDowels }; +enum class ModelObjectCutAttribute : int { KeepUpper, KeepLower, KeepAsParts, FlipUpper, FlipLower, PlaceOnCutUpper, PlaceOnCutLower, CreateDowels, InvalidateCutInfo }; using ModelObjectCutAttributes = enum_bitmask; ENABLE_ENUM_BITMASK_OPERATORS(ModelObjectCutAttribute); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 8b49ca6d3b..fa2df0c617 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -277,6 +277,8 @@ bool GLGizmoCut3D::on_mouse(const wxMouseEvent &mouse_event) if (mouse_event.ShiftDown() && mouse_event.LeftDown()) return gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), mouse_event.CmdDown()); + if (mouse_event.CmdDown() && mouse_event.LeftDown()) + return false; if (cut_line_processing()) { if (mouse_event.ShiftDown()) { if (mouse_event.Moving()|| mouse_event.Dragging()) @@ -682,8 +684,12 @@ void GLGizmoCut3D::render_cut_plane() shader->set_uniform("view_model_matrix", view_model_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - if (can_perform_cut() && has_valid_contour()) - m_plane.model.set_color({ 0.8f, 0.8f, 0.8f, 0.5f }); + if (can_perform_cut() && has_valid_contour()) { + if (m_hover_id == CutPlane) + m_plane.model.set_color({ 0.9f, 0.9f, 0.9f, 0.5f }); + else + m_plane.model.set_color({ 0.8f, 0.8f, 0.8f, 0.5f }); + } else m_plane.model.set_color({ 1.0f, 0.8f, 0.8f, 0.5f }); m_plane.model.render(); @@ -1677,8 +1683,7 @@ void GLGizmoCut3D::set_connectors_editing(bool connectors_editing) void GLGizmoCut3D::flip_cut_plane() { - m_rotation_m = m_start_dragging_m * rotation_transform(PI * Vec3d::UnitX()); - + m_rotation_m = m_rotation_m * rotation_transform(PI * Vec3d::UnitX()); Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Flip cut plane"), UndoRedo::SnapshotType::GizmoAction); m_start_dragging_m = m_rotation_m; @@ -1760,7 +1765,7 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors) add_vertical_scaled_interval(0.75f); - m_imgui->disabled_begin(!m_keep_upper || !m_keep_lower); + m_imgui->disabled_begin(!m_keep_upper || !m_keep_lower || m_keep_as_parts); if (m_imgui->button(has_connectors ? _L("Edit connectors") : _L("Add connectors"))) set_connectors_editing(true); m_imgui->disabled_end(); @@ -2247,7 +2252,8 @@ void GLGizmoCut3D::perform_cut(const Selection& selection) only_if(m_place_on_cut_lower, ModelObjectCutAttribute::PlaceOnCutLower) | only_if(m_rotate_upper, ModelObjectCutAttribute::FlipUpper) | only_if(m_rotate_lower, ModelObjectCutAttribute::FlipLower) | - only_if(create_dowels_as_separate_object, ModelObjectCutAttribute::CreateDowels)); + only_if(create_dowels_as_separate_object, ModelObjectCutAttribute::CreateDowels) | + only_if(!has_connectors, ModelObjectCutAttribute::InvalidateCutInfo)); } } @@ -2482,7 +2488,7 @@ bool GLGizmoCut3D::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_posi if (is_dragging() || m_connector_mode == CutConnectorMode::Auto) return false; - if ( m_hover_id < 0 && shift_down && ! m_connectors_editing && + if ( (m_hover_id < 0 || m_hover_id == CutPlane) && shift_down && ! m_connectors_editing && (action == SLAGizmoEventType::LeftDown || action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::Moving) ) return process_cut_line(action, mouse_position);