From 9198f9e26eb4f49296d3a88e6f182ae95c908968 Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 22 Dec 2021 17:47:53 +0100 Subject: [PATCH] Fix 'avoid crossing perimeters' when wipe enabled. Also add a new setting to say if the wipe is really needed if 'avoid crossing perimeters' activated & no crossing. supermerill/SuperSlicer#1069 --- resources/ui_layout/extruder.ui | 1 + src/libslic3r/GCode.cpp | 64 ++++++++++++++++++++++++--------- src/libslic3r/GCode.hpp | 2 +- src/libslic3r/Preset.cpp | 2 +- src/libslic3r/Print.cpp | 1 + src/libslic3r/PrintConfig.cpp | 13 ++++++- src/libslic3r/PrintConfig.hpp | 2 ++ src/slic3r/GUI/Tab.cpp | 22 ++++++++++-- 8 files changed, 85 insertions(+), 22 deletions(-) diff --git a/resources/ui_layout/extruder.ui b/resources/ui_layout/extruder.ui index e6ecdaddf..eb2c5a6ef 100644 --- a/resources/ui_layout/extruder.ui +++ b/resources/ui_layout/extruder.ui @@ -33,6 +33,7 @@ group:Retraction wipe setting:idx:wipe setting:idx:wipe_speed setting:idx:retract_before_wipe + setting:idx:wipe_only_crossing setting:idx:wipe_extra_perimeter setting:idx:seam_gap group:Retraction when tool is disabled (advanced settings for multi-extruder setups) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 023d53593..362127cc0 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -3382,6 +3382,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s prev_point = current_point; current_point = pt; gcode += m_writer.travel_to_xy(this->point_to_gcode(pt), 0.0, config().gcode_comments ? "; extra wipe" : ""); + this->set_last_pos(pt); } } } @@ -3417,6 +3418,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s pt.rotate(angle, current_point); // generate the travel move gcode += m_writer.travel_to_xy(this->point_to_gcode(pt), 0.0, "move inwards before travel"); + this->set_last_pos(pt); gcode += ";" + GCodeProcessor::Wipe_End_Tag + "\n"; // also shift the wipe on retract @@ -3441,6 +3443,25 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s } } } + if (best_sqr_dist == nd * nd * 2) { + //try to find an edge + for (size_t poly_idx = 0; poly_idx < polys.size(); poly_idx++) { + Polygon& poly = polys[poly_idx]; + if (poly.is_clockwise() ^ original_polygon.is_clockwise()) + poly.reverse(); + poly.points.push_back(poly.points.front()); + for (size_t pt_idx = 0; pt_idx < poly.points.size()-1; pt_idx++) { + if (Line{ poly.points[pt_idx], poly.points[pt_idx + 1] }.distance_to_squared(pt) < best_sqr_dist) { + poly.points.insert(poly.points.begin() + pt_idx + 1, pt); + best_sqr_dist = 0; + best_poly_idx = poly_idx; + best_pt_idx = pt_idx + 1; + poly.points.erase(poly.points.end() - 1); + break; + } + } + } + } if (best_sqr_dist == nd * nd * 2) { //can't find a path, use the old one //BOOST_LOG_TRIVIAL(warning) << "Warn: can't find a proper path for wipe on retract. Layer " << m_layer_index << ", pos " << this->point_to_gcode(pt).x() << " : " << this->point_to_gcode(pt).y() << " !"; @@ -4228,40 +4249,49 @@ Polyline GCode::travel_to(std::string &gcode, const Point &point, ExtrusionRole this->origin in order to get G-code coordinates. */ Polyline travel { this->last_pos(), point }; - // check / compute avoid_crossing_perimeters - bool will_cross_perimeter = this->can_cross_perimeter(travel); // check whether wipe could be disabled without causing visible stringing bool could_be_wipe_disabled = false; + //can use the avoid crossing algo? + bool can_avoid_cross_peri = m_config.avoid_crossing_perimeters + && !m_avoid_crossing_perimeters.disabled_once() + && m_avoid_crossing_perimeters.is_init() + && !(m_config.avoid_crossing_not_first_layer && this->on_first_layer()); + + // check / compute avoid_crossing_perimeters + bool will_cross_perimeter = this->can_cross_perimeter(travel, can_avoid_cross_peri); + // if a retraction would be needed (with a low min_dist threshold), try to use avoid_crossing_perimeters to plan a // multi-hop travel path inside the configuration space if (will_cross_perimeter && this->needs_retraction(travel, role, scale_d(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0.4)) * 3) - && m_config.avoid_crossing_perimeters - && ! m_avoid_crossing_perimeters.disabled_once() - && m_avoid_crossing_perimeters.is_init() - && !(m_config.avoid_crossing_not_first_layer && this->on_first_layer())) { + && can_avoid_cross_peri) { travel = m_avoid_crossing_perimeters.travel_to(*this, point, &could_be_wipe_disabled); } + if(can_avoid_cross_peri) + will_cross_perimeter = this->can_cross_perimeter(travel, false); // check whether a straight travel move would need retraction bool needs_retraction = this->needs_retraction(travel, role); + if (m_config.only_retract_when_crossing_perimeters) + needs_retraction = needs_retraction && will_cross_perimeter; // Re-allow avoid_crossing_perimeters for the next travel moves m_avoid_crossing_perimeters.reset_once_modifiers(); // generate G-code for the travel move if (needs_retraction) { - if (m_config.avoid_crossing_perimeters && could_be_wipe_disabled) + if (m_config.avoid_crossing_perimeters && could_be_wipe_disabled && EXTRUDER_CONFIG_WITH_DEFAULT(wipe_only_crossing, true)) m_wipe.reset_path(); Point last_post_before_retract = this->last_pos(); gcode += this->retract(); // When "Wipe while retracting" is enabled, then extruder moves to another position, and travel from this position can cross perimeters. - // Because of it, it is necessary to call avoid crossing perimeters for the path between previous last_post and last_post after calling retraction() - if (last_post_before_retract != this->last_pos() && m_config.avoid_crossing_perimeters) { - Polyline retract_travel = m_avoid_crossing_perimeters.travel_to(*this, last_post_before_retract); - append(retract_travel.points, travel.points); - travel = std::move(retract_travel); + if (last_post_before_retract != this->last_pos() && can_avoid_cross_peri) { + // Is the distance is short enough to just shortcut it? + if (last_post_before_retract.distance_to(this->last_pos()) > scale_d(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0.4)) * 2) { + // Because of it, it is necessary to redo the thing + travel = m_avoid_crossing_perimeters.travel_to(*this, point); + } } } else { // Reset the wipe path when traveling, so one would not wipe along an old path. @@ -4369,7 +4399,7 @@ bool GCode::needs_retraction(const Polyline& travel, ExtrusionRole role /*=erNon return true; } -bool GCode::can_cross_perimeter(const Polyline& travel) +bool GCode::can_cross_perimeter(const Polyline& travel, bool offset) { if(m_layer != nullptr) if ( (m_config.only_retract_when_crossing_perimeters && m_config.fill_density.value > 0) || m_config.avoid_crossing_perimeters) @@ -4388,13 +4418,13 @@ bool GCode::can_cross_perimeter(const Polyline& travel) //if (inside) { //contained inside at least one bb //construct m_layer_slices_offseted if needed - if (m_layer_slices_offseted.layer != m_layer) { + if (m_layer_slices_offseted.layer != m_layer && offset) { m_layer_slices_offseted.layer = m_layer; m_layer_slices_offseted.diameter = scale_t(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0.4)); - m_layer_slices_offseted.slices = offset_ex(m_layer->lslices, - m_layer_slices_offseted.diameter * 1.5); + m_layer_slices_offseted.slices = offset_ex(m_layer->lslices, -m_layer_slices_offseted.diameter * 1.5f); } // test if a expoly contains the entire travel - for (const ExPolygon &poly : m_layer_slices_offseted.slices) + for (const ExPolygon &poly : offset ? m_layer_slices_offseted.slices : m_layer->lslices) if (poly.contains(travel)) { return false; } @@ -4427,6 +4457,8 @@ std::string GCode::retract(bool toolchange) methods even if we performed wipe, since this will ensure the entire retraction length is honored in case wipe path was too short. */ gcode += toolchange ? m_writer.retract_for_toolchange() : m_writer.retract(); + + //check if need to lift bool need_lift = !m_writer.tool_is_extruder() || toolchange || (BOOL_EXTRUDER_CONFIG(retract_lift_first_layer) && m_config.print_retract_lift.value != 0 && this->m_layer_index == 0) || this->m_writer.get_extra_lift() > 0; diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 7fab43e75..bfa644595 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -318,7 +318,7 @@ private: Polyline travel_to(std::string& gcode, const Point &point, ExtrusionRole role); void write_travel_to(std::string& gcode, const Polyline& travel, std::string comment); - bool can_cross_perimeter(const Polyline& travel); + bool can_cross_perimeter(const Polyline& travel, bool offset); bool needs_retraction(const Polyline& travel, ExtrusionRole role = erNone, coordf_t max_min_dist = 0); std::string retract(bool toolchange = false); std::string unretract() { return m_writer.unlift() + m_writer.unretract(); } diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 45eace66b..7545b3074 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -697,7 +697,7 @@ const std::vector& Preset::filament_options() "filament_retract_length", "filament_retract_lift", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_speed", "filament_deretract_speed", "filament_retract_restart_extra", "filament_retract_before_travel", "filament_retract_layer_change", "filament_retract_before_wipe", "filament_seam_gap", - "filament_wipe", "filament_wipe_extra_perimeter", "filament_wipe_speed", + "filament_wipe", "filament_wipe_only_crossing", "filament_wipe_extra_perimeter", "filament_wipe_speed", // Profile compatibility "filament_vendor", "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits" //merill adds diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 9043d0cde..1132af8dd 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -185,6 +185,7 @@ bool Print::invalidate_state_by_config_options(const std::vectoris_vector_extruder = true; def->set_default_value(new ConfigOptionBools{ false }); + def = this->add("wipe_only_crossing", coBools); + def->label = L("Wipe only when crossing perimeters"); + def->category = OptionCategory::extruders; + def->tooltip = L("Don't wipe when you don't cross a perimeter."); + def->mode = comAdvanced; + def->is_vector_extruder = true; + def->set_default_value(new ConfigOptionBools{ true }); + def = this->add("wipe_speed", coFloats); def->label = L("Wipe speed"); def->category = OptionCategory::extruders; @@ -4843,7 +4851,7 @@ void PrintConfigDef::init_fff_params() "retract_length", "retract_lift", "retract_lift_above", "retract_lift_below", "retract_speed", "deretract_speed", "retract_restart_extra", "retract_before_travel", "wipe_extra_perimeter", "wipe_speed", // bools - "retract_layer_change", "wipe", + "retract_layer_change", "wipe", "wipe_only_crossing", // percents "retract_before_wipe", // floatsOrPercents @@ -4896,6 +4904,7 @@ void PrintConfigDef::init_extruder_option_keys() "tool_name", "wipe", "wipe_extra_perimeter", + "wipe_only_crossing", "wipe_speed", }; @@ -4913,6 +4922,7 @@ void PrintConfigDef::init_extruder_option_keys() "seam_gap", "wipe", "wipe_extra_perimeter", + "wipe_only_crossing", "wipe_speed", }; assert(std::is_sorted(m_extruder_retract_keys.begin(), m_extruder_retract_keys.end())); @@ -6112,6 +6122,7 @@ std::unordered_set prusa_export_to_remove_keys = { "wipe_advanced_nozzle_melted_volume", "wipe_advanced", "wipe_extra_perimeter", +"wipe_only_crossing", "wipe_speed", "wipe_tower_brim", "xy_inner_size_compensation", diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 8e64e70ea..1c37e9189 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1177,6 +1177,7 @@ public: ConfigOptionFloat wipe_advanced_multiplier; ConfigOptionFloats wipe_extra_perimeter; ConfigOptionEnum wipe_advanced_algo; + ConfigOptionBools wipe_only_crossing; ConfigOptionFloats wipe_speed; ConfigOptionFloat z_step; ConfigOptionString color_change_gcode; @@ -1294,6 +1295,7 @@ protected: OPT_PTR(wipe_advanced_multiplier); OPT_PTR(wipe_advanced_algo); OPT_PTR(wipe_extra_perimeter); + OPT_PTR(wipe_only_crossing); OPT_PTR(wipe_speed); OPT_PTR(z_step); OPT_PTR(color_change_gcode); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 0f63501bc..38ec11954 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2348,6 +2348,7 @@ void TabFilament::add_filament_overrides_page() "filament_retract_layer_change", "filament_seam_gap", "filament_wipe", + "filament_wipe_extra_perimeter", "filament_wipe_speed", "filament_wipe_extra_perimeter" }) @@ -2377,6 +2378,7 @@ void TabFilament::update_filament_overrides_page() "filament_retract_layer_change", "filament_seam_gap", "filament_wipe", + "filament_wipe_extra_perimeter", "filament_wipe_speed", "filament_wipe_extra_perimeter" }; @@ -2923,11 +2925,21 @@ void TabPrinter::clear_pages() void TabPrinter::toggle_options() { - if (!m_active_page || m_presets->get_edited_preset().printer_technology() == ptSLA) + if (!m_active_page || m_presets->get_edited_preset().printer_technology() != ptFFF) return; Field* field; + const DynamicPrintConfig& print_config = m_preset_bundle->fff_prints.get_edited_preset().config; + const DynamicPrintConfig& filament_config = m_preset_bundle->filaments.get_edited_preset().config; + const DynamicPrintConfig& printer_config = m_preset_bundle->printers.get_edited_preset().config; + + // Print config values + DynamicPrintConfig full_print_config; + full_print_config.apply(print_config); + full_print_config.apply(filament_config); + full_print_config.apply(printer_config); + bool have_multiple_extruders = m_extruders_count > 1; field = get_field("toolchange_gcode"); if (field) field->toggle(have_multiple_extruders); @@ -3004,7 +3016,7 @@ void TabPrinter::toggle_options() // some options only apply when not using firmware retraction vec.resize(0); - vec = { "retract_speed", "deretract_speed", "retract_before_wipe", "retract_restart_extra", "wipe", "wipe_speed" }; + vec = { "retract_speed", "deretract_speed", "retract_before_wipe", "retract_restart_extra", "wipe", "wipe_speed" , "wipe_only_crossing"}; for (auto el : vec) { field = get_field(el, i); if (field) @@ -3012,13 +3024,17 @@ void TabPrinter::toggle_options() } bool wipe = m_config->opt_bool("wipe", i) && have_retract_length; - vec = { "retract_before_wipe", "wipe_speed" }; + vec = { "retract_before_wipe", "wipe_only_crossing", "wipe_speed" }; for (auto el : vec) { field = get_field(el, i); if (field) field->toggle(wipe); } + // wipe_only_crossing can only work if avoid_crossing_perimeters + if (!full_print_config.opt_bool("avoid_crossing_perimeters")) + get_field("wipe_only_crossing", i)->toggle(false); + if (use_firmware_retraction && wipe) { wxMessageDialog dialog(parent(), _(L("The Wipe option is not available when using the Firmware Retraction mode.\n"