diff --git a/src/libslic3r/GCode/CoolingBuffer.cpp b/src/libslic3r/GCode/CoolingBuffer.cpp index fb2d12a680f..5b1ab626fda 100644 --- a/src/libslic3r/GCode/CoolingBuffer.cpp +++ b/src/libslic3r/GCode/CoolingBuffer.cpp @@ -730,7 +730,10 @@ std::string CoolingBuffer::apply_layer_cooldown( new_gcode.reserve(gcode.size() * 2); bool bridge_fan_control = false; int bridge_fan_speed = 0; - auto change_extruder_set_fan = [ this, layer_id, layer_time, &new_gcode, &bridge_fan_control, &bridge_fan_speed ]() { + int external_perimeter_fan_speed = 0; + bool in_external_perimeter = false; + auto change_extruder_set_fan = [ this, layer_id, layer_time, &new_gcode, &bridge_fan_control, &bridge_fan_speed, &external_perimeter_fan_speed, &in_external_perimeter]() { + in_external_perimeter = false; #define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_current_extruder) int min_fan_speed = EXTRUDER_CONFIG(min_fan_speed); int fan_speed_new = EXTRUDER_CONFIG(fan_always_on) ? min_fan_speed : 0; @@ -743,6 +746,7 @@ std::string CoolingBuffer::apply_layer_cooldown( disable_fan_first_layers = 1; } if (int(layer_id) >= disable_fan_first_layers) { + external_perimeter_fan_speed = EXTRUDER_CONFIG(external_perimeter_fan_speed); int max_fan_speed = EXTRUDER_CONFIG(max_fan_speed); float slowdown_below_layer_time = float(EXTRUDER_CONFIG(slowdown_below_layer_time)); float fan_below_layer_time = float(EXTRUDER_CONFIG(fan_below_layer_time)); @@ -756,6 +760,9 @@ std::string CoolingBuffer::apply_layer_cooldown( double t = (layer_time - slowdown_below_layer_time) / (fan_below_layer_time - slowdown_below_layer_time); fan_speed_new = int(floor(t * min_fan_speed + (1. - t) * max_fan_speed) + 0.5); } + // Use the higher of the adjusted speeds if both external perimeter and automatic cooling are enabled. + if (external_perimeter_fan_speed && fan_speed_new > external_perimeter_fan_speed) + external_perimeter_fan_speed = fan_speed_new; } bridge_fan_speed = EXTRUDER_CONFIG(bridge_fan_speed); if (int(layer_id) >= disable_fan_first_layers && int(layer_id) + 1 < full_fan_speed_layer) { @@ -763,6 +770,7 @@ std::string CoolingBuffer::apply_layer_cooldown( float factor = float(int(layer_id + 1) - disable_fan_first_layers) / float(full_fan_speed_layer - disable_fan_first_layers); fan_speed_new = std::clamp(int(float(fan_speed_new) * factor + 0.5f), 0, 255); bridge_fan_speed = std::clamp(int(float(bridge_fan_speed) * factor + 0.5f), 0, 255); + external_perimeter_fan_speed = std::clamp(int(float(external_perimeter_fan_speed) * factor + 0.5f), 0, 255); } #undef EXTRUDER_CONFIG bridge_fan_control = bridge_fan_speed > fan_speed_new; @@ -770,6 +778,7 @@ std::string CoolingBuffer::apply_layer_cooldown( bridge_fan_control = false; bridge_fan_speed = 0; fan_speed_new = 0; + external_perimeter_fan_speed = 0; } if (fan_speed_new != m_fan_speed) { m_fan_speed = fan_speed_new; @@ -783,6 +792,16 @@ std::string CoolingBuffer::apply_layer_cooldown( for (const CoolingLine *line : lines) { const char *line_start = gcode.c_str() + line->line_start; const char *line_end = gcode.c_str() + line->line_end; + + // Adjust the fan speed for external perimeters only when the setting is enabled and we would need to adjust the speed. + bool adjust_fan_speed_on_external_perimeter = !!external_perimeter_fan_speed && m_fan_speed != external_perimeter_fan_speed; + + if (adjust_fan_speed_on_external_perimeter) { + bool prev_in_external_perimeter = in_external_perimeter; + in_external_perimeter = line->type & CoolingLine::TYPE_EXTERNAL_PERIMETER; + adjust_fan_speed_on_external_perimeter = in_external_perimeter != prev_in_external_perimeter; + } + if (line_start > pos) new_gcode.append(pos, line_start - pos); if (line->type & CoolingLine::TYPE_SET_TOOL) { @@ -800,8 +819,11 @@ std::string CoolingBuffer::apply_layer_cooldown( if (bridge_fan_control) new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_config.gcode_comments, m_fan_speed); } else if (line->type & CoolingLine::TYPE_EXTRUDE_END) { - // Just remove this comment. + if (adjust_fan_speed_on_external_perimeter) + new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_config.gcode_comments, m_fan_speed); } else if (line->type & (CoolingLine::TYPE_ADJUSTABLE | CoolingLine::TYPE_ADJUSTABLE_EMPTY | CoolingLine::TYPE_EXTERNAL_PERIMETER | CoolingLine::TYPE_WIPE | CoolingLine::TYPE_HAS_F)) { + if (adjust_fan_speed_on_external_perimeter) + new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_config.gcode_comments, external_perimeter_fan_speed); // Find the start of a comment, or roll to the end of line. const char *end = line_start; for (; end < line_end && *end != ';'; ++ end); diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index eebb4d54f80..367c2f70424 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -473,7 +473,7 @@ static std::vector s_Preset_filament_options { "filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", "filament_minimal_purge_on_wipe_tower", "temperature", "idle_temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed", "max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers", "full_fan_speed_layer", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed", - "start_filament_gcode", "end_filament_gcode", + "start_filament_gcode", "end_filament_gcode", "external_perimeter_fan_speed", // Retract overrides "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_wipe", "filament_retract_before_wipe", diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 3c810b178e6..6969930ff37 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -75,6 +75,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n "end_gcode", "end_filament_gcode", "external_perimeter_acceleration", + "external_perimeter_fan_speed", "extrusion_axis", "extruder_clearance_height", "extruder_clearance_radius", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 625b1a55496..b5dc7ec8d49 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -794,6 +794,18 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloatOrPercent(0, false)); + def = this->add("external_perimeter_fan_speed", coInts); + def->label = L("External perimeter fan speed"); + def->tooltip = L("When set to a non-zero value this fan speed is used only for external perimeters (visible ones). " + "When set to zero the normal fan speed is used on external perimeters. " + "External perimeters can benefit from higher fan speed to improve surface finish, " + "while internal perimeters, infill, etc. benefit from lower fan speed to improve layer adhesion."); + def->sidetext = L("%"); + def->min = 0; + def->max = 100; + def->mode = comExpert; + def->set_default_value(new ConfigOptionInts { 0 }); + def = this->add("external_perimeter_speed", coFloatOrPercent); def->label = L("External perimeters"); def->category = L("Speed"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index b8995714903..fdd347132b0 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -755,6 +755,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionEnum, draft_shield)) ((ConfigOptionFloat, duplicate_distance)) ((ConfigOptionFloat, external_perimeter_acceleration)) + ((ConfigOptionInts, external_perimeter_fan_speed)) ((ConfigOptionFloat, extruder_clearance_height)) ((ConfigOptionFloat, extruder_clearance_radius)) ((ConfigOptionStrings, extruder_colour)) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 17ddd63abd4..6ad6df48c7b 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1990,6 +1990,7 @@ void TabFilament::build() line.append_option(optgroup->get_option("max_fan_speed")); optgroup->append_line(line); + optgroup->append_single_option_line("external_perimeter_fan_speed", category_path + "fan-settings"); optgroup->append_single_option_line("bridge_fan_speed", category_path + "fan-settings"); optgroup->append_single_option_line("disable_fan_first_layers", category_path + "fan-settings"); optgroup->append_single_option_line("full_fan_speed_layer", category_path + "fan-settings");