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
This commit is contained in:
supermerill 2021-12-22 17:47:53 +01:00
parent 5b2cda2e9c
commit 9198f9e26e
8 changed files with 85 additions and 22 deletions

View File

@ -33,6 +33,7 @@ group:Retraction wipe
setting:idx:wipe setting:idx:wipe
setting:idx:wipe_speed setting:idx:wipe_speed
setting:idx:retract_before_wipe setting:idx:retract_before_wipe
setting:idx:wipe_only_crossing
setting:idx:wipe_extra_perimeter setting:idx:wipe_extra_perimeter
setting:idx:seam_gap setting:idx:seam_gap
group:Retraction when tool is disabled (advanced settings for multi-extruder setups) group:Retraction when tool is disabled (advanced settings for multi-extruder setups)

View File

@ -3382,6 +3382,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s
prev_point = current_point; prev_point = current_point;
current_point = pt; current_point = pt;
gcode += m_writer.travel_to_xy(this->point_to_gcode(pt), 0.0, config().gcode_comments ? "; extra wipe" : ""); 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); pt.rotate(angle, current_point);
// generate the travel move // generate the travel move
gcode += m_writer.travel_to_xy(this->point_to_gcode(pt), 0.0, "move inwards before travel"); 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"; gcode += ";" + GCodeProcessor::Wipe_End_Tag + "\n";
// also shift the wipe on retract // 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) { if (best_sqr_dist == nd * nd * 2) {
//can't find a path, use the old one //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() << " !"; //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. */ this->origin in order to get G-code coordinates. */
Polyline travel { this->last_pos(), point }; 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 // check whether wipe could be disabled without causing visible stringing
bool could_be_wipe_disabled = false; 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 // 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 // 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) 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 && can_avoid_cross_peri) {
&& ! m_avoid_crossing_perimeters.disabled_once()
&& m_avoid_crossing_perimeters.is_init()
&& !(m_config.avoid_crossing_not_first_layer && this->on_first_layer())) {
travel = m_avoid_crossing_perimeters.travel_to(*this, point, &could_be_wipe_disabled); 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 // check whether a straight travel move would need retraction
bool needs_retraction = this->needs_retraction(travel, role); 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 // Re-allow avoid_crossing_perimeters for the next travel moves
m_avoid_crossing_perimeters.reset_once_modifiers(); m_avoid_crossing_perimeters.reset_once_modifiers();
// generate G-code for the travel move // generate G-code for the travel move
if (needs_retraction) { 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(); m_wipe.reset_path();
Point last_post_before_retract = this->last_pos(); Point last_post_before_retract = this->last_pos();
gcode += this->retract(); gcode += this->retract();
// When "Wipe while retracting" is enabled, then extruder moves to another position, and travel from this position can cross perimeters. // 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() && can_avoid_cross_peri) {
if (last_post_before_retract != this->last_pos() && m_config.avoid_crossing_perimeters) { // Is the distance is short enough to just shortcut it?
Polyline retract_travel = m_avoid_crossing_perimeters.travel_to(*this, last_post_before_retract); if (last_post_before_retract.distance_to(this->last_pos()) > scale_d(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0.4)) * 2) {
append(retract_travel.points, travel.points); // Because of it, it is necessary to redo the thing
travel = std::move(retract_travel); travel = m_avoid_crossing_perimeters.travel_to(*this, point);
}
} }
} else { } else {
// Reset the wipe path when traveling, so one would not wipe along an old path. // 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; 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_layer != nullptr)
if ( (m_config.only_retract_when_crossing_perimeters && m_config.fill_density.value > 0) || m_config.avoid_crossing_perimeters) 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) { //if (inside) {
//contained inside at least one bb //contained inside at least one bb
//construct m_layer_slices_offseted if needed //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.layer = m_layer;
m_layer_slices_offseted.diameter = scale_t(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0.4)); 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 // 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)) { if (poly.contains(travel)) {
return false; 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 methods even if we performed wipe, since this will ensure the entire retraction
length is honored in case wipe path was too short. */ length is honored in case wipe path was too short. */
gcode += toolchange ? m_writer.retract_for_toolchange() : m_writer.retract(); 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 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) || (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; || this->m_writer.get_extra_lift() > 0;

View File

@ -318,7 +318,7 @@ private:
Polyline travel_to(std::string& gcode, const Point &point, ExtrusionRole role); Polyline travel_to(std::string& gcode, const Point &point, ExtrusionRole role);
void write_travel_to(std::string& gcode, const Polyline& travel, std::string comment); 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); bool needs_retraction(const Polyline& travel, ExtrusionRole role = erNone, coordf_t max_min_dist = 0);
std::string retract(bool toolchange = false); std::string retract(bool toolchange = false);
std::string unretract() { return m_writer.unlift() + m_writer.unretract(); } std::string unretract() { return m_writer.unlift() + m_writer.unretract(); }

View File

@ -697,7 +697,7 @@ const std::vector<std::string>& 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_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_retract_layer_change", "filament_retract_before_wipe",
"filament_seam_gap", "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 // Profile compatibility
"filament_vendor", "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits" "filament_vendor", "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits"
//merill adds //merill adds

View File

@ -185,6 +185,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
"use_volumetric_e", "use_volumetric_e",
"variable_layer_height", "variable_layer_height",
"wipe", "wipe",
"wipe_only_crossing",
"wipe_speed", "wipe_speed",
"wipe_extra_perimeter" "wipe_extra_perimeter"
}; };

View File

