Merge branch 'lh_dynamic_fan_speed_fix'

This commit is contained in:
Lukas Matena 2024-08-09 09:57:10 +02:00
commit a2cabdd74b
6 changed files with 243 additions and 115 deletions

View File

@ -2874,10 +2874,37 @@ std::string GCodeGenerator::change_layer(
std::string GCodeGenerator::extrude_smooth_path(
const GCode::SmoothPath &smooth_path, const bool is_loop, const std::string_view description, const double speed
) {
// Extrude along the smooth path.
std::string gcode;
for (const GCode::SmoothPathElement &el : smooth_path)
gcode += this->_extrude(el.path_attributes, el.path, description, speed);
// Extrude along the smooth path.
bool is_bridge_extruded = false;
EmitModifiers emit_modifiers = EmitModifiers::create_with_disabled_emits();
for (auto el_it = smooth_path.begin(); el_it != smooth_path.end(); ++el_it) {
const auto next_el_it = next(el_it);
// By default, GCodeGenerator::_extrude() emit markers _BRIDGE_FAN_START, _BRIDGE_FAN_END and _RESET_FAN_SPEED for every extrusion.
// Together with split extrusions because of different ExtrusionAttributes, this could flood g-code with those markers and then
// produce an unnecessary number of duplicity M106.
// To prevent this, we control when each marker should be emitted by EmitModifiers, which allows determining when a bridge starts and ends,
// even when it is split into several extrusions.
if (el_it->path_attributes.role.is_bridge()) {
emit_modifiers.emit_bridge_fan_start = !is_bridge_extruded;
emit_modifiers.emit_bridge_fan_end = next_el_it == smooth_path.end() || !next_el_it->path_attributes.role.is_bridge();
is_bridge_extruded = true;
} else if (is_bridge_extruded) {
emit_modifiers.emit_bridge_fan_start = false;
emit_modifiers.emit_bridge_fan_end = false;
is_bridge_extruded = false;
}
// Ensure that just for the last extrusion from the smooth path, the fan speed will be reset back
// to the value calculated by the CoolingBuffer.
if (next_el_it == smooth_path.end()) {
emit_modifiers.emit_fan_speed_reset = true;
}
gcode += this->_extrude(el_it->path_attributes, el_it->path, description, speed, emit_modifiers);
}
// reset acceleration
gcode += m_writer.set_print_acceleration(fast_round_up<unsigned int>(m_config.default_acceleration.value));
@ -2889,6 +2916,7 @@ std::string GCodeGenerator::extrude_smooth_path(
GCode::reverse(reversed_smooth_path);
m_wipe.set_path(std::move(reversed_smooth_path));
}
return gcode;
}
@ -3115,7 +3143,8 @@ std::string GCodeGenerator::_extrude(
const ExtrusionAttributes &path_attr,
const Geometry::ArcWelder::Path &path,
const std::string_view description,
double speed)
double speed,
const EmitModifiers &emit_modifiers)
{
std::string gcode;
const std::string_view description_bridge = path_attr.role.is_bridge() ? " (bridge)"sv : ""sv;
@ -3217,21 +3246,21 @@ std::string GCodeGenerator::_extrude(
else if (this->object_layer_over_raft())
speed = m_config.get_abs_value("first_layer_speed_over_raft", speed);
std::pair<float, float> dynamic_speed_and_fan_speed{-1, -1};
ExtrusionProcessor::OverhangSpeeds dynamic_print_and_fan_speeds = {-1.f, -1.f};
if (path_attr.overhang_attributes.has_value()) {
double external_perim_reference_speed = m_config.get_abs_value("external_perimeter_speed");
if (external_perim_reference_speed == 0)
external_perim_reference_speed = m_volumetric_speed / path_attr.mm3_per_mm;
external_perim_reference_speed = cap_speed(
external_perim_reference_speed, m_config, m_writer.extruder()->id(), path_attr
);
double external_perimeter_reference_speed = m_config.get_abs_value("external_perimeter_speed");
if (external_perimeter_reference_speed == 0) {
external_perimeter_reference_speed = m_volumetric_speed / path_attr.mm3_per_mm;
}
dynamic_speed_and_fan_speed = ExtrusionProcessor::calculate_overhang_speed(path_attr, this->m_config, m_writer.extruder()->id(),
external_perim_reference_speed, speed);
external_perimeter_reference_speed = cap_speed(external_perimeter_reference_speed, m_config, m_writer.extruder()->id(), path_attr);
dynamic_print_and_fan_speeds = ExtrusionProcessor::calculate_overhang_speed(path_attr, this->m_config, m_writer.extruder()->id(),
float(external_perimeter_reference_speed), float(speed),
m_current_dynamic_fan_speed);
}
if (dynamic_speed_and_fan_speed.first > -1) {
speed = dynamic_speed_and_fan_speed.first;
if (dynamic_print_and_fan_speeds.print_speed > -1) {
speed = dynamic_print_and_fan_speeds.print_speed;
}
// cap speed with max_volumetric_speed anyway (even if user is not using autospeed)
@ -3282,18 +3311,30 @@ std::string GCodeGenerator::_extrude(
std::string cooling_marker_setspeed_comments;
if (m_enable_cooling_markers) {
if (path_attr.role.is_bridge())
if (path_attr.role.is_bridge() && emit_modifiers.emit_bridge_fan_start) {
gcode += ";_BRIDGE_FAN_START\n";
else
} else if (!path_attr.role.is_bridge()) {
cooling_marker_setspeed_comments = ";_EXTRUDE_SET_SPEED";
if (path_attr.role == ExtrusionRole::ExternalPerimeter)
}
if (path_attr.role == ExtrusionRole::ExternalPerimeter) {
cooling_marker_setspeed_comments += ";_EXTERNAL_PERIMETER";
}
}
// F is mm per minute.
gcode += m_writer.set_speed(F, "", cooling_marker_setspeed_comments);
if (dynamic_speed_and_fan_speed.second >= 0)
gcode += ";_SET_FAN_SPEED" + std::to_string(int(dynamic_speed_and_fan_speed.second)) + "\n";
if (dynamic_print_and_fan_speeds.fan_speed >= 0) {
const int fan_speed = int(dynamic_print_and_fan_speeds.fan_speed);
if (!m_current_dynamic_fan_speed.has_value() || (m_current_dynamic_fan_speed.has_value() && m_current_dynamic_fan_speed != fan_speed)) {
m_current_dynamic_fan_speed = fan_speed;
gcode += ";_SET_FAN_SPEED" + std::to_string(fan_speed) + "\n";
}
} else if (m_current_dynamic_fan_speed.has_value() && dynamic_print_and_fan_speeds.fan_speed < 0) {
m_current_dynamic_fan_speed.reset();
gcode += ";_RESET_FAN_SPEED\n";
}
std::string comment;
if (m_config.gcode_comments) {
@ -3343,11 +3384,18 @@ std::string GCodeGenerator::_extrude(
}
}
if (m_enable_cooling_markers)
gcode += path_attr.role.is_bridge() ? ";_BRIDGE_FAN_END\n" : ";_EXTRUDE_END\n";
if (m_enable_cooling_markers) {
if (path_attr.role.is_bridge() && emit_modifiers.emit_bridge_fan_end) {
gcode += ";_BRIDGE_FAN_END\n";
} else if (!path_attr.role.is_bridge()) {
gcode += ";_EXTRUDE_END\n";
}
}
if (dynamic_speed_and_fan_speed.second >= 0)
if (m_current_dynamic_fan_speed.has_value() && emit_modifiers.emit_fan_speed_reset) {
m_current_dynamic_fan_speed.reset();
gcode += ";_RESET_FAN_SPEED\n";
}
this->last_position = path.back().point;
return gcode;

View File

@ -436,6 +436,9 @@ private:
std::unique_ptr<PressureEqualizer> m_pressure_equalizer;
std::unique_ptr<GCode::WipeTowerIntegration> m_wipe_tower;
// Current fan speed set by dynamic fan speed control.
std::optional<float> m_current_dynamic_fan_speed;
// Heights (print_z) at which the skirt has already been extruded.
std::vector<coordf_t> m_skirt_done;
// Has the brim been extruded already? Brim is being extruded only for the first object of a multi-object print.
@ -455,8 +458,24 @@ private:
// Back-pointer to Print (const).
const Print* m_print;
std::string _extrude(
const ExtrusionAttributes &attribs, const Geometry::ArcWelder::Path &path, const std::string_view description, double speed = -1);
struct EmitModifiers {
EmitModifiers(bool emit_fan_speed_reset, bool emit_bridge_fan_start, bool emit_bridge_fan_end)
: emit_fan_speed_reset(emit_fan_speed_reset), emit_bridge_fan_start(emit_bridge_fan_start), emit_bridge_fan_end(emit_bridge_fan_end) {}
EmitModifiers() : EmitModifiers(true, true, true) {};
static EmitModifiers create_with_disabled_emits() {
return {false, false, false};
}
bool emit_fan_speed_reset = true;
bool emit_bridge_fan_start = true;
bool emit_bridge_fan_end = true;
};
std::string _extrude(const ExtrusionAttributes &attribs, const Geometry::ArcWelder::Path &path, std::string_view description, double speed, const EmitModifiers &emit_modifiers = EmitModifiers());
void print_machine_envelope(GCodeOutputStream &file, const Print &print);
void _print_first_layer_chamber_temperature(GCodeOutputStream &file, const Print &print, const std::string &gcode, int temp, bool wait, bool accurate);
void _print_first_layer_bed_temperature(GCodeOutputStream &file, const Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);

View File

@ -95,6 +95,7 @@ struct CoolingLine
TYPE_ADJUSTABLE_EMPTY = 1 << 16,
// Custom fan speed (introduced for overhang fan speed)
TYPE_SET_FAN_SPEED = 1 << 17,
// Reset fan speed back to speed calculate by the CoolingBuffer.
TYPE_RESET_FAN_SPEED = 1 << 18,
};
@ -571,19 +572,20 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
fast_float::from_chars(sline.data() + (has_S ? pos_S : pos_P) + 1, sline.data() + sline.size(), line.time);
if (has_P)
line.time *= 0.001f;
} else
} else {
line.time = 0;
line.time_max = line.time;
}
}
if (boost::contains(sline, ";_SET_FAN_SPEED")) {
line.time_max = line.time;
} else if (boost::contains(sline, ";_SET_FAN_SPEED")) {
auto speed_start = sline.find_last_of('D');
int speed = 0;
for (char num : sline.substr(speed_start + 1)) {
speed = speed * 10 + (num - '0');
}
line.type |= CoolingLine::TYPE_SET_FAN_SPEED;
line.fan_speed = speed;
line.type |= CoolingLine::TYPE_SET_FAN_SPEED;
} else if (boost::contains(sline, ";_RESET_FAN_SPEED")) {
line.type |= CoolingLine::TYPE_RESET_FAN_SPEED;
}
@ -820,14 +822,22 @@ 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]() {
auto change_extruder_set_fan = [this, layer_id, layer_time, &new_gcode, &bridge_fan_control, &bridge_fan_speed](const int requested_fan_speed = -1) {
#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;
std::pair<int, int> custom_fan_speed_limits{fan_speed_new, 100 };
int disable_fan_first_layers = EXTRUDER_CONFIG(disable_fan_first_layers);
const int min_fan_speed = EXTRUDER_CONFIG(min_fan_speed);
// Is the fan speed ramp enabled?
int full_fan_speed_layer = EXTRUDER_CONFIG(full_fan_speed_layer);
const int full_fan_speed_layer = EXTRUDER_CONFIG(full_fan_speed_layer);
int disable_fan_first_layers = EXTRUDER_CONFIG(disable_fan_first_layers);
int fan_speed_new = EXTRUDER_CONFIG(fan_always_on) ? min_fan_speed : 0;
struct FanSpeedRange
{
int min_speed;
int max_speed;
};
FanSpeedRange requested_fan_speed_limits{fan_speed_new, 100};
if (disable_fan_first_layers <= 0 && full_fan_speed_layer > 0) {
// When ramping up fan speed from disable_fan_first_layers to full_fan_speed_layer, force disable_fan_first_layers above zero,
// so there will be a zero fan speed at least at the 1st layer.
@ -840,43 +850,52 @@ std::string CoolingBuffer::apply_layer_cooldown(
if (EXTRUDER_CONFIG(cooling)) {
if (layer_time < slowdown_below_layer_time) {
// Layer time very short. Enable the fan to a full throttle.
fan_speed_new = max_fan_speed;
custom_fan_speed_limits.first = fan_speed_new;
fan_speed_new = max_fan_speed;
requested_fan_speed_limits.min_speed = max_fan_speed;
} else if (layer_time < fan_below_layer_time) {
// Layer time quite short. Enable the fan proportionally according to the current layer time.
assert(layer_time >= slowdown_below_layer_time);
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);
custom_fan_speed_limits.first = fan_speed_new;
const 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);
requested_fan_speed_limits.min_speed = fan_speed_new;
}
}
bridge_fan_speed = EXTRUDER_CONFIG(bridge_fan_speed);
bridge_fan_speed = EXTRUDER_CONFIG(bridge_fan_speed);
if (int(layer_id) >= disable_fan_first_layers && int(layer_id) + 1 < full_fan_speed_layer) {
// Ramp up the fan speed from disable_fan_first_layers to full_fan_speed_layer.
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, 100);
bridge_fan_speed = std::clamp(int(float(bridge_fan_speed) * factor + 0.5f), 0, 100);
custom_fan_speed_limits.second = fan_speed_new;
const 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, 100);
bridge_fan_speed = std::clamp(int(float(bridge_fan_speed) * factor + 0.5f), 0, 100);
requested_fan_speed_limits.max_speed = fan_speed_new;
}
#undef EXTRUDER_CONFIG
bridge_fan_control = bridge_fan_speed > fan_speed_new;
} else { // fan disabled
bridge_fan_control = false;
bridge_fan_speed = 0;
fan_speed_new = 0;
custom_fan_speed_limits.second = 0;
bridge_fan_control = false;
bridge_fan_speed = 0;
fan_speed_new = 0;
requested_fan_speed_limits.max_speed = 0;
}
requested_fan_speed_limits.min_speed = std::min(requested_fan_speed_limits.min_speed, requested_fan_speed_limits.max_speed);
if (requested_fan_speed >= 0) {
fan_speed_new = std::clamp(requested_fan_speed, requested_fan_speed_limits.min_speed, requested_fan_speed_limits.max_speed);
}
if (fan_speed_new != m_fan_speed) {
m_fan_speed = fan_speed_new;
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_config.gcode_comments, m_fan_speed);
}
custom_fan_speed_limits.first = std::min(custom_fan_speed_limits.first, custom_fan_speed_limits.second);
return custom_fan_speed_limits;
};
const char *pos = gcode.c_str();
int current_feedrate = 0;
std::pair<int,int> fan_speed_limits = change_extruder_set_fan();
change_extruder_set_fan();
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;
@ -887,17 +906,13 @@ std::string CoolingBuffer::apply_layer_cooldown(
auto res = std::from_chars(line_start + m_toolchange_prefix.size(), line_end, new_extruder);
if (res.ec != std::errc::invalid_argument && new_extruder != m_current_extruder) {
m_current_extruder = new_extruder;
fan_speed_limits = change_extruder_set_fan();
change_extruder_set_fan();
}
new_gcode.append(line_start, line_end - line_start);
} else if (line->type & CoolingLine::TYPE_SET_FAN_SPEED) {
int new_speed = std::clamp(line->fan_speed, fan_speed_limits.first, fan_speed_limits.second);
if (m_fan_speed != new_speed) {
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_config.gcode_comments, new_speed);
m_fan_speed = new_speed;
}
change_extruder_set_fan(line->fan_speed);
} else if (line->type & CoolingLine::TYPE_RESET_FAN_SPEED){
fan_speed_limits = change_extruder_set_fan();
change_extruder_set_fan();
} else if (line->type & CoolingLine::TYPE_BRIDGE_FAN_START) {
if (bridge_fan_control)
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_config.gcode_comments, bridge_fan_speed);

