From df0a49a73d1c61ba6cfbebb61ea7719d8e8ab532 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Thu, 9 Nov 2023 20:54:33 +0800 Subject: [PATCH 1/9] Fix retraction issues --- src/libslic3r/Extruder.hpp | 5 ++--- src/libslic3r/GCode.hpp | 2 +- src/libslic3r/GCodeWriter.cpp | 6 +++--- src/libslic3r/libslic3r.h | 6 ++++++ 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/Extruder.hpp b/src/libslic3r/Extruder.hpp index aa33891eee..d5066f91ec 100644 --- a/src/libslic3r/Extruder.hpp +++ b/src/libslic3r/Extruder.hpp @@ -22,9 +22,8 @@ public: } else { m_E = 0; m_retracted = 0; - m_restart_extra = 0; } - + m_restart_extra = 0; m_absolute_E = 0; } @@ -34,7 +33,7 @@ public: double retract(double length, double restart_extra); double unretract(); double E() const { return m_share_extruder ? m_share_E : m_E; } - void reset_E() { m_E = 0.; m_share_E = 0.; } + void reset_E() { reset(); } double e_per_mm(double mm3_per_mm) const { return mm3_per_mm * m_e_per_mm3; } double e_per_mm3() const { return m_e_per_mm3; } // Used filament volume in mm^3. diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 08c806a581..9fc63f63be 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -213,7 +213,7 @@ public: std::string travel_to(const Point& point, ExtrusionRole role, std::string comment); bool needs_retraction(const Polyline& travel, ExtrusionRole role, LiftType& lift_type); - std::string retract(bool toolchange = false, bool is_last_retraction = false, LiftType lift_type = LiftType::SpiralLift); + std::string retract(bool toolchange = false, bool is_last_retraction = false, LiftType lift_type = LiftType::NormalLift); std::string unretract() { return m_writer.unlift() + m_writer.unretract(); } std::string set_extruder(unsigned int extruder_id, double print_z); bool is_BBL_Printer(); diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index d93a8af119..76ac289ae7 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -320,7 +320,7 @@ std::string GCodeWriter::reset_e(bool force) return ""; if (m_extruder != nullptr) { - if (m_extruder->E() == 0. && ! force) + if (is_zero(m_extruder->E()) && ! force) return ""; m_extruder->reset_E(); } @@ -709,7 +709,7 @@ std::string GCodeWriter::_retract(double length, double restart_extra, const std length = 1; std::string gcode; - if (double dE = m_extruder->retract(length, restart_extra); dE != 0) { + if (double dE = m_extruder->retract(length, restart_extra); !is_zero(dE)) { if (this->config.use_firmware_retraction) { gcode = FLAVOR_IS(gcfMachinekit) ? "G22 ; retract\n" : "G10 ; retract\n"; } @@ -737,7 +737,7 @@ std::string GCodeWriter::unretract() if (FLAVOR_IS(gcfMakerWare)) gcode = "M101 ; extruder on\n"; - if (double dE = m_extruder->unretract(); dE != 0) { + if (double dE = m_extruder->unretract(); !is_zero(dE)) { if (this->config.use_firmware_retraction) { gcode += FLAVOR_IS(gcfMachinekit) ? "G23 ; unretract\n" : "G11 ; unretract\n"; gcode += this->reset_e(); diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h index ea218dced5..fa59415d4f 100644 --- a/src/libslic3r/libslic3r.h +++ b/src/libslic3r/libslic3r.h @@ -278,6 +278,12 @@ constexpr inline T sqr(T x) return x * x; } +template constexpr +inline bool is_zero(Number value) +{ + return std::fabs(double(value)) < 1e-6; +} + template constexpr inline T lerp(const T& a, const T& b, Number t) { From 22abe8cc9d74ea36ed3f229edd94aaa5ead09dea Mon Sep 17 00:00:00 2001 From: SoftFever Date: Thu, 9 Nov 2023 22:09:41 +0800 Subject: [PATCH 2/9] Automatically recover from corrupted config file --- src/slic3r/GUI/GUI_App.cpp | 17 ++++++++++++----- src/slic3r/GUI/GUI_App.hpp | 1 + 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index b49dda3fbd..b9d3a8cd74 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -2122,16 +2122,15 @@ void GUI_App::init_app_config() app_config = new AppConfig(); //app_config = new AppConfig(is_editor() ? AppConfig::EAppMode::Editor : AppConfig::EAppMode::GCodeViewer); + m_config_corrupted = false; // load settings m_app_conf_exists = app_config->exists(); if (m_app_conf_exists) { std::string error = app_config->load(); if (!error.empty()) { - // Error while parsing config file. We'll customize the error message and rethrow to be displayed. - throw Slic3r::RuntimeError( - _u8L("OrcaSlicer configuration file may be corrupted and is not abled to be parsed." - "Please delete the file and try again.") + - "\n\n" + app_config->config_path() + "\n\n" + error); + // Orca: if the config file is corrupted, we will show a error dialog and create a default config file. + m_config_corrupted = true; + } // Save orig_version here, so its empty if no app_config existed before this run. m_last_config_version = app_config->orig_version();//parse_semver_from_ini(app_config->config_path()); @@ -2748,6 +2747,7 @@ bool GUI_App::on_init_inner() if (m_post_initialized && app_config->dirty()) app_config->save(); + }); m_initialized = true; @@ -2755,6 +2755,13 @@ bool GUI_App::on_init_inner() flush_logs(); BOOST_LOG_TRIVIAL(info) << "finished the gui app init"; + if (m_config_corrupted) { + m_config_corrupted = false; + show_error(nullptr, + _u8L( + "The OrcaSlicer configuration file may be corrupted and cannot be parsed.\nOrcaSlicer has attempted to recreate the " + "configuration file.\nPlease note, application settings will be lost, but printer profiles will not be affected.")); + } //BBS: delete splash screen delete scrn; return true; diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 44411b361c..2defd53a5d 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -656,6 +656,7 @@ private: bool m_datadir_redefined { false }; std::string m_older_data_dir_path; boost::optional m_last_config_version; + bool m_config_corrupted { false }; }; DECLARE_APP(GUI_App) From cd8f555714cbb42462555ab20bfb5906e6bb3931 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Thu, 9 Nov 2023 22:19:40 +0800 Subject: [PATCH 3/9] Fix some gui issues (#2653) * Fix text gizmo input dialog caption alignment * Fix issue that layer slider top/bottom label left edge been cut by draw region (#2603) --- src/slic3r/GUI/Gizmos/GLGizmoText.cpp | 43 +++++++++++++++++---------- src/slic3r/GUI/IMSlider.cpp | 2 +- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp index 553b477b32..8726d73146 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp @@ -147,6 +147,17 @@ bool GLGizmoText::on_init() reset_text_info(); + m_desc["font"] = _L("Font"); + m_desc["size"] = _L("Size"); + m_desc["thickness"] = _L("Thickness"); + m_desc["text_gap"] = _L("Text Gap"); + m_desc["angle"] = _L("Angle"); + m_desc["embeded_depth"] = _L("Embeded\ndepth"); + m_desc["input_text"] = _L("Input text"); + + m_desc["surface"] = _L("Surface"); + m_desc["horizontal_text"] = _L("Horizontal text"); + m_desc["rotate_text_caption"] = _L("Shift + Mouse move up or dowm"); m_desc["rotate_text"] = _L("Rotate text"); @@ -669,13 +680,13 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) ImGui::PushStyleVar(ImGuiStyleVar_ScrollbarSize, 4.0f * currt_scale); GizmoImguiBegin("Text", ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar); - float space_size = m_imgui->get_style_scaling() * 8; - float font_cap = m_imgui->calc_text_size(_L("Font")).x; - float size_cap = m_imgui->calc_text_size(_L("Size")).x; - float thickness_cap = m_imgui->calc_text_size(_L("Thickness")).x; - float input_cap = m_imgui->calc_text_size(_L("Input text")).x; - float depth_cap = m_imgui->calc_text_size(_L("Embeded")).x; - float caption_size = std::max(std::max(font_cap, size_cap), std::max(depth_cap, input_cap)) + space_size + ImGui::GetStyle().WindowPadding.x; + const float space_size = m_imgui->get_style_scaling() * 8; + const std::array cap_array = std::array{ "font", "size", "thickness", "text_gap", "angle", "embeded_depth", "input_text" }; + float caption_size = 0.0f; + for (const auto &t : cap_array) { + caption_size = std::max(caption_size, m_imgui->calc_text_size(m_desc[t]).x); + } + caption_size += space_size + ImGui::GetStyle().WindowPadding.x; float input_text_size = m_imgui->scaled(10.0f); float button_size = ImGui::GetFrameHeight(); @@ -702,7 +713,7 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) ImGui::AlignTextToFramePadding(); - m_imgui->text(_L("Font")); + m_imgui->text(m_desc["font"]); ImGui::SameLine(caption_size); ImGui::PushItemWidth(list_width); push_combo_style(currt_scale); @@ -742,7 +753,7 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) ImGui::PopStyleVar(2); pop_combo_style(); ImGui::AlignTextToFramePadding(); - m_imgui->text(_L("Size")); + m_imgui->text(m_desc["size"]); ImGui::SameLine(caption_size); ImGui::PushItemWidth(input_size); if(ImGui::InputFloat("###font_size", &m_font_size, 0.0f, 0.0f, "%.2f")) @@ -769,7 +780,7 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) ImGui::PopStyleVar(3); ImGui::AlignTextToFramePadding(); - m_imgui->text(_L("Thickness")); + m_imgui->text(m_desc["thickness"]); ImGui::SameLine(caption_size); ImGui::PushItemWidth(list_width); float old_value = m_thickness; @@ -784,7 +795,7 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) const float drag_left_width = caption_size + slider_width + space_size; ImGui::AlignTextToFramePadding(); - m_imgui->text(_L("Text Gap")); + m_imgui->text(m_desc["text_gap"]); ImGui::SameLine(caption_size); ImGui::PushItemWidth(slider_width); if (m_imgui->bbl_slider_float_style("##text_gap", &m_text_gap, -100, 100, "%.2f", 1.0f, true)) @@ -795,7 +806,7 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) m_need_update_text = true; ImGui::AlignTextToFramePadding(); - m_imgui->text(_L("Angle")); + m_imgui->text(m_desc["angle"]); ImGui::SameLine(caption_size); ImGui::PushItemWidth(slider_width); if (m_imgui->bbl_slider_float_style("##angle", &m_rotate_angle, 0, 360, "%.2f", 1.0f, true)) @@ -806,7 +817,7 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) m_need_update_text = true; ImGui::AlignTextToFramePadding(); - m_imgui->text(_L("Embeded\ndepth")); + m_imgui->text(m_desc["embeded_depth"]); ImGui::SameLine(caption_size); ImGui::PushItemWidth(list_width); old_value = m_embeded_depth; @@ -817,7 +828,7 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) m_need_update_text = true; ImGui::AlignTextToFramePadding(); - m_imgui->text(_L("Input text")); + m_imgui->text(m_desc["input_text"]); ImGui::SameLine(caption_size); ImGui::PushItemWidth(list_width); @@ -835,12 +846,12 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) ImGui::SameLine(caption_size); ImGui::AlignTextToFramePadding(); - if (m_imgui->bbl_checkbox(_L("Surface"), m_is_surface_text)) + if (m_imgui->bbl_checkbox(m_desc["surface"], m_is_surface_text)) m_need_update_text = true; ImGui::SameLine(); ImGui::AlignTextToFramePadding(); - if (m_imgui->bbl_checkbox(_L("Horizontal text"), m_keep_horizontal)) + if (m_imgui->bbl_checkbox(m_desc["horizontal_text"], m_keep_horizontal)) m_need_update_text = true; //ImGui::SameLine(); diff --git a/src/slic3r/GUI/IMSlider.cpp b/src/slic3r/GUI/IMSlider.cpp index 7987ea7862..0c8094a4bb 100644 --- a/src/slic3r/GUI/IMSlider.cpp +++ b/src/slic3r/GUI/IMSlider.cpp @@ -16,7 +16,7 @@ constexpr double miscalculation = scale_(scale_(1)); // equal to 1 mm2 static const float LEFT_MARGIN = 13.0f + 100.0f; // avoid thumbnail toolbar static const float HORIZONTAL_SLIDER_WINDOW_HEIGHT = 64.0f; -static const float VERTICAL_SLIDER_WINDOW_WIDTH = 124.0f; +static const float VERTICAL_SLIDER_WINDOW_WIDTH = 160.0f; static const float GROOVE_WIDTH = 12.0f; static const ImVec2 ONE_LAYER_MARGIN = ImVec2(20.0f, 20.0f); static const ImVec2 ONE_LAYER_BUTTON_SIZE = ImVec2(28.0f, 28.0f); From 333287535bf752bd2e3430d328940c52231ffac2 Mon Sep 17 00:00:00 2001 From: Hukete <100949318+Hukete@users.noreply.github.com> Date: Thu, 9 Nov 2023 22:20:14 +0800 Subject: [PATCH 4/9] Update fdm_filament_pla.json (#2657) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 10-25 Add TPU-95A HF * 1030 Adding Introduction of Chamber Temperature Control Macros(M191) to Notes * 1102 Add ABS-GF10 profile, Remove a extra "s" from the "0.36mm Standard @Qidi XPlus3 0.6 nozzle.json" file * 1106 Add the PA value to some genetic filament profiles * Update fdm_filament_pla.json Change the fan rate of begin layers --- resources/profiles/Qidi/filament/fdm_filament_pla.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/resources/profiles/Qidi/filament/fdm_filament_pla.json b/resources/profiles/Qidi/filament/fdm_filament_pla.json index d72b51ae86..8a82c3711e 100644 --- a/resources/profiles/Qidi/filament/fdm_filament_pla.json +++ b/resources/profiles/Qidi/filament/fdm_filament_pla.json @@ -65,7 +65,10 @@ "50%" ], "close_fan_the_first_x_layers": [ - "1" + "2" + ], + "full_fan_speed_layer": [ + "4" ], "nozzle_temperature": [ "220" From f16feff2a4951bc38fc75b49bb859d9f38d2f553 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Thu, 9 Nov 2023 22:21:44 +0800 Subject: [PATCH 5/9] Fixes scars on thing walls when "avoid crossing wall" is turned on (#2659) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Travel very close to the inner holes, could cross external perimeter when the avoid crossing perimeters was enabled. (cherry picked from commit prusa3d/PrusaSlicer@6c51e5148c0fca15c869d344e081aad249b0244f) * Modified variable offset in the avoid crossing perimeters to not cause scars on thin objects (#7699). Previously, the minimum contour width was chosen too conservative and, on some thin objects, only allowed minimal (or non) offset. This could result in travels being planned along the outer perimeter. Now, the minimum contour width is chosen much smaller at the start and tested if the variable offset wasn't failed (the outer contour broke up into more parts, more or fewer holes, etc.). If any problem is detected, the variable offset is recalculated with a larger minimum contour width. (cherry picked from commit prusa3d/PrusaSlicer@dc00f0bf983902a6cb81503afa78be4a0ccafb71) --------- Co-authored-by: Lukáš Hejl --- .../GCode/AvoidCrossingPerimeters.cpp | 261 +++++++++++------- .../GCode/AvoidCrossingPerimeters.hpp | 9 +- 2 files changed, 168 insertions(+), 102 deletions(-) diff --git a/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp b/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp index 4d9f3dcf1b..0598db3b17 100644 --- a/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp +++ b/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2020 - 2022 Vojtěch Bubník @bubnikv, Lukáš Hejl @hejllukas +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "../Layer.hpp" #include "../GCode.hpp" #include "../EdgeGrid.hpp" @@ -13,6 +17,8 @@ #include #include +//#define AVOID_CROSSING_PERIMETERS_DEBUG_OUTPUT + namespace Slic3r { struct TravelPoint @@ -20,6 +26,8 @@ struct TravelPoint Point point; // Index of the polygon containing this point. A negative value indicates that the point is not on any border. int border_idx; + // simplify_travel() doesn't remove this point. + bool do_not_remove = false; }; struct Intersection @@ -32,6 +40,8 @@ struct Intersection Point point; // Distance from the first point in the corresponding boundary float distance; + // simplify_travel() doesn't remove this point. + bool do_not_remove = false; }; struct ClosestLine @@ -207,8 +217,8 @@ static std::vector extend_for_closest_lines(const std::vector new_intersections; - new_intersections.push_back({cl_start.border_idx, cl_start.line_idx, cl_start.point, compute_distance(cl_start)}); - new_intersections.push_back({cl_end.border_idx, cl_end.line_idx, cl_end.point, compute_distance(cl_end)}); + new_intersections.push_back({cl_start.border_idx, cl_start.line_idx, cl_start.point, compute_distance(cl_start), true}); + new_intersections.push_back({cl_end.border_idx, cl_end.line_idx, cl_end.point, compute_distance(cl_end), true}); return new_intersections; } } @@ -259,7 +269,7 @@ static std::vector extend_for_closest_lines(const std::vector::max()) { // If there is any ClosestLine around the start point closer to the Intersection, then replace this Intersection with ClosestLine. const ClosestLine &cl_start = start_lines[cl_start_idx]; - new_intersections.front() = {cl_start.border_idx, cl_start.line_idx, cl_start.point, compute_distance(cl_start)}; + new_intersections.front() = {cl_start.border_idx, cl_start.line_idx, cl_start.point, compute_distance(cl_start), true}; } else { // Check if there is any ClosestLine with the same boundary_idx as any Intersection. If this ClosestLine exists, then add it to the // vector of intersections. This allows in some cases when it is more than one around ClosestLine start point chose that one which @@ -267,7 +277,7 @@ static std::vector extend_for_closest_lines(const std::vector::max()) ? start_lines[start_closest_lines_idx] : start_lines.front(); - new_intersections.insert(new_intersections.begin(),{cl_start.border_idx, cl_start.line_idx, cl_start.point, compute_distance(cl_start)}); + new_intersections.insert(new_intersections.begin(),{cl_start.border_idx, cl_start.line_idx, cl_start.point, compute_distance(cl_start), true}); } } @@ -276,7 +286,7 @@ static std::vector extend_for_closest_lines(const std::vector::max()) { // If there is any ClosestLine around the end point closer to the Intersection, then replace this Intersection with ClosestLine. const ClosestLine &cl_end = end_lines[cl_end_idx]; - new_intersections.back() = {cl_end.border_idx, cl_end.line_idx, cl_end.point, compute_distance(cl_end)}; + new_intersections.back() = {cl_end.border_idx, cl_end.line_idx, cl_end.point, compute_distance(cl_end), true}; } else { // Check if there is any ClosestLine with the same boundary_idx as any Intersection. If this ClosestLine exists, then add it to the // vector of intersections. This allows in some cases when it is more than one around ClosestLine end point chose that one which @@ -284,7 +294,7 @@ static std::vector extend_for_closest_lines(const std::vector::max()) ? end_lines[end_closest_lines_idx] : end_lines.front(); - new_intersections.push_back({cl_end.border_idx, cl_end.line_idx, cl_end.point, compute_distance(cl_end)}); + new_intersections.push_back({cl_end.border_idx, cl_end.line_idx, cl_end.point, compute_distance(cl_end), true}); } } return new_intersections; @@ -350,8 +360,6 @@ static Polyline to_polyline(const std::vector &travel) return result; } -// #define AVOID_CROSSING_PERIMETERS_DEBUG_OUTPUT - #ifdef AVOID_CROSSING_PERIMETERS_DEBUG_OUTPUT static void export_travel_to_svg(const Polygons &boundary, const Line &original_travel, @@ -359,16 +367,17 @@ static void export_travel_to_svg(const Polygons &boundary, const std::vector &intersections, const std::string &path) { - BoundingBox bbox = get_extents(boundary); + coordf_t stroke_width = scale_(0.05); + BoundingBox bbox = get_extents(boundary); ::Slic3r::SVG svg(path, bbox); - svg.draw_outline(boundary, "green"); - svg.draw(original_travel, "blue"); - svg.draw(result_travel, "red"); - svg.draw(original_travel.a, "black"); - svg.draw(original_travel.b, "grey"); + svg.draw_outline(boundary, "green", stroke_width); + svg.draw(original_travel, "blue", stroke_width); + svg.draw(result_travel, "red", stroke_width); + svg.draw(original_travel.a, "black", stroke_width); + svg.draw(original_travel.b, "grey", stroke_width); for (const Intersection &intersection : intersections) - svg.draw(intersection.point, "lightseagreen"); + svg.draw(intersection.point, "lightseagreen", stroke_width); } static void export_travel_to_svg(const Polygons &boundary, @@ -433,21 +442,30 @@ static std::vector simplify_travel(const AvoidCrossingPerimeters::B visitor.pt_current = ¤t_point; - for (size_t point_idx_2 = point_idx + 1; point_idx_2 < travel.size(); ++point_idx_2) { - if (travel[point_idx_2].point == current_point) { - next = travel[point_idx_2]; - point_idx = point_idx_2; - continue; - } + if (!next.do_not_remove) + for (size_t point_idx_2 = point_idx + 1; point_idx_2 < travel.size(); ++point_idx_2) { + // Workaround for some issue in MSVC 19.29.30037 32-bit compiler. +#if defined(_WIN32) && !defined(_WIN64) + if (bool volatile do_not_remove = travel[point_idx_2].do_not_remove; do_not_remove) + break; +#else + if (travel[point_idx_2].do_not_remove) + break; +#endif + if (travel[point_idx_2].point == current_point) { + next = travel[point_idx_2]; + point_idx = point_idx_2; + continue; + } - visitor.pt_next = &travel[point_idx_2].point; - boundary.grid.visit_cells_intersecting_line(*visitor.pt_current, *visitor.pt_next, visitor); - // Check if deleting point causes crossing a boundary - if (!visitor.intersect) { - next = travel[point_idx_2]; - point_idx = point_idx_2; + visitor.pt_next = &travel[point_idx_2].point; + boundary.grid.visit_cells_intersecting_line(*visitor.pt_current, *visitor.pt_next, visitor); + // Check if deleting point causes crossing a boundary + if (!visitor.intersect) { + next = travel[point_idx_2]; + point_idx = point_idx_2; + } } - } simplified_path.emplace_back(next); } @@ -473,7 +491,7 @@ static float get_perimeter_spacing(const Layer &layer) size_t regions_count = 0; float perimeter_spacing = 0.f; for (const LayerRegion *layer_region : layer.regions()) - if (layer_region != nullptr && !layer_region->slices.empty()) { + if (layer_region != nullptr && ! layer_region->slices.empty()) { perimeter_spacing += layer_region->flow(frPerimeter).scaled_spacing(); ++regions_count; } @@ -494,7 +512,7 @@ static float get_perimeter_spacing_external(const Layer &layer) for (const PrintObject *object : layer.object()->print()->objects()) if (const Layer *l = object->get_layer_at_printz(layer.print_z, EPSILON); l) for (const LayerRegion *layer_region : l->regions()) - if (layer_region != nullptr && !layer_region->slices.empty()) { + if (layer_region != nullptr && ! layer_region->slices.empty()) { perimeter_spacing += layer_region->flow(frPerimeter).scaled_spacing(); ++ regions_count; } @@ -507,6 +525,25 @@ static float get_perimeter_spacing_external(const Layer &layer) return perimeter_spacing; } +// Returns average perimeter width calculated from all LayerRegion within the layer. +static float get_external_perimeter_width(const Layer &layer) +{ + size_t regions_count = 0; + float perimeter_width = 0.f; + for (const LayerRegion *layer_region : layer.regions()) + if (layer_region != nullptr && ! layer_region->slices.empty()) { + perimeter_width += float(layer_region->flow(frExternalPerimeter).scaled_width()); + ++regions_count; + } + + assert(perimeter_width >= 0.f); + if (regions_count != 0) + perimeter_width /= float(regions_count); + else + perimeter_width = get_default_perimeter_spacing(*layer.object()); + return perimeter_width; +} + // Called by avoid_perimeters() and by simplify_travel_heuristics(). static size_t avoid_perimeters_inner(const AvoidCrossingPerimeters::Boundary &boundary, const Point &start, @@ -566,7 +603,7 @@ static size_t avoid_perimeters_inner(const AvoidCrossingPerimeters::Boundary &bo // Offset of the polygon's point using get_middle_point_offset is used to simplify the calculation of intersection between the // boundary and the travel. The appended point is translated in the direction of inward normal. This translation ensures that the // appended point will be inside the polygon and not on the polygon border. - result.push_back({get_middle_point_offset(boundaries[intersection_first.border_idx], left_idx, right_idx, intersection_first.point, coord_t(SCALED_EPSILON)), int(intersection_first.border_idx)}); + result.push_back({get_middle_point_offset(boundaries[intersection_first.border_idx], left_idx, right_idx, intersection_first.point, coord_t(SCALED_EPSILON)), int(intersection_first.border_idx), intersection_first.do_not_remove}); // Check if intersection line also exit the boundary polygon if (it_second_r != it_last_item) { @@ -590,7 +627,7 @@ static size_t avoid_perimeters_inner(const AvoidCrossingPerimeters::Boundary &bo // Append the farthest intersection into the path left_idx = intersection_second.line_idx; right_idx = (intersection_second.line_idx >= (boundaries[intersection_second.border_idx].points.size() - 1)) ? 0 : (intersection_second.line_idx + 1); - result.push_back({get_middle_point_offset(boundaries[intersection_second.border_idx], left_idx, right_idx, intersection_second.point, coord_t(SCALED_EPSILON)), int(intersection_second.border_idx)}); + result.push_back({get_middle_point_offset(boundaries[intersection_second.border_idx], left_idx, right_idx, intersection_second.point, coord_t(SCALED_EPSILON)), int(intersection_second.border_idx), intersection_second.do_not_remove}); // Skip intersections in between it_first = it_second; } @@ -645,22 +682,22 @@ static size_t avoid_perimeters(const AvoidCrossingPerimeters::Boundary &boundary // Check if anyone of ExPolygons contains whole travel. // called by need_wipe() and AvoidCrossingPerimeters::travel_to() // FIXME Lukas H.: Maybe similar approach could also be used for ExPolygon::contains() -static bool any_expolygon_contains(const ExPolygons &ex_polygons, - const std::vector &ex_polygons_bboxes, - const EdgeGrid::Grid &grid_lslice, +static bool any_expolygon_contains(const ExPolygons &lslices_offset, + const std::vector &lslices_offset_bboxes, + const EdgeGrid::Grid &grid_lslices_offset, const Line &travel) { - assert(ex_polygons.size() == ex_polygons_bboxes.size()); - if(!grid_lslice.bbox().contains(travel.a) || !grid_lslice.bbox().contains(travel.b)) + assert(lslices_offset.size() == lslices_offset_bboxes.size()); + if(!grid_lslices_offset.bbox().contains(travel.a) || !grid_lslices_offset.bbox().contains(travel.b)) return false; - FirstIntersectionVisitor visitor(grid_lslice); + FirstIntersectionVisitor visitor(grid_lslices_offset); visitor.pt_current = &travel.a; visitor.pt_next = &travel.b; - grid_lslice.visit_cells_intersecting_line(*visitor.pt_current, *visitor.pt_next, visitor); + grid_lslices_offset.visit_cells_intersecting_line(*visitor.pt_current, *visitor.pt_next, visitor); if (!visitor.intersect) { - for (const ExPolygon &ex_polygon : ex_polygons) { - const BoundingBox &bbox = ex_polygons_bboxes[&ex_polygon - &ex_polygons.front()]; + for (const ExPolygon &ex_polygon : lslices_offset) { + const BoundingBox &bbox = lslices_offset_bboxes[&ex_polygon - &lslices_offset.front()]; if (bbox.contains(travel.a) && bbox.contains(travel.b) && ex_polygon.contains(travel.a)) return true; } @@ -670,18 +707,18 @@ static bool any_expolygon_contains(const ExPolygons &ex_polygons, // Check if anyone of ExPolygons contains whole travel. // called by need_wipe() -static bool any_expolygon_contains(const ExPolygons &ex_polygons, const std::vector &ex_polygons_bboxes, const EdgeGrid::Grid &grid_lslice, const Polyline &travel) +static bool any_expolygon_contains(const ExPolygons &ex_polygons, const std::vector &ex_polygons_bboxes, const EdgeGrid::Grid &grid_lslice_offset, const Polyline &travel) { assert(ex_polygons.size() == ex_polygons_bboxes.size()); - if(std::any_of(travel.points.begin(), travel.points.end(), [&grid_lslice](const Point &point) { return !grid_lslice.bbox().contains(point); })) + if(std::any_of(travel.points.begin(), travel.points.end(), [&grid_lslice_offset](const Point &point) { return !grid_lslice_offset.bbox().contains(point); })) return false; - FirstIntersectionVisitor visitor(grid_lslice); + FirstIntersectionVisitor visitor(grid_lslice_offset); bool any_intersection = false; for (size_t line_idx = 1; line_idx < travel.size(); ++line_idx) { visitor.pt_current = &travel.points[line_idx - 1]; visitor.pt_next = &travel.points[line_idx]; - grid_lslice.visit_cells_intersecting_line(*visitor.pt_current, *visitor.pt_next, visitor); + grid_lslice_offset.visit_cells_intersecting_line(*visitor.pt_current, *visitor.pt_next, visitor); any_intersection = visitor.intersect; if (any_intersection) break; } @@ -698,13 +735,13 @@ static bool any_expolygon_contains(const ExPolygons &ex_polygons, const std::vec } static bool need_wipe(const GCode &gcodegen, - const EdgeGrid::Grid &grid_lslice, - const Line &original_travel, - const Polyline &result_travel, - const size_t intersection_count) + const ExPolygons &lslices_offset, + const std::vector &lslices_offset_bboxes, + const EdgeGrid::Grid &grid_lslices_offset, + const Line &original_travel, + const Polyline &result_travel, + const size_t intersection_count) { - const ExPolygons &lslices = gcodegen.layer()->lslices; - const std::vector &lslices_bboxes = gcodegen.layer()->lslices_bboxes; bool z_lift_enabled = gcodegen.config().z_hop.get_at(gcodegen.writer().extruder()->id()) > 0.; bool wipe_needed = false; @@ -714,16 +751,16 @@ static bool need_wipe(const GCode &gcodegen, // The original layer is intersected with defined boundaries. Then it is necessary to make a detailed test. // If the z-lift is enabled, then a wipe is needed when the original travel leads above the holes. if (z_lift_enabled) { - if (any_expolygon_contains(lslices, lslices_bboxes, grid_lslice, original_travel)) { + if (any_expolygon_contains(lslices_offset, lslices_offset_bboxes, grid_lslices_offset, original_travel)) { // Check if original_travel and result_travel are not same. // If both are the same, then it is possible to skip testing of result_travel wipe_needed = !(result_travel.size() > 2 && result_travel.first_point() == original_travel.a && result_travel.last_point() == original_travel.b) && - !any_expolygon_contains(lslices, lslices_bboxes, grid_lslice, result_travel); + !any_expolygon_contains(lslices_offset, lslices_offset_bboxes, grid_lslices_offset, result_travel); } else { wipe_needed = true; } } else { - wipe_needed = !any_expolygon_contains(lslices, lslices_bboxes, grid_lslice, result_travel); + wipe_needed = !any_expolygon_contains(lslices_offset, lslices_offset_bboxes, grid_lslices_offset, result_travel); } } @@ -945,55 +982,71 @@ static std::vector contour_distance(const EdgeGrid::Grid &grid, // ExPolygons are handled one by one so returned ExPolygons could intersect. static ExPolygons inner_offset(const ExPolygons &ex_polygons, double offset) { - double min_contour_width = 2. * offset + SCALED_EPSILON; - double search_radius = 2. * (offset + min_contour_width); - ExPolygons ex_poly_result = ex_polygons; + const std::vector min_contour_width_values = {offset / 2., offset, 2. * offset + SCALED_EPSILON}; + ExPolygons ex_poly_result = ex_polygons; resample_expolygons(ex_poly_result, offset / 2, scaled(0.5)); for (ExPolygon &ex_poly : ex_poly_result) { BoundingBox bbox(get_extents(ex_poly)); bbox.offset(SCALED_EPSILON); - EdgeGrid::Grid grid; - grid.set_bbox(bbox); - grid.create(ex_poly, coord_t(0.7 * search_radius)); - std::vector> ex_poly_distances; - precompute_expolygon_distances(ex_poly, ex_poly_distances); + // Filter out expolygons smaller than 0.1mm^2 + if (Vec2d bbox_size = bbox.size().cast(); bbox_size.x() * bbox_size.y() < Slic3r::sqr(scale_(0.1f))) + continue; - std::vector> offsets; - offsets.reserve(ex_poly.holes.size() + 1); - for (size_t idx_contour = 0; idx_contour <= ex_poly.holes.size(); ++idx_contour) { - const Polygon &poly = (idx_contour == 0) ? ex_poly.contour : ex_poly.holes[idx_contour - 1]; - assert(poly.is_counter_clockwise() == (idx_contour == 0)); - std::vector distances = contour_distance(grid, ex_poly_distances[idx_contour], idx_contour, poly, offset, search_radius); - for (float &distance : distances) { - if (distance < min_contour_width) - distance = 0.f; - else if (distance > min_contour_width + 2. * offset) - distance = - float(offset); - else - distance = - (distance - float(min_contour_width)) / 2.f; - } - offsets.emplace_back(distances); - } + for (const double &min_contour_width : min_contour_width_values) { + const size_t min_contour_width_idx = &min_contour_width - &min_contour_width_values.front(); + const double search_radius = 2. * (offset + min_contour_width); - ExPolygons offset_ex_poly = variable_offset_inner_ex(ex_poly, offsets); - // If variable_offset_inner_ex produces empty result, then original ex_polygon is used - if (offset_ex_poly.size() == 1) { - ex_poly = std::move(offset_ex_poly.front()); - } else if (offset_ex_poly.size() > 1) { - // fix_after_inner_offset called inside variable_offset_inner_ex sometimes produces - // tiny artefacts polygons, so these artefacts are removed. - double max_area = offset_ex_poly.front().area(); - size_t max_area_idx = 0; - for (size_t poly_idx = 1; poly_idx < offset_ex_poly.size(); ++poly_idx) { - double area = offset_ex_poly[poly_idx].area(); - if (max_area < area) { - max_area = area; - max_area_idx = poly_idx; + EdgeGrid::Grid grid; + grid.set_bbox(bbox); + grid.create(ex_poly, coord_t(0.7 * search_radius)); + + std::vector> ex_poly_distances; + precompute_expolygon_distances(ex_poly, ex_poly_distances); + + std::vector> offsets; + offsets.reserve(ex_poly.holes.size() + 1); + for (size_t idx_contour = 0; idx_contour <= ex_poly.holes.size(); ++idx_contour) { + const Polygon &poly = (idx_contour == 0) ? ex_poly.contour : ex_poly.holes[idx_contour - 1]; + assert(poly.is_counter_clockwise() == (idx_contour == 0)); + std::vector distances = contour_distance(grid, ex_poly_distances[idx_contour], idx_contour, poly, offset, search_radius); + for (float &distance : distances) { + if (distance < min_contour_width) + distance = 0.f; + else if (distance > min_contour_width + 2. * offset) + distance = -float(offset); + else + distance = -(distance - float(min_contour_width)) / 2.f; } + offsets.emplace_back(distances); + } + + ExPolygons offset_ex_poly = variable_offset_inner_ex(ex_poly, offsets); + // If variable_offset_inner_ex produces empty result, then original ex_polygon is used + if (offset_ex_poly.size() == 1 && offset_ex_poly.front().holes.size() == ex_poly.holes.size()) { + ex_poly = std::move(offset_ex_poly.front()); + break; + } else if ((min_contour_width_idx + 1) < min_contour_width_values.size()) { + continue; // Try the next round with bigger min_contour_width. + } else if (offset_ex_poly.size() == 1) { + ex_poly = std::move(offset_ex_poly.front()); + break; + } else if (offset_ex_poly.size() > 1) { + // fix_after_inner_offset called inside variable_offset_inner_ex sometimes produces + // tiny artefacts polygons, so these artefacts are removed. + double max_area = offset_ex_poly.front().area(); + size_t max_area_idx = 0; + for (size_t poly_idx = 1; poly_idx < offset_ex_poly.size(); ++poly_idx) { + double area = offset_ex_poly[poly_idx].area(); + if (max_area < area) { + max_area = area; + max_area_idx = poly_idx; + } + } + ex_poly = std::move(offset_ex_poly[max_area_idx]); + break; } - ex_poly = std::move(offset_ex_poly[max_area_idx]); } } return ex_poly_result; @@ -1133,10 +1186,8 @@ Polyline AvoidCrossingPerimeters::travel_to(const GCode &gcodegen, const Point & Vec2d startf = start.cast(); Vec2d endf = end .cast(); - const ExPolygons &lslices = gcodegen.layer()->lslices; - const std::vector &lslices_bboxes = gcodegen.layer()->lslices_bboxes; - bool is_support_layer = (dynamic_cast(gcodegen.layer()) != nullptr); - if (!use_external && (is_support_layer || (!lslices.empty() && !any_expolygon_contains(lslices, lslices_bboxes, m_grid_lslice, travel)))) { + bool is_support_layer = dynamic_cast(gcodegen.layer()) != nullptr; + if (!use_external && (is_support_layer || (!m_lslices_offset.empty() && !any_expolygon_contains(m_lslices_offset, m_lslices_offset_bboxes, m_grid_lslices_offset, travel)))) { // Initialize m_internal only when it is necessary. if (m_internal.boundaries.empty()) init_boundary(&m_internal, to_polygons(get_boundary(*gcodegen.layer()))); @@ -1186,7 +1237,7 @@ Polyline AvoidCrossingPerimeters::travel_to(const GCode &gcodegen, const Point & } else if (max_detour_length_exceeded) { *could_be_wipe_disabled = false; } else - *could_be_wipe_disabled = !need_wipe(gcodegen, m_grid_lslice, travel, result_pl, travel_intersection_count); + *could_be_wipe_disabled = !need_wipe(gcodegen, m_lslices_offset, m_lslices_offset_bboxes, m_grid_lslices_offset, travel, result_pl, travel_intersection_count); return result_pl; } @@ -1197,13 +1248,21 @@ void AvoidCrossingPerimeters::init_layer(const Layer &layer) { m_internal.clear(); m_external.clear(); + m_lslices_offset.clear(); + m_lslices_offset_bboxes.clear(); + + float perimeter_offset = -get_external_perimeter_width(layer) / float(2.); + m_lslices_offset = offset_ex(layer.lslices, perimeter_offset); + + m_lslices_offset_bboxes.reserve(m_lslices_offset.size()); + for (const ExPolygon &ex_poly : m_lslices_offset) + m_lslices_offset_bboxes.emplace_back(get_extents(ex_poly)); BoundingBox bbox_slice(get_extents(layer.lslices)); bbox_slice.offset(SCALED_EPSILON); - m_grid_lslice.set_bbox(bbox_slice); - //FIXME 1mm grid? - m_grid_lslice.create(layer.lslices, coord_t(scale_(1.))); + m_grid_lslices_offset.set_bbox(bbox_slice); + m_grid_lslices_offset.create(m_lslices_offset, coord_t(scale_(1.))); } #if 0 diff --git a/src/libslic3r/GCode/AvoidCrossingPerimeters.hpp b/src/libslic3r/GCode/AvoidCrossingPerimeters.hpp index b67642c5d8..5d85aace7f 100644 --- a/src/libslic3r/GCode/AvoidCrossingPerimeters.hpp +++ b/src/libslic3r/GCode/AvoidCrossingPerimeters.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2020 - 2022 Lukáš Hejl @hejllukas, Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_AvoidCrossingPerimeters_hpp_ #define slic3r_AvoidCrossingPerimeters_hpp_ @@ -58,8 +62,11 @@ private: // we enable it by default for the first travel move in print bool m_disabled_once { true }; + // Lslices offseted by half an external perimeter width. Used for detection if line or polyline is inside of any polygon. + ExPolygons m_lslices_offset; + std::vector m_lslices_offset_bboxes; // Used for detection of line or polyline is inside of any polygon. - EdgeGrid::Grid m_grid_lslice; + EdgeGrid::Grid m_grid_lslices_offset; // Store all needed data for travels inside object Boundary m_internal; // Store all needed data for travels outside object From 97502df924cb89209ef559d8ca18171eabf9ea16 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Thu, 9 Nov 2023 22:22:43 +0800 Subject: [PATCH 6/9] Fix cli segfault (#2661) (#2665) --- src/slic3r/GUI/PartPlate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index bd86ceaa3d..d07895b3de 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -459,7 +459,7 @@ void PartPlate::calc_vertex_for_icons(int index, GeometryBuffer &buffer) ExPolygon poly; auto bed_ext = get_extents(m_shape); Vec2d p = bed_ext[2]; - if (m_plater->get_build_volume_type() == BuildVolume_Type::Circle) + if (m_plater && m_plater->get_build_volume_type() == BuildVolume_Type::Circle) p[1] -= std::max( 0.0, (bed_ext.size()(1) - 5 * PARTPLATE_ICON_SIZE - 4 * PARTPLATE_ICON_GAP_Y - PARTPLATE_ICON_GAP_TOP) / 2); From 2203131211f1559810ff0207e3619b64e4fb8d2b Mon Sep 17 00:00:00 2001 From: niklasb <58566859+niklasb22@users.noreply.github.com> Date: Thu, 9 Nov 2023 15:23:43 +0100 Subject: [PATCH 7/9] Fix: Height range Modifier translation in German #2613 (#2668) Update OrcaSlicer_de.po --- localization/i18n/de/OrcaSlicer_de.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/localization/i18n/de/OrcaSlicer_de.po b/localization/i18n/de/OrcaSlicer_de.po index 171270cfeb..1c69a1d007 100644 --- a/localization/i18n/de/OrcaSlicer_de.po +++ b/localization/i18n/de/OrcaSlicer_de.po @@ -148,7 +148,7 @@ msgid "Bucket fill" msgstr "Flächenfüllung" msgid "Height range" -msgstr "Höhenreichweite" +msgstr "Höhenbereich" msgid "Ctrl + Shift + Enter" msgstr "Strg + Umschalt + Eingabetaste" @@ -163,7 +163,7 @@ msgid "Triangle" msgstr "Dreieck" msgid "Height Range" -msgstr "Höhenreichweite" +msgstr "Höhenbereich" msgid "Vertical" msgstr "Vertikal" From 1b53d1b72d7dcb2222d13ad9e99a70ad1b71f5ac Mon Sep 17 00:00:00 2001 From: renemosner <99507763+renemosner@users.noreply.github.com> Date: Thu, 9 Nov 2023 15:24:49 +0100 Subject: [PATCH 8/9] Update OrcaSlicer_cs.po (#2670) --- localization/i18n/cs/OrcaSlicer_cs.po | 68 +++++++++++++-------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/localization/i18n/cs/OrcaSlicer_cs.po b/localization/i18n/cs/OrcaSlicer_cs.po index b4ece6ed9c..a70af652b0 100644 --- a/localization/i18n/cs/OrcaSlicer_cs.po +++ b/localization/i18n/cs/OrcaSlicer_cs.po @@ -1787,10 +1787,10 @@ msgid "An SD card needs to be inserted before printing via LAN." msgstr "Před tiskem přes LAN je třeba vložit SD kartu." msgid "Sending gcode file over LAN" -msgstr "Odesílání souboru gcode přes LAN" +msgstr "Odesílání souboru gkód přes LAN" msgid "Sending gcode file to sdcard" -msgstr "Odesílání souboru gcode na sdcard" +msgstr "Odesílání souboru gkód na sd kartu" #, c-format, boost-format msgid "Successfully sent. Close current page in %s s" @@ -2181,7 +2181,7 @@ msgid "" "(Currently supporting automatic supply of consumables with the same brand, " "material type, and color)" msgstr "" -"Pokud v AMS existují dva identické filameny, bude povolena záloha AMS " +"Pokud v AMS existují dva identické filamenty, bude povolena záloha AMS " "filamentu. \n" "(Aktuálně podporuje automatické doplňování spotřebního materiálu stejné " "značky, typu materiálu a barvy)" @@ -2333,7 +2333,7 @@ msgid "" "Error message: %1%.\n" "Source file %2%." msgstr "" -"Soubor gcode se nepodařilo uložit.\n" +"Soubor gkód se nepodařilo uložit.\n" "Chybová zpráva: %1%.\n" "Zdrojový soubor %2%." @@ -2524,7 +2524,7 @@ msgstr "" "typ časosběru je tradiční." msgid " But machines with I3 structure will not generate timelapse videos." -msgstr " Ale stroje s I3 strukturou nevytvoří timelapse videa." +msgstr " Ale stroje s I3 strukturou nevytvářejí časosběrná videa." msgid "" "Change these settings automatically? \n" @@ -2645,7 +2645,7 @@ msgid "Calibrating the micro lida" msgstr "Kalibrace mikro lida" msgid "Calibrating extrusion flow" -msgstr "Kalibrace extruze průtpku" +msgstr "Kalibrace extruze průtoku" msgid "Paused due to nozzle temperature malfunction" msgstr "Pozastaveno kvůli poruše teploty trysky" @@ -3449,7 +3449,7 @@ msgid "Export current sliced file" msgstr "Exportovat aktuální Slicovaný soubor" msgid "Export all plate sliced file" -msgstr "Exportovat všechny soubor slicované na pdložce" +msgstr "Exportovat všechny soubor slicované na podložce" msgid "Export G-code" msgstr "Exportovat G-kód" @@ -4132,7 +4132,7 @@ msgid " upload config prase failed\n" msgstr " nahrávání konfigurace se nepodařilo zpracovat\n" msgid " No corresponding storage bucket\n" -msgstr " Žádný odpovídající úložný bucket\n" +msgstr " Žádný odpovídající úložný prostor\n" msgid " can not be opened\n" msgstr " nelze otevřít\n" @@ -4366,7 +4366,7 @@ msgid "" "The application cannot run normally because OpenGL version is lower than " "2.0.\n" msgstr "" -"Aplikace nemůže běžet normálně, protože máte nižší verzi OpenGLnež 2.0.\n" +"Aplikace nemůže běžet normálně, protože máte nižší verzi OpenGL než 2.0.\n" msgid "Please upgrade your graphics card driver." msgstr "Prosím aktualizujte ovladač grafické karty." @@ -4808,7 +4808,7 @@ msgid "" "The loaded file contains gcode only, Can not enter the Prepare page" msgstr "" "Režim pouze náhled:\n" -"Načtený soubor obsahuje pouze gcode, nelze vstoupit na stránku Příprava" +"Načtený soubor obsahuje pouze gkód, nelze vstoupit na stránku Příprava" msgid "You can keep the modified presets to the new project or discard them" msgstr "Upravené předvolby si můžete ponechat pro nový projekt nebo je zahodit" @@ -4914,7 +4914,7 @@ msgid "The following characters are not allowed by a FAT file system:" msgstr "Následující znaky nejsou v souborovém systému FAT povoleny:" msgid "Save Sliced file as:" -msgstr "Uložit Slicované soubor jako:" +msgstr "Uložit Slicovaný soubor jako:" #, c-format, boost-format msgid "" @@ -4932,7 +4932,7 @@ msgstr "" "kladné části." msgid "Is the printer ready? Is the print sheet in place, empty and clean?" -msgstr "Je tiskarna připravená k tisku? Je podložka prázdná a čistá?" +msgstr "Je tiskárna připravená k tisku? Je podložka prázdná a čistá?" msgid "Upload and Print" msgstr "Nahrát a Tisknout" @@ -6226,7 +6226,7 @@ msgid "Jerk limitation" msgstr "Omezení Jerk-Ryv" msgid "Single extruder multimaterial setup" -msgstr "Nastavení multimaterialu s jedním extruderem" +msgstr "Nastavení multimateriálu s jedním extruderem" msgid "Wipe tower" msgstr "Čistící věž" @@ -6558,7 +6558,7 @@ msgid "Login" msgstr "Přihlášení" msgid "The configuration package is changed in previous Config Guide" -msgstr "Konfigurační balíček byl změněn v předchozím Config Guide" +msgstr "Konfigurační balíček byl změněn v předchozím průvodci konfigurací" msgid "Configuration package changed" msgstr "Konfigurační balíček změněn" @@ -8221,7 +8221,7 @@ msgid "" msgstr "" "Materiál může mít objemovou změnu po přepnutí mezi roztaveným a krystalickým " "stavem. Toto nastavení proporcionálně změní veškerý vytlačovací tok tohoto " -"filamentu v gcode. Doporučený rozsah hodnot je mezi 0,95 a 1,05. Možná " +"filamentu v gkódu. Doporučený rozsah hodnot je mezi 0,95 a 1,05. Možná " "můžete tuto hodnotu vyladit, abyste získali pěkně rovný povrch, když dochází " "k mírnému přetečení nebo podtečení" @@ -8323,7 +8323,7 @@ msgid "" "Filament diameter is used to calculate extrusion in gcode, so it's important " "and should be accurate" msgstr "" -"Průměr filamentu se používá k výpočtu vytlačování v gcode, takže je důležitý " +"Průměr filamentu se používá k výpočtu vytlačování v gkódu, takže je důležitý " "a měl by být přesný" msgid "Shrinkage" @@ -8337,7 +8337,7 @@ msgid "" "Be sure to allow enough space between objects, as this compensation is done " "after the checks." msgstr "" -"Zadejte procento smrštění, které filament získá po ochlazení (94% pokud " +"Zadejte procento smrštění, které filament získá po ochlazení (94% i pokud " "naměříte 94mm místo 100mm). Část bude pro kompenzaci zmenšena v xy. Bere se " "v úvahu pouze filamentu použit pro obvod.\n" "Ujistěte se aby byl mezi objekty dostatek prostoru, protože tato kompenzace " @@ -8431,7 +8431,7 @@ msgid "" msgstr "" "Doba, po kterou firmware tiskárny (nebo jednotka Multi Material 2.0) zavádí " "nový filament během jeho výměny (při provádění kódu T). Tento čas je přidán " -"k celkové době tisku pomocí G-code odhadovače tiskového času." +"k celkové době tisku pomocí G-kódu odhadovače tiskového času." msgid "Ramming parameters" msgstr "Parametry rapidní extruze" @@ -8450,7 +8450,7 @@ msgid "" msgstr "" "Doba, po kterou firmware tiskárny (nebo jednotka Multi Material 2.0) vysouvá " "filament během jeho výměny (při provádění kódu T). Tento čas je přidán k " -"celkové době tisku pomocí G-code odhadovače tiskového času." +"celkové době tisku pomocí G-kódu odhadovače tiskového času." msgid "Enable ramming for multitool setups" msgstr "Povolení rapidní extruze tiskárny s více nástroji" @@ -9037,7 +9037,7 @@ msgid "G-code flavor" msgstr "Druh G-kódu" msgid "What kind of gcode the printer is compatible with" -msgstr "S jakým typem gcode je tiskárna kompatibilní" +msgstr "S jakým typem gkódu je tiskárna kompatibilní" msgid "Klipper" msgstr "Klipper" @@ -9181,7 +9181,7 @@ msgstr "" "použije výchozí metodu." msgid "This gcode part is inserted at every layer change after lift z" -msgstr "Tato část gcode je vložena při každé změně vrstvy po zvednutí z" +msgstr "Tato část gkódu je vložena při každé změně vrstvy po zvednutí z" msgid "Supports silent mode" msgstr "Podporuje tichý režim" @@ -9198,7 +9198,7 @@ msgid "" "pause G-code in gcode viewer" msgstr "" "Tento G-kód bude použit jako kód pro pozastavený tisk. Uživatel může vložit " -"pauzu G-kód do prohlížeče gcode" +"pauzu G-kód do prohlížeče gkódu" msgid "This G-code will be used as a custom code" msgstr "Tento G-kód bude použit jako vlastní kód" @@ -9669,7 +9669,7 @@ msgid "" "resolution and more time to slice" msgstr "" "Cesta G-kódu se generuje po zjednodušení obrysu modelu, aby se předešlo " -"příliš velkému počtu bodů a Linek gcode v souboru gcode. Menší hodnota " +"příliš velkému počtu bodů a Linek gkódu v souboru gkód. Menší hodnota " "znamená vyšší rozlišení a více času na slicování" msgid "Travel distance threshold" @@ -9680,7 +9680,7 @@ msgid "" "threshold" msgstr "" "Spusťte retrakci pouze tehdy, když je dráha jízdy delší než tato hraniční " -"hohnota" +"hodnota" msgid "Retract amount before wipe" msgstr "Délka retrakce před očištěním" @@ -9925,7 +9925,7 @@ msgid "" "The printing speed in exported gcode will be slowed down, when the estimated " "layer time is shorter than this value, to get better cooling for these layers" msgstr "" -"Rychlost tisku v exportovaném kódu gcode se zpomalí, když je odhadovaná doba " +"Rychlost tisku v exportovaném kódu gkód se zpomalí, když je odhadovaná doba " "vrstvy kratší než tato hodnota, aby se dosáhlo lepšího chlazení pro tyto " "vrstvy" @@ -10089,7 +10089,7 @@ msgid "" "print bed, set this to -0.3 (or fix your endstop)." msgstr "" "Tato hodnota bude přidána (nebo odečtena) ze všech souřadnic Z ve výstupním " -"G-code. Používá se ke kompenzování špatné pozice endstopu Z. Například pokud " +"G-kódu. Používá se ke kompenzování špatné pozice endstopu Z. Například pokud " "endstop 0 skutečně ponechá trysku 0,3 mm daleko od tiskové podložky, " "nastavte hodnotu -0,3 (nebo dolaďte svůj koncový doraz)." @@ -10283,7 +10283,7 @@ msgstr "" "ušetří materiál a sníží poškození objektu.\n" "Pro stromovou podpěru, tenký a organický styl bude agresivněji slučovat " "větve a ušetří mnoho materiálu (výchozí organický), zatímco hybridní styl " -"vytvoří podobnou strukturu jako běžná podpěra pod velkými plochými převiy." +"vytvoří podobnou strukturu jako běžná podpěra pod velkými plochými převisy." msgid "Snug" msgstr "Přiléhavý" @@ -10390,7 +10390,7 @@ msgstr "" "automaticky vypočítány" msgid "Tree support brim width" -msgstr "Šířka Limce podpěr stromů" +msgstr "Šířka Límce podpěr stromů" msgid "Distance from tree branch to the outermost brim line" msgstr "Vzdálenost od větve stromu k nejvzdálenější linii Límce" @@ -10406,7 +10406,7 @@ msgid "Tree support branch diameter" msgstr "Průměr větve podpěr stromů" msgid "This setting determines the initial diameter of support nodes." -msgstr "Toto nastavení určuje počáteční průměr uzlů poděry." +msgstr "Toto nastavení určuje počáteční průměr uzlů podpěr." #. TRN PrintSettings: #lmFIXME msgid "Branch Diameter Angle" @@ -10501,7 +10501,7 @@ msgid "" "This gcode is inserted when change filament, including T command to trigger " "tool change" msgstr "" -"Tento gcode se vloží při výměně filamentu, včetně příkazu T ke spuštění " +"Tento gkód se vloží při výměně filamentu, včetně příkazu T ke spuštění " "výměny nástroje" msgid "" @@ -10957,7 +10957,7 @@ msgid "Update the configs values of 3mf to latest." msgstr "Aktualizujte konfigurační hodnoty 3mf na nejnovější." msgid "Load default filaments" -msgstr "Načíst výchozí filameny" +msgstr "Načíst výchozí filamenty" msgid "Load first filament as default for those not loaded" msgstr "Načíst první filament jako výchozí pro ty, které nebyly načteny" @@ -11399,7 +11399,7 @@ msgid "" "3. If the max volumetric speed or print temperature is changed in the " "filament setting." msgstr "" -"Nyní jsme přidali automatickou kalibraci pro různé filameny, která je plně " +"Nyní jsme přidali automatickou kalibraci pro různé filamenty, která je plně " "automatizovaná a výsledek bude uložen do tiskárny pro budoucí použití. " "Kalibraci musíte provést pouze v následujících omezených případech:\n" "1. Pokud použijete nový filament jiné značky/modelu nebo je filament vlhký;\n" @@ -11747,7 +11747,7 @@ msgid "Success to get history result" msgstr "Úspěšně načtený historický výsledek kalibrace dynamiky průtoku" msgid "Refreshing the historical Flow Dynamics Calibration records" -msgstr "Aktualizace historických záznamů kalibrace dynamiky průtpku probíhá" +msgstr "Aktualizace historických záznamů kalibrace dynamiky průtoku probíhá" msgid "Action" msgstr "Akce" @@ -11768,7 +11768,7 @@ msgid "Service name" msgstr "Název služby" msgid "OctoPrint version" -msgstr "Service name" +msgstr "Verze OctoPrintu" msgid "Searching for devices" msgstr "Vyhledávání zařízení" From 120a3576a0745655f0159e16fd2ca6b615bc9bf0 Mon Sep 17 00:00:00 2001 From: Ocraftyone Date: Thu, 9 Nov 2023 09:30:30 -0500 Subject: [PATCH 9/9] SS port - Change extrusion role gcode (#2459) implement custom gcode for when the extrusion role is changed Co-authored-by: supermerill --- src/libslic3r/GCode.cpp | 43 +++++++++++++++++++++++++++++++++++ src/libslic3r/GCode.hpp | 1 + src/libslic3r/Preset.cpp | 2 +- src/libslic3r/PrintConfig.cpp | 9 ++++++++ src/libslic3r/PrintConfig.hpp | 1 + src/slic3r/GUI/Tab.cpp | 11 +++++++++ 6 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index fa565cbe21..d2ae580d9d 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1402,6 +1402,8 @@ namespace DoExport { //BBS //if (ret.size() < MAX_TAGS_COUNT) check(_(L("Printing by object G-code")), config.printing_by_object_gcode.value); //if (ret.size() < MAX_TAGS_COUNT) check(_(L("Color Change G-code")), config.color_change_gcode.value); + //Orca + if (ret.size() < MAX_TAGS_COUNT) check(_(L("Change extrusion role G-code")), config.change_extrusion_role_gcode.value); if (ret.size() < MAX_TAGS_COUNT) check(_(L("Pause G-code")), config.machine_pause_gcode.value); if (ret.size() < MAX_TAGS_COUNT) check(_(L("Template Custom G-code")), config.template_custom_gcode.value); if (ret.size() < MAX_TAGS_COUNT) { @@ -4755,6 +4757,18 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, double F = speed * 60; // convert mm/sec to mm/min + //Orca: process custom gcode for extrusion role change + if (path.role() != m_last_extrusion_role && !m_config.change_extrusion_role_gcode.value.empty()) { + DynamicConfig config; + config.set_key_value("extrusion_role", new ConfigOptionString(extrusion_role_to_string_for_parser(path.role()))); + config.set_key_value("last_extrusion_role", new ConfigOptionString(extrusion_role_to_string_for_parser(m_last_extrusion_role))); + config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index + 1)); + config.set_key_value("layer_z", new ConfigOptionFloat(m_layer == nullptr ? m_last_height : m_layer->print_z)); + gcode += this->placeholder_parser_process("change_extrusion_role_gcode", + m_config.change_extrusion_role_gcode.value, m_writer.extruder()->id(), &config) + + "\n"; + } + // extrude arc or line if (m_enable_extrusion_role_markers) { if (path.role() != m_last_extrusion_role) { @@ -5002,6 +5016,35 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, return gcode; } +//Orca: get string name of extrusion role. used for change_extruder_role_gcode +std::string GCode::extrusion_role_to_string_for_parser(const ExtrusionRole & role) +{ + switch (role) { + case erPerimeter: return "Perimeter"; + case erExternalPerimeter: return "ExternalPerimeter"; + case erOverhangPerimeter: return "OverhangPerimeter"; + case erInternalInfill: return "InternalInfill"; + case erSolidInfill: return "SolidInfill"; + case erTopSolidInfill: return "TopSolidInfill"; + case erBottomSurface: return "BottomSurface"; + case erBridgeInfill: + case erInternalBridgeInfill: return "BridgeInfill"; + case erGapFill: return "GapFill"; + case erIroning: return "Ironing"; + case erSkirt: return "Skirt"; + case erBrim: return "Brim"; + case erSupportMaterial: return "SupportMaterial"; + case erSupportMaterialInterface: return "SupportMaterialInterface"; + case erSupportTransition: return "SupportTransition"; + case erWipeTower: return "WipeTower"; + case erCustom: + case erMixed: + case erCount: + case erNone: + default: return "Mixed"; + } +} + std::string encodeBase64(uint64_t value) { //Always use big endian mode diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 9fc63f63be..5e8d8d1934 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -205,6 +205,7 @@ public: // inside the generated string and after the G-code export finishes. std::string placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override = nullptr); bool enable_cooling_markers() const { return m_enable_cooling_markers; } + std::string extrusion_role_to_string_for_parser(const ExtrusionRole &); // For Perl bindings, to be used exclusively by unit tests. unsigned int layer_count() const { return m_layer_count; } diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index f09240129e..c8c158f930 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -819,7 +819,7 @@ static std::vector s_Preset_printer_options { "printer_technology", "printable_area", "bed_exclude_area","bed_custom_texture", "bed_custom_model", "gcode_flavor", "fan_kickstart", "fan_speedup_time", "fan_speedup_overhangs", - "single_extruder_multi_material", "manual_filament_change", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "layer_change_gcode", "time_lapse_gcode", "change_filament_gcode", + "single_extruder_multi_material", "manual_filament_change", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "layer_change_gcode", "time_lapse_gcode", "change_filament_gcode", "change_extrusion_role_gcode", "printer_model", "printer_variant", "printable_height", "extruder_clearance_radius", "extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod", "default_print_profile", "inherits", "silent_mode", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index aa63e6bfd7..2702e3b47f 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -3970,6 +3970,15 @@ def = this->add("filament_loading_speed", coFloats); def->mode = comAdvanced; def->set_default_value(new ConfigOptionString("")); + def = this->add("change_extrusion_role_gcode", coString); + def->label = L("Change extrusion role G-code"); + def->tooltip = L("This gcode is inserted when the extrusion role is changed"); + def->multiline = true; + def->full_width = true; + def->height = 5; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionString("")); + def = this->add("top_surface_line_width", coFloatOrPercent); def->label = L("Top surface"); def->category = L("Quality"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index fd853e1d0c..a44137a1ae 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -969,6 +969,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBool, single_extruder_multi_material_priming)) ((ConfigOptionBool, wipe_tower_no_sparse_layers)) ((ConfigOptionString, change_filament_gcode)) + ((ConfigOptionString, change_extrusion_role_gcode)) ((ConfigOptionFloat, travel_speed)) ((ConfigOptionFloat, travel_speed_z)) ((ConfigOptionBool, silent_mode)) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 312944a524..9a38c7409a 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3231,6 +3231,17 @@ void TabPrinter::build_fff() option.opt.height = gcode_field_height;//150; optgroup->append_single_option_line(option); + optgroup = page->new_optgroup(L("Change extrusion role G-code"), L"param_gcode", 0); + optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { + validate_custom_gcode_cb(this, optgroup, opt_key, value); + }; + + option = optgroup->get_option("change_extrusion_role_gcode"); + option.opt.full_width = true; + option.opt.is_code = true; + option.opt.height = gcode_field_height;//150; + optgroup->append_single_option_line(option); + optgroup = page->new_optgroup(L("Pause G-code"), L"param_gcode", 0); optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { validate_custom_gcode_cb(this, optgroup, opt_key, value);