mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-31 06:52:03 +08:00
Merge branch 'lh_dynamic_fan_speed_fix'
This commit is contained in:
commit
a2cabdd74b
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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> ¤t_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
|
||||
|
@ -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> ¤t_fan_speed);
|
||||
|
||||
}} // namespace Slic3r::ExtrusionProcessor
|
||||
} // namespace Slic3r::ExtrusionProcessor
|
||||
|
||||
#endif // slic3r_ExtrusionProcessor_hpp_
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user