diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index e089145c57..dc2a57b050 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -293,25 +293,26 @@ struct CutConnector float height; float radius_tolerance;// [0.f : 1.f] float height_tolerance;// [0.f : 1.f] + float z_angle {0.f}; CutConnectorAttributes attribs; CutConnector() - : pos(Vec3d::Zero()), rotation_m(Transform3d::Identity()), radius(5.f), height(10.f), radius_tolerance(0.f), height_tolerance(0.1f) + : pos(Vec3d::Zero()), rotation_m(Transform3d::Identity()), radius(5.f), height(10.f), radius_tolerance(0.f), height_tolerance(0.1f), z_angle(0.f) {} - CutConnector(Vec3d p, Transform3d rot, float r, float h, float rt, float ht, CutConnectorAttributes attributes) - : pos(p), rotation_m(rot), radius(r), height(h), radius_tolerance(rt), height_tolerance(ht), attribs(attributes) + CutConnector(Vec3d p, Transform3d rot, float r, float h, float rt, float ht, float za, CutConnectorAttributes attributes) + : pos(p), rotation_m(rot), radius(r), height(h), radius_tolerance(rt), height_tolerance(ht), z_angle(za), attribs(attributes) {} CutConnector(const CutConnector& rhs) : - CutConnector(rhs.pos, rhs.rotation_m, rhs.radius, rhs.height, rhs.radius_tolerance, rhs.height_tolerance, rhs.attribs) {} + CutConnector(rhs.pos, rhs.rotation_m, rhs.radius, rhs.height, rhs.radius_tolerance, rhs.height_tolerance, rhs.z_angle, rhs.attribs) {} bool operator==(const CutConnector& other) const; bool operator!=(const CutConnector& other) const { return !(other == (*this)); } template inline void serialize(Archive& ar) { - ar(pos, rotation_m, radius, height, radius_tolerance, height_tolerance, attribs); + ar(pos, rotation_m, radius, height, radius_tolerance, height_tolerance, z_angle, attribs); } }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index e52e4c789c..e96e4b37a0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -231,6 +231,7 @@ GLGizmoCut3D::GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, {"Shape" , _u8L("Shape")}, {"Depth" , _u8L("Depth")}, {"Size" , _u8L("Size")}, + {"Rotation" , _u8L("Rotation")}, {"Groove" , _u8L("Groove")}, {"Width" , _u8L("Width")}, {"Flap Angle" , _u8L("Flap Angle")}, @@ -2329,6 +2330,11 @@ void GLGizmoCut3D::render_connectors_input_window(CutConnectors &connectors) connectors[idx].radius_tolerance = 0.5f * m_connector_size_tolerance; }); + if (render_angle_input(m_labels_map["Rotation"], m_connector_angle, 0.f, 0.f, 180.f)) + apply_selected_connectors([this, &connectors](size_t idx) { + connectors[idx].z_angle = m_connector_angle; + }); + if (m_connector_type == CutConnectorType::Snap) { render_snap_specific_input(_u8L("Bulge"), _L("Bulge proportion related to radius"), m_snap_bulge_proportion, 0.15f, 5.f, 100.f * m_snap_space_proportion); render_snap_specific_input(_u8L("Space"), _L("Space proportion related to radius"), m_snap_space_proportion, 0.3f, 10.f, 50.f); @@ -2538,7 +2544,7 @@ void GLGizmoCut3D::render_groove_float_input(const std::string& label, float& in } } -void GLGizmoCut3D::render_groove_angle_input(const std::string& label, float& in_val, const float& init_val, float min_val, float max_val) +bool GLGizmoCut3D::render_angle_input(const std::string& label, float& in_val, const float& init_val, float min_val, float max_val) { bool is_changed{ false }; @@ -2551,14 +2557,15 @@ void GLGizmoCut3D::render_groove_angle_input(const std::string& label, float& in const float old_val = val; const std::string format = "%.0f " + _u8L("°"); - m_imgui->slider_float(("##groove_" + label).c_str(), &val, min_val, max_val, format.c_str(), 1.f, true, from_u8(label)); + m_imgui->slider_float(("##angle_" + label).c_str(), &val, min_val, max_val, format.c_str(), 1.f, true, from_u8(label)); m_is_slider_editing_done |= m_imgui->get_last_slider_status().deactivated_after_edit; if (!is_approx(old_val, val)) { if (m_imgui->get_last_slider_status().can_take_snapshot) { - Plater::TakeSnapshot snapshot(wxGetApp().plater(), format_wxstr("%1%: %2%", _L("Groove change"), label), UndoRedo::SnapshotType::GizmoAction); + Plater::TakeSnapshot snapshot(wxGetApp().plater(), format_wxstr("%1%: %2%", _L("Edited"), label), UndoRedo::SnapshotType::GizmoAction); m_imgui->get_last_slider_status().invalidate_snapshot(); - m_groove_editing = true; + if (m_mode == size_t(CutMode::cutTongueAndGroove)) + m_groove_editing = true; } in_val = deg2rad(val); is_changed = true; @@ -2568,14 +2575,19 @@ void GLGizmoCut3D::render_groove_angle_input(const std::string& label, float& in m_imgui->disabled_begin(is_approx(in_val, init_val)); const std::string act_name = _u8L("Reset"); - if (render_reset_button(("##groove_" + label + act_name).c_str(), act_name)) { + if (render_reset_button(("##angle_" + label + act_name).c_str(), act_name)) { Plater::TakeSnapshot snapshot(wxGetApp().plater(), format_wxstr("%1%: %2%", act_name, label), UndoRedo::SnapshotType::GizmoAction); in_val = init_val; is_changed = true; } m_imgui->disabled_end(); - if (is_changed) { + return is_changed; +} + +void GLGizmoCut3D::render_groove_angle_input(const std::string& label, float& in_val, const float& init_val, float min_val, float max_val) +{ + if (render_angle_input(label, in_val, init_val, min_val, max_val)) { update_plane_model(); reset_cut_by_contours(); } @@ -2793,6 +2805,8 @@ void GLGizmoCut3D::validate_connector_settings() m_connector_size = 2.5f; if (m_connector_size_tolerance < 0.f) m_connector_size_tolerance = 0.f; + if (m_connector_angle < 0.f || m_connector_angle > float(PI) ) + m_connector_angle = 0.f; if (m_connector_type == CutConnectorType::Undef) m_connector_type = CutConnectorType::Plug; @@ -2812,6 +2826,7 @@ void GLGizmoCut3D::init_input_window_data(CutConnectors &connectors) float depth_ratio_tolerance { UndefFloat }; float radius { UndefFloat }; float radius_tolerance { UndefFloat }; + float angle { UndefFloat }; CutConnectorType type { CutConnectorType::Undef }; CutConnectorStyle style { CutConnectorStyle::Undef }; CutConnectorShape shape { CutConnectorShape::Undef }; @@ -2825,6 +2840,7 @@ void GLGizmoCut3D::init_input_window_data(CutConnectors &connectors) depth_ratio_tolerance = connector.height_tolerance; radius = connector.radius; radius_tolerance = connector.radius_tolerance; + angle = connector.z_angle; type = connector.attribs.type; style = connector.attribs.style; shape = connector.attribs.shape; @@ -2842,6 +2858,8 @@ void GLGizmoCut3D::init_input_window_data(CutConnectors &connectors) radius = UndefFloat; if (!is_approx(radius_tolerance, connector.radius_tolerance)) radius_tolerance = UndefFloat; + if (!is_approx(angle, connector.z_angle)) + angle = UndefFloat; if (type != connector.attribs.type) type = CutConnectorType::Undef; @@ -2857,6 +2875,7 @@ void GLGizmoCut3D::init_input_window_data(CutConnectors &connectors) m_connector_size = 2.f * radius; m_connector_size_tolerance = 2.f * radius_tolerance; m_connector_type = type; + m_connector_angle = angle; m_connector_style = int(style); m_connector_shape_id = int(shape); } @@ -3108,7 +3127,8 @@ void GLGizmoCut3D::render_connectors() else if (!looking_forward) pos += 0.05 * m_clp_normal; - const Transform3d view_model_matrix = camera.get_view_matrix() * translation_transform(pos) * m_rotation_m * + const Transform3d view_model_matrix = camera.get_view_matrix() * translation_transform(pos) * m_rotation_m * + rotation_transform(-connector.z_angle * Vec3d::UnitZ()) * scale_transform(Vec3f(connector.radius, connector.radius, height).cast()); render_model(m_shapes[connector.attribs].model, render_color, view_model_matrix); @@ -3511,6 +3531,7 @@ bool GLGizmoCut3D::add_connector(CutConnectors& connectors, const Vec2d& mouse_p connectors.emplace_back(pos, m_rotation_m, m_connector_size * 0.5f, m_connector_depth_ratio, m_connector_size_tolerance * 0.5f, m_connector_depth_ratio_tolerance, + m_connector_angle, CutConnectorAttributes( CutConnectorType(m_connector_type), CutConnectorStyle(m_connector_style), CutConnectorShape(m_connector_shape_id))); @@ -3735,6 +3756,7 @@ void GLGizmoCut3D::apply_cut_connectors(ModelObject* mo, const std::string& conn // Transform the new modifier to be aligned inside the instance new_volume->set_transformation(translation_transform(connector.pos) * connector.rotation_m * + rotation_transform(-connector.z_angle * Vec3d::UnitZ()) * scale_transform(Vec3f(connector.radius, connector.radius, connector.height).cast())); new_volume->cut_info = { connector.attribs.type, connector.radius_tolerance, connector.height_tolerance }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index dc4b784b79..89c1b92833 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -138,6 +138,7 @@ class GLGizmoCut3D : public GLGizmoBase float m_connector_depth_ratio{ 3.f }; float m_connector_size{ 2.5f }; + float m_connector_angle{ 0.f }; float m_connector_depth_ratio_tolerance{ 0.1f }; float m_connector_size_tolerance{ 0.f }; @@ -306,6 +307,7 @@ protected: void render_color_marker(float size, const ImU32& color); void render_groove_float_input(const std::string &label, float &in_val, const float &init_val, float &in_tolerance); void render_groove_angle_input(const std::string &label, float &in_val, const float &init_val, float min_val, float max_val); + bool render_angle_input(const std::string& label, float& in_val, const float& init_val, float min_val, float max_val); void render_snap_specific_input(const std::string& label, const wxString& tooltip, float& in_val, const float& init_val, const float min_val, const float max_val); void render_cut_plane_input_window(CutConnectors &connectors); void init_input_window_data(CutConnectors &connectors);