@ -4579,6 +4579,14 @@ void PrintConfigDef::init_fff_params()
def->is_vector_extruder = true; def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionBools{ false }); 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 = this->add("wipe_speed", coFloats);
def->label = L("Wipe speed"); def->label = L("Wipe speed");
def->category = OptionCategory::extruders; 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", "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", "wipe_extra_perimeter", "wipe_speed",
// bools // bools
"retract_layer_change", "wipe", "retract_layer_change", "wipe", "wipe_only_crossing",
// percents // percents
"retract_before_wipe", "retract_before_wipe",
// floatsOrPercents // floatsOrPercents
@ -4896,6 +4904,7 @@ void PrintConfigDef::init_extruder_option_keys()
"tool_name", "tool_name",
"wipe", "wipe",
"wipe_extra_perimeter", "wipe_extra_perimeter",
"wipe_only_crossing",
"wipe_speed", "wipe_speed",
}; };
@ -4913,6 +4922,7 @@ void PrintConfigDef::init_extruder_option_keys()
"seam_gap", "seam_gap",
"wipe", "wipe",
"wipe_extra_perimeter", "wipe_extra_perimeter",
"wipe_only_crossing",
"wipe_speed", "wipe_speed",
}; };
assert(std::is_sorted(m_extruder_retract_keys.begin(), m_extruder_retract_keys.end())); assert(std::is_sorted(m_extruder_retract_keys.begin(), m_extruder_retract_keys.end()));
@ -6112,6 +6122,7 @@ std::unordered_set<std::string> prusa_export_to_remove_keys = {
"wipe_advanced_nozzle_melted_volume", "wipe_advanced_nozzle_melted_volume",
"wipe_advanced", "wipe_advanced",
"wipe_extra_perimeter", "wipe_extra_perimeter",
"wipe_only_crossing",
"wipe_speed", "wipe_speed",
"wipe_tower_brim", "wipe_tower_brim",
"xy_inner_size_compensation", "xy_inner_size_compensation",

View File

@ -1177,6 +1177,7 @@ public:
ConfigOptionFloat wipe_advanced_multiplier; ConfigOptionFloat wipe_advanced_multiplier;
ConfigOptionFloats wipe_extra_perimeter; ConfigOptionFloats wipe_extra_perimeter;
ConfigOptionEnum<WipeAlgo> wipe_advanced_algo; ConfigOptionEnum<WipeAlgo> wipe_advanced_algo;
ConfigOptionBools wipe_only_crossing;
ConfigOptionFloats wipe_speed; ConfigOptionFloats wipe_speed;
ConfigOptionFloat z_step; ConfigOptionFloat z_step;
ConfigOptionString color_change_gcode; ConfigOptionString color_change_gcode;
@ -1294,6 +1295,7 @@ protected:
OPT_PTR(wipe_advanced_multiplier); OPT_PTR(wipe_advanced_multiplier);
OPT_PTR(wipe_advanced_algo); OPT_PTR(wipe_advanced_algo);
OPT_PTR(wipe_extra_perimeter); OPT_PTR(wipe_extra_perimeter);
OPT_PTR(wipe_only_crossing);
OPT_PTR(wipe_speed); OPT_PTR(wipe_speed);
OPT_PTR(z_step); OPT_PTR(z_step);
OPT_PTR(color_change_gcode); OPT_PTR(color_change_gcode);

View File

@ -2348,6 +2348,7 @@ void TabFilament::add_filament_overrides_page()
"filament_retract_layer_change", "filament_retract_layer_change",
"filament_seam_gap", "filament_seam_gap",
"filament_wipe", "filament_wipe",
"filament_wipe_extra_perimeter",
"filament_wipe_speed", "filament_wipe_speed",
"filament_wipe_extra_perimeter" "filament_wipe_extra_perimeter"
}) })
@ -2377,6 +2378,7 @@ void TabFilament::update_filament_overrides_page()
"filament_retract_layer_change", "filament_retract_layer_change",
"filament_seam_gap", "filament_seam_gap",
"filament_wipe", "filament_wipe",
"filament_wipe_extra_perimeter",
"filament_wipe_speed", "filament_wipe_speed",
"filament_wipe_extra_perimeter" "filament_wipe_extra_perimeter"
}; };
@ -2923,11 +2925,21 @@ void TabPrinter::clear_pages()
void TabPrinter::toggle_options() 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; return;
Field* field; 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; bool have_multiple_extruders = m_extruders_count > 1;
field = get_field("toolchange_gcode"); field = get_field("toolchange_gcode");
if (field) field->toggle(have_multiple_extruders); if (field) field->toggle(have_multiple_extruders);
@ -3004,7 +3016,7 @@ void TabPrinter::toggle_options()
// some options only apply when not using firmware retraction // some options only apply when not using firmware retraction
vec.resize(0); 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) { for (auto el : vec) {
field = get_field(el, i); field = get_field(el, i);
if (field) if (field)
@ -3012,13 +3024,17 @@ void TabPrinter::toggle_options()
} }
bool wipe = m_config->opt_bool("wipe", i) && have_retract_length; 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) { for (auto el : vec) {
field = get_field(el, i); field = get_field(el, i);
if (field) if (field)
field->toggle(wipe); 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) { if (use_firmware_retraction && wipe) {
wxMessageDialog dialog(parent(), wxMessageDialog dialog(parent(),
_(L("The Wipe option is not available when using the Firmware Retraction mode.\n" _(L("The Wipe option is not available when using the Firmware Retraction mode.\n"