View File

@ -11,7 +11,7 @@
#include "libslic3r/Line.hpp"
#include "libslic3r/Polygon.hpp"
namespace Slic3r { namespace ExtrusionProcessor {
namespace Slic3r::ExtrusionProcessor {
ExtrusionPaths calculate_and_split_overhanging_extrusions(const ExtrusionPath &path,
const AABBTreeLines::LinesDistancer<Linef> &unscaled_prev_layer,
@ -146,57 +146,85 @@ ExtrusionEntityCollection calculate_and_split_overhanging_extrusions(const Extru
return result;
};
std::pair<float,float> calculate_overhang_speed(const ExtrusionAttributes &attributes,
const FullPrintConfig &config,
size_t extruder_id,
float external_perim_reference_speed,
float default_speed)
static std::map<float, float> calc_print_speed_sections(const ExtrusionAttributes &attributes,
const FullPrintConfig &config,
const float external_perimeter_reference_speed,
const float default_speed)
{
assert(attributes.overhang_attributes.has_value());
std::vector<std::pair<int, ConfigOptionFloatOrPercent>> overhangs_with_speeds = {
{100, ConfigOptionFloatOrPercent{default_speed, false}}};
struct OverhangWithSpeed
{
int percent;
ConfigOptionFloatOrPercent print_speed;
};
std::vector<OverhangWithSpeed> overhangs_with_speeds = {{100, ConfigOptionFloatOrPercent{default_speed, false}}};
if (config.enable_dynamic_overhang_speeds) {
overhangs_with_speeds = {{0, config.overhang_speed_0},
{25, config.overhang_speed_1},
{50, config.overhang_speed_2},
{75, config.overhang_speed_3},
overhangs_with_speeds = {{ 0, config.overhang_speed_0},
{ 25, config.overhang_speed_1},
{ 50, config.overhang_speed_2},
{ 75, config.overhang_speed_3},
{100, ConfigOptionFloatOrPercent{default_speed, false}}};
}
std::vector<std::pair<int, ConfigOptionInts>> overhang_with_fan_speeds = {{100, ConfigOptionInts{0}}};
if (config.enable_dynamic_fan_speeds.get_at(extruder_id)) {
overhang_with_fan_speeds = {{0, config.overhang_fan_speed_0},
{25, config.overhang_fan_speed_1},
{50, config.overhang_fan_speed_2},
{75, config.overhang_fan_speed_3},
{100, ConfigOptionInts{0}}};
}
float speed_base = external_perim_reference_speed > 0 ? external_perim_reference_speed : default_speed;
const float speed_base = external_perimeter_reference_speed > 0 ? external_perimeter_reference_speed : default_speed;
std::map<float, float> speed_sections;
for (size_t i = 0; i < overhangs_with_speeds.size(); i++) {
float distance = attributes.width * (1.0 - (overhangs_with_speeds[i].first / 100.0));
float speed = overhangs_with_speeds[i].second.percent ? (speed_base * overhangs_with_speeds[i].second.value / 100.0) :
overhangs_with_speeds[i].second.value;
if (speed < EPSILON)
for (OverhangWithSpeed &overhangs_with_speed : overhangs_with_speeds) {
const float distance = attributes.width * (1.f - (float(overhangs_with_speed.percent) / 100.f));
float speed = float(overhangs_with_speed.print_speed.get_abs_value(speed_base));
if (speed < EPSILON) {
speed = speed_base;
}
speed_sections[distance] = speed;
}
return speed_sections;
}
static std::map<float, float> calc_fan_speed_sections(const ExtrusionAttributes &attributes,
const FullPrintConfig &config,
const size_t extruder_id)
{
struct OverhangWithFanSpeed
{
int percent;
ConfigOptionInts fan_speed;
};
std::vector<OverhangWithFanSpeed> overhang_with_fan_speeds = {{100, ConfigOptionInts{0}}};
if (config.enable_dynamic_fan_speeds.get_at(extruder_id)) {
overhang_with_fan_speeds = {{ 0, config.overhang_fan_speed_0},
{ 25, config.overhang_fan_speed_1},
{ 50, config.overhang_fan_speed_2},
{ 75, config.overhang_fan_speed_3},
{100, ConfigOptionInts{0}}};
}
std::map<float, float> fan_speed_sections;
for (size_t i = 0; i < overhang_with_fan_speeds.size(); i++) {
float distance = attributes.width * (1.0 - (overhang_with_fan_speeds[i].first / 100.0));
float fan_speed = overhang_with_fan_speeds[i].second.get_at(extruder_id);
for (OverhangWithFanSpeed &overhang_with_fan_speed : overhang_with_fan_speeds) {
float distance = attributes.width * (1.f - (float(overhang_with_fan_speed.percent) / 100.f));
float fan_speed = float(overhang_with_fan_speed.fan_speed.get_at(extruder_id));
fan_speed_sections[distance] = fan_speed;
}
return fan_speed_sections;
}
OverhangSpeeds calculate_overhang_speed(const ExtrusionAttributes &attributes,
const FullPrintConfig &config,
const size_t extruder_id,
const float external_perimeter_reference_speed,
const float default_speed,
const std::optional<float> &current_fan_speed)
{
assert(attributes.overhang_attributes.has_value());
auto interpolate_speed = [](const std::map<float, float> &values, float distance) {
auto upper_dist = values.lower_bound(distance);
if (upper_dist == values.end()) {
return values.rbegin()->second;
}
if (upper_dist == values.begin()) {
} else if (upper_dist == values.begin()) {
return upper_dist->second;
}
@ -205,22 +233,29 @@ std::pair<float,float> calculate_overhang_speed(const ExtrusionAttributes &attri
return (1.0f - t) * lower_dist->second + t * upper_dist->second;
};
float extrusion_speed = std::min(interpolate_speed(speed_sections, attributes.overhang_attributes->start_distance_from_prev_layer),
interpolate_speed(speed_sections, attributes.overhang_attributes->end_distance_from_prev_layer));
float curled_base_speed = interpolate_speed(speed_sections,
attributes.width * attributes.overhang_attributes->proximity_to_curled_lines);
float final_speed = std::min(curled_base_speed, extrusion_speed);
float fan_speed = std::min(interpolate_speed(fan_speed_sections, attributes.overhang_attributes->start_distance_from_prev_layer),
interpolate_speed(fan_speed_sections, attributes.overhang_attributes->end_distance_from_prev_layer));
const std::map<float, float> speed_sections = calc_print_speed_sections(attributes, config, external_perimeter_reference_speed, default_speed);
const std::map<float, float> fan_speed_sections = calc_fan_speed_sections(attributes, config, extruder_id);
const float extrusion_speed = std::min(interpolate_speed(speed_sections, attributes.overhang_attributes->start_distance_from_prev_layer),
interpolate_speed(speed_sections, attributes.overhang_attributes->end_distance_from_prev_layer));
const float curled_base_speed = interpolate_speed(speed_sections, attributes.width * attributes.overhang_attributes->proximity_to_curled_lines);
const float fan_speed = std::min(interpolate_speed(fan_speed_sections, attributes.overhang_attributes->start_distance_from_prev_layer),
interpolate_speed(fan_speed_sections, attributes.overhang_attributes->end_distance_from_prev_layer));
OverhangSpeeds overhang_speeds = {std::min(curled_base_speed, extrusion_speed), fan_speed};
if (!config.enable_dynamic_overhang_speeds) {
final_speed = -1;
}
if (!config.enable_dynamic_fan_speeds.get_at(extruder_id)) {
fan_speed = -1;
overhang_speeds.print_speed = -1;
}
return {final_speed, fan_speed};
if (!config.enable_dynamic_fan_speeds.get_at(extruder_id)) {
overhang_speeds.fan_speed = -1;
} else if (current_fan_speed.has_value() && (fan_speed < *current_fan_speed) && (*current_fan_speed - fan_speed) <= MIN_FAN_SPEED_NEGATIVE_CHANGE_TO_EMIT) {
// Always allow the fan speed to be increased without any hysteresis, but the speed will be decreased only when it exceeds a limit for minimum change.
overhang_speeds.fan_speed = *current_fan_speed;
}
return overhang_speeds;
}
}} // namespace Slic3r::ExtrusionProcessor
} // namespace Slic3r::ExtrusionProcessor

View File

@ -42,7 +42,11 @@ class CurledLine;
class Linef;
} // namespace Slic3r
namespace Slic3r { namespace ExtrusionProcessor {
namespace Slic3r::ExtrusionProcessor {
// Minimum decrease of the fan speed in percents that will be emitted into g-code.
// Decreases below this limit will be omitted to not overflow the g-code with fan speed changes.
const constexpr float MIN_FAN_SPEED_NEGATIVE_CHANGE_TO_EMIT = 3.f;
struct ExtendedPoint
{
@ -51,6 +55,12 @@ struct ExtendedPoint
float curvature;
};
struct OverhangSpeeds
{
float print_speed;
float fan_speed;
};
template<bool SCALED_INPUT, bool ADD_INTERSECTIONS, bool PREV_LAYER_BOUNDARY_OFFSET, bool SIGNED_DISTANCE, typename POINTS, typename L>
std::vector<ExtendedPoint> estimate_points_properties(const POINTS &input_points,
const AABBTreeLines::LinesDistancer<L> &unscaled_prev_layer,
@ -266,12 +276,13 @@ ExtrusionEntityCollection calculate_and_split_overhanging_extrusions(
const AABBTreeLines::LinesDistancer<Linef> &unscaled_prev_layer,
const AABBTreeLines::LinesDistancer<CurledLine> &prev_layer_curled_lines);
std::pair<float, float> calculate_overhang_speed(const ExtrusionAttributes &attributes,
const FullPrintConfig &config,
size_t extruder_id,
float external_perim_reference_speed,
float default_speed);
OverhangSpeeds calculate_overhang_speed(const ExtrusionAttributes &attributes,
const FullPrintConfig &config,
size_t extruder_id,
float external_perimeter_reference_speed,
float default_speed,
const std::optional<float> &current_fan_speed);
}} // namespace Slic3r::ExtrusionProcessor
} // namespace Slic3r::ExtrusionProcessor
#endif // slic3r_ExtrusionProcessor_hpp_

View File

@ -2389,7 +2389,7 @@ void TabFilament::toggle_options()
bool dynamic_fan_speeds = m_config->opt_bool("enable_dynamic_fan_speeds", 0);
for (int i = 0; i < 4; i++) {
toggle_option("overhang_fan_speed_"+std::to_string(i),dynamic_fan_speeds);
toggle_option("overhang_fan_speed_"+std::to_string(i),dynamic_fan_speeds);
}
}