refactoring overhang speed

This commit is contained in:
Pavel Mikus 2022-12-11 23:04:40 +01:00 committed by Pavel Mikuš
parent 3714943b49
commit f730fd21d4
12 changed files with 126 additions and 70 deletions

View File

@ -851,7 +851,6 @@ namespace DoExport {
if (region.config().get_abs_value("perimeter_speed") == 0 || if (region.config().get_abs_value("perimeter_speed") == 0 ||
region.config().get_abs_value("small_perimeter_speed") == 0 || region.config().get_abs_value("small_perimeter_speed") == 0 ||
region.config().get_abs_value("external_perimeter_speed") == 0 || region.config().get_abs_value("external_perimeter_speed") == 0 ||
region.config().get_abs_value("overhang_speed") == 0 ||
region.config().get_abs_value("bridge_speed") == 0) region.config().get_abs_value("bridge_speed") == 0)
mm3_per_mm.push_back(layerm->perimeters().min_mm3_per_mm()); mm3_per_mm.push_back(layerm->perimeters().min_mm3_per_mm());
if (region.config().get_abs_value("infill_speed") == 0 || if (region.config().get_abs_value("infill_speed") == 0 ||
@ -2877,9 +2876,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
speed = m_config.get_abs_value("perimeter_speed"); speed = m_config.get_abs_value("perimeter_speed");
} else if (path.role() == erExternalPerimeter) { } else if (path.role() == erExternalPerimeter) {
speed = m_config.get_abs_value("external_perimeter_speed"); speed = m_config.get_abs_value("external_perimeter_speed");
}else if (path.role() == erOverhangPerimeter){ } else if (path.role() == erOverhangPerimeter || path.role() == erBridgeInfill) {
speed = m_config.get_abs_value("overhang_speed");
} else if (path.role() == erBridgeInfill) {
speed = m_config.get_abs_value("bridge_speed"); speed = m_config.get_abs_value("bridge_speed");
} else if (path.role() == erInternalInfill) { } else if (path.role() == erInternalInfill) {
speed = m_config.get_abs_value("infill_speed"); speed = m_config.get_abs_value("infill_speed");
@ -2918,9 +2915,11 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
bool variable_speed = false; bool variable_speed = false;
std::vector<ProcessedPoint> new_points{}; std::vector<ProcessedPoint> new_points{};
if (this->m_config.overhangs && !this->on_first_layer() && is_perimeter(path.role())) { if (this->m_config.enable_dynamic_overhang_speeds && !this->on_first_layer() && is_perimeter(path.role())) {
new_points = m_extrusion_quality_estimator.estimate_extrusion_quality(path); new_points = m_extrusion_quality_estimator.estimate_extrusion_quality(path, m_config.overhang_overlaps,
variable_speed = std::any_of(new_points.begin(), new_points.end(), [](const ProcessedPoint &p) { return p.speed_factor != 1.0; }); m_config.dynamic_overhang_speeds,
m_config.get_abs_value("external_perimeter_speed"), speed);
variable_speed = std::any_of(new_points.begin(), new_points.end(), [speed](const ProcessedPoint &p) { return p.speed != speed; });
} }
double F = speed * 60; // convert mm/sec to mm/min double F = speed * 60; // convert mm/sec to mm/min
@ -2987,7 +2986,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
if (!variable_speed) { if (!variable_speed) {
// F is mm per minute. // F is mm per minute.
gcode += m_writer.set_speed(F, "", comment); gcode += m_writer.set_speed(F, "", comment);
double path_length = 0.; double path_length = 0.;
std::string comment; std::string comment;
if (m_config.gcode_comments) { if (m_config.gcode_comments) {
comment = description; comment = description;
@ -2996,30 +2995,29 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
Vec2d prev = this->point_to_gcode_quantized(path.polyline.points.front()); Vec2d prev = this->point_to_gcode_quantized(path.polyline.points.front());
auto it = path.polyline.points.begin(); auto it = path.polyline.points.begin();
auto end = path.polyline.points.end(); auto end = path.polyline.points.end();
for (++it; it != end; ++it) { for (++ it; it != end; ++ it) {
Vec2d p = this->point_to_gcode_quantized(*it); Vec2d p = this->point_to_gcode_quantized(*it);
const double line_length = (p - prev).norm(); const double line_length = (p - prev).norm();
path_length += line_length; path_length += line_length;
gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment); gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment);
prev = p; prev = p;
} }
} else { } else {
double overhang_speed = m_config.get_abs_value("overhang_speed");
std::string comment; std::string comment;
if (m_config.gcode_comments) { if (m_config.gcode_comments) {
comment = description; comment = description;
comment += description_bridge; comment += description_bridge;
} }
double last_set_speed = std::max(overhang_speed, new_points[0].speed_factor * speed) * 60.0; double last_set_speed = new_points[0].speed * 60.0;
gcode += m_writer.set_speed(last_set_speed, "", comment); gcode += m_writer.set_speed(last_set_speed, "", comment);
Vec2d prev = this->point_to_gcode_quantized(new_points[0].p); Vec2d prev = this->point_to_gcode_quantized(new_points[0].p);
for (size_t i = 1; i < new_points.size(); i++) { for (size_t i = 1; i < new_points.size(); i++) {
const ProcessedPoint& procesed_point = new_points[i]; const ProcessedPoint& processed_point = new_points[i];
Vec2d p = this->point_to_gcode_quantized(procesed_point.p); Vec2d p = this->point_to_gcode_quantized(processed_point.p);
const double line_length = (p - prev).norm(); const double line_length = (p - prev).norm();
gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment); gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment);
prev = p; prev = p;
double new_speed = std::max(overhang_speed, procesed_point.speed_factor * speed) * 60.0; double new_speed = processed_point.speed * 60.0;
if (last_set_speed != new_speed) { if (last_set_speed != new_speed) {
gcode += m_writer.set_speed(new_speed, "", comment); gcode += m_writer.set_speed(new_speed, "", comment);
last_set_speed = new_speed; last_set_speed = new_speed;

View File

@ -12,6 +12,7 @@
#include "../Polygon.hpp" #include "../Polygon.hpp"
#include "../ClipperUtils.hpp" #include "../ClipperUtils.hpp"
#include "../Flow.hpp" #include "../Flow.hpp"
#include "../Config.hpp"
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
@ -19,6 +20,7 @@
#include <limits> #include <limits>
#include <numeric> #include <numeric>
#include <unordered_map> #include <unordered_map>
#include <utility>
#include <vector> #include <vector>
namespace Slic3r { namespace Slic3r {
@ -67,8 +69,8 @@ public:
class CurvatureEstimator class CurvatureEstimator
{ {
static const size_t sliders_count = 3; static const size_t sliders_count = 2;
SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{2.0}, {4.0}, {8.0}}; SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{1.5}, {3.0}};
public: public:
void add_point(float distance, float angle) void add_point(float distance, float angle)
@ -189,7 +191,7 @@ std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P>
struct ProcessedPoint struct ProcessedPoint
{ {
Point p; Point p;
float speed_factor = 1.0f; float speed = 1.0f;
}; };
class ExtrusionQualityEstimator class ExtrusionQualityEstimator
@ -209,33 +211,53 @@ public:
next_layer_boundaries[object] = AABBTreeLines::LinesDistancer<Linef>{to_unscaled_linesf(layer->lslices)}; next_layer_boundaries[object] = AABBTreeLines::LinesDistancer<Linef>{to_unscaled_linesf(layer->lslices)};
} }
std::vector<ProcessedPoint> estimate_extrusion_quality(const ExtrusionPath &path) std::vector<ProcessedPoint> estimate_extrusion_quality(const ExtrusionPath &path,
const ConfigOptionPercents &overlaps,
const ConfigOptionFloatsOrPercents &speeds,
float ext_perimeter_speed,
float original_speed)
{ {
size_t speed_sections_count = std::min(overlaps.values.size(), speeds.values.size());
std::vector<std::pair<float, float>> speed_sections;
for (size_t i = 0; i < speed_sections_count; i++) {
float distance = path.width * (1.0 - (overlaps.get_at(i) / 100.0));
float speed = speeds.get_at(i).percent ? (ext_perimeter_speed * speeds.get_at(i).value / 100.0) : speeds.get_at(i).value;
speed_sections.push_back({distance, speed});
}
std::sort(speed_sections.begin(), speed_sections.end(),
[](const std::pair<float, float> &a, const std::pair<float, float> &b) { return a.first < b.first; });
std::vector<ExtendedPoint> extended_points = std::vector<ExtendedPoint> extended_points =
estimate_points_properties<true, true, true, false>(path.polyline.points, prev_layer_boundaries[current_object], path.width); estimate_points_properties<true, true, true, false>(path.polyline.points, prev_layer_boundaries[current_object], path.width);
float min_malformation_dist = 0.55 * path.width;
float peak_malformation_dist = path.width;
std::vector<ProcessedPoint> processed_points; std::vector<ProcessedPoint> processed_points;
processed_points.reserve(extended_points.size()); processed_points.reserve(extended_points.size());
for (size_t i = 0; i < extended_points.size(); i++) { for (size_t i = 0; i < extended_points.size(); i++) {
const ExtendedPoint &curr = extended_points[i]; const ExtendedPoint &curr = extended_points[i];
const ExtendedPoint &next = extended_points[i + 1 < extended_points.size() ? i + 1 : i]; const ExtendedPoint &next = extended_points[i + 1 < extended_points.size() ? i + 1 : i];
float extrusion_speed_factor = 1.0f; auto calculate_speed = [&speed_sections, &original_speed](float distance) {
if (std::max(curr.distance, next.distance) < min_malformation_dist) { float final_speed;
extrusion_speed_factor = 1.0f; if (distance <= speed_sections.front().first) {
} else { final_speed = original_speed;
float curvature_penalty = std::min(1.0f, next.curvature); } else if (distance >= speed_sections.back().first) {
float distance_penalty = (std::max(curr.distance, next.distance) - min_malformation_dist) / final_speed = speed_sections.back().second;
(peak_malformation_dist - min_malformation_dist); } else {
distance_penalty = std::min(1.0f, distance_penalty); size_t section_idx = 0;
while (distance > speed_sections[section_idx + 1].first) {
section_idx++;
}
float t = (distance - speed_sections[section_idx].first) /
(speed_sections[section_idx + 1].first - speed_sections[section_idx].first);
t = std::clamp(t, 0.0f, 1.0f);
final_speed = (1.0f - t) * speed_sections[section_idx].second + t * speed_sections[section_idx + 1].second;
}
return final_speed;
};
extrusion_speed_factor = std::clamp(1.0f - distance_penalty - curvature_penalty, 0.0f, 1.0f); float extrusion_speed = (calculate_speed(curr.distance) + calculate_speed(next.distance)) / 2.0f;
}
processed_points.push_back({scaled(curr.position), extrusion_speed_factor}); processed_points.push_back({scaled(curr.position), extrusion_speed});
} }
return processed_points; return processed_points;
} }

View File

@ -474,7 +474,6 @@ void Layer::make_perimeters()
&& config.perimeters == other_config.perimeters && config.perimeters == other_config.perimeters
&& config.perimeter_speed == other_config.perimeter_speed && config.perimeter_speed == other_config.perimeter_speed
&& config.external_perimeter_speed == other_config.external_perimeter_speed && config.external_perimeter_speed == other_config.external_perimeter_speed
&& config.overhang_speed == other_config.overhang_speed
&& (config.gap_fill_enabled ? config.gap_fill_speed.value : 0.) == && (config.gap_fill_enabled ? config.gap_fill_speed.value : 0.) ==
(other_config.gap_fill_enabled ? other_config.gap_fill_speed.value : 0.) (other_config.gap_fill_enabled ? other_config.gap_fill_speed.value : 0.)
&& config.overhangs == other_config.overhangs && config.overhangs == other_config.overhangs

View File

@ -428,7 +428,8 @@ static std::vector<std::string> s_Preset_print_options {
"max_print_speed", "max_volumetric_speed", "avoid_crossing_perimeters_max_detour", "max_print_speed", "max_volumetric_speed", "avoid_crossing_perimeters_max_detour",
"fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_dist", "fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_dist",
"max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative", "max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative",
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "overhang_speed", "infill_speed", "solid_infill_speed", "perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "infill_speed", "solid_infill_speed",
"enable_dynamic_overhang_speeds", "dynamic_overhang_speeds", "overhang_overlaps",
"top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed", "top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed",
"bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "travel_speed_z", "first_layer_speed", "first_layer_speed_over_raft", "perimeter_acceleration", "infill_acceleration", "bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "travel_speed_z", "first_layer_speed", "first_layer_speed_over_raft", "perimeter_acceleration", "infill_acceleration",
"bridge_acceleration", "first_layer_acceleration", "first_layer_acceleration_over_raft", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield", "bridge_acceleration", "first_layer_acceleration", "first_layer_acceleration_over_raft", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield",

View File

@ -528,6 +528,36 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(60)); def->set_default_value(new ConfigOptionFloat(60));
def = this->add("enable_dynamic_overhang_speeds", coBool);
def->label = L("Enable dynamic overhang speeds (Experimental)");
def->category = L("Speed");
def->tooltip = L("This setting enables dynamic speed control on overhangs.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(true));
def = this->add("overhang_overlaps", coPercents);
def->label = L("Overhang overlap percentage");
def->category = L("Speed");
def->tooltip = L("Controls percentage of overhang extrusion overlap with the previous layer."
"Each overlap size then corresponds with the overhang speed set below.");
def->sidetext = L("%");
def->min = 0;
def->max = 100;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionPercents({60, 40, 20, 0}));
def = this->add("dynamic_overhang_speeds", coFloatsOrPercents);
def->label = L("Dynamic speed on overhangs");
def->category = L("Speed");
def->tooltip = L("This setting controls the speed of the overhangs for overlap values set above."
"The final speed is calculated as an interpolation of the set speed values."
"If set as percentage, the speeds are calculated over the external perimeter speed."
);
def->sidetext = L("mm/s or %");
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatsOrPercents({{25, false}, {20, false}, {15, false}, {15, false}}));
def = this->add("brim_width", coFloat); def = this->add("brim_width", coFloat);
def->label = L("Brim width"); def->label = L("Brim width");
def->category = L("Skirt and brim"); def->category = L("Skirt and brim");
@ -2358,18 +2388,6 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(15, false)); def->set_default_value(new ConfigOptionFloatOrPercent(15, false));
def = this->add("overhang_speed", coFloatOrPercent);
def->label = L("Overhangs");
def->category = L("Speed");
def->tooltip = L("This setting controls the speed of overhangs."
"If expressed as percentage (for example: 80%) it will be calculated "
"on the external perimeters speed setting. Set to zero for auto.");
def->sidetext = L("mm/s or %");
def->ratio_over = "external_perimeter_speed";
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(15, false));
def = this->add("solid_infill_below_area", coFloat); def = this->add("solid_infill_below_area", coFloat);
def->label = L("Solid infill threshold area"); def->label = L("Solid infill threshold area");
def->category = L("Infill"); def->category = L("Infill");

View File

@ -564,7 +564,9 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionEnum<InfillPattern>, bottom_fill_pattern)) ((ConfigOptionEnum<InfillPattern>, bottom_fill_pattern))
((ConfigOptionFloatOrPercent, external_perimeter_extrusion_width)) ((ConfigOptionFloatOrPercent, external_perimeter_extrusion_width))
((ConfigOptionFloatOrPercent, external_perimeter_speed)) ((ConfigOptionFloatOrPercent, external_perimeter_speed))
((ConfigOptionFloatOrPercent, overhang_speed)) ((ConfigOptionBool, enable_dynamic_overhang_speeds))
((ConfigOptionPercents, overhang_overlaps))
((ConfigOptionFloatsOrPercents, dynamic_overhang_speeds))
((ConfigOptionBool, external_perimeters_first)) ((ConfigOptionBool, external_perimeters_first))
((ConfigOptionBool, extra_perimeters)) ((ConfigOptionBool, extra_perimeters))
((ConfigOptionBool, extra_perimeters_on_overhangs)) ((ConfigOptionBool, extra_perimeters_on_overhangs))

View File

@ -748,7 +748,9 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "support_material_speed" || opt_key == "support_material_speed"
|| opt_key == "support_material_interface_speed" || opt_key == "support_material_interface_speed"
|| opt_key == "bridge_speed" || opt_key == "bridge_speed"
|| opt_key == "overhang_speed" || opt_key == "enable_dynamic_overhang_speeds"
|| opt_key == "overhang_overlaps"
|| opt_key == "dynamic_overhang_speeds"
|| opt_key == "external_perimeter_speed" || opt_key == "external_perimeter_speed"
|| opt_key == "infill_speed" || opt_key == "infill_speed"
|| opt_key == "perimeter_speed" || opt_key == "perimeter_speed"

View File

@ -220,9 +220,12 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
bool have_perimeters = config->opt_int("perimeters") > 0; bool have_perimeters = config->opt_int("perimeters") > 0;
for (auto el : { "extra_perimeters","extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness", "thin_walls", "overhangs", for (auto el : { "extra_perimeters","extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness", "thin_walls", "overhangs",
"seam_position","staggered_inner_seams", "external_perimeters_first", "external_perimeter_extrusion_width", "seam_position","staggered_inner_seams", "external_perimeters_first", "external_perimeter_extrusion_width",
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "overhang_speed" }) "perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "enable_dynamic_overhang_speeds", "overhang_overlaps", "dynamic_overhang_speeds" })
toggle_field(el, have_perimeters); toggle_field(el, have_perimeters);
toggle_field("overhang_overlaps", config->opt_bool("enable_dynamic_overhang_speeds"));
toggle_field("dynamic_overhang_speeds", config->opt_bool("enable_dynamic_overhang_speeds"));
bool have_infill = config->option<ConfigOptionPercent>("fill_density")->value > 0; bool have_infill = config->option<ConfigOptionPercent>("fill_density")->value > 0;
// infill_extruder uses the same logic as in Print::extruders() // infill_extruder uses the same logic as in Print::extruders()
for (auto el : { "fill_pattern", "infill_every_layers", "infill_only_where_needed", for (auto el : { "fill_pattern", "infill_every_layers", "infill_only_where_needed",

View File

@ -100,7 +100,6 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle
double bridge_flow_ratio = print_config.opt_float("bridge_flow_ratio"); double bridge_flow_ratio = print_config.opt_float("bridge_flow_ratio");
double perimeter_speed = print_config.opt_float("perimeter_speed"); double perimeter_speed = print_config.opt_float("perimeter_speed");
double external_perimeter_speed = print_config.get_abs_value("external_perimeter_speed", perimeter_speed); double external_perimeter_speed = print_config.get_abs_value("external_perimeter_speed", perimeter_speed);
// double overhang_seed = print_config.get_abs_value("overhang_speed", external_perimeter_speed);
// double gap_fill_speed = print_config.opt_bool("gap_fill_enabled") ? print_config.opt_float("gap_fill_speed") : 0.; // double gap_fill_speed = print_config.opt_bool("gap_fill_enabled") ? print_config.opt_float("gap_fill_speed") : 0.;
double infill_speed = print_config.opt_float("infill_speed"); double infill_speed = print_config.opt_float("infill_speed");
double small_perimeter_speed = print_config.get_abs_value("small_perimeter_speed", perimeter_speed); double small_perimeter_speed = print_config.get_abs_value("small_perimeter_speed", perimeter_speed);

View File

@ -1,4 +1,5 @@
// #include "libslic3r/GCodeSender.hpp" // #include "libslic3r/GCodeSender.hpp"
#include "slic3r/GUI/BedShapeDialog.hpp"
#include "slic3r/Utils/Serial.hpp" #include "slic3r/Utils/Serial.hpp"
#include "Tab.hpp" #include "Tab.hpp"
#include "PresetHints.hpp" #include "PresetHints.hpp"
@ -1541,7 +1542,6 @@ void TabPrint::build()
optgroup->append_single_option_line("perimeter_speed"); optgroup->append_single_option_line("perimeter_speed");
optgroup->append_single_option_line("small_perimeter_speed"); optgroup->append_single_option_line("small_perimeter_speed");
optgroup->append_single_option_line("external_perimeter_speed"); optgroup->append_single_option_line("external_perimeter_speed");
optgroup->append_single_option_line("overhang_speed");
optgroup->append_single_option_line("infill_speed"); optgroup->append_single_option_line("infill_speed");
optgroup->append_single_option_line("solid_infill_speed"); optgroup->append_single_option_line("solid_infill_speed");
optgroup->append_single_option_line("top_solid_infill_speed"); optgroup->append_single_option_line("top_solid_infill_speed");
@ -1551,6 +1551,20 @@ void TabPrint::build()
optgroup->append_single_option_line("gap_fill_speed"); optgroup->append_single_option_line("gap_fill_speed");
optgroup->append_single_option_line("ironing_speed"); optgroup->append_single_option_line("ironing_speed");
optgroup = page->new_optgroup(L("Dynamic overhang speed"));
auto append_option_line = [](ConfigOptionsGroupShp optgroup, std::string opt_key) {
auto option = optgroup->get_option(opt_key, 0);
auto line = Line{option.opt.full_label, ""};
line.append_option(option);
line.append_option(optgroup->get_option(opt_key, 1));
line.append_option(optgroup->get_option(opt_key, 2));
line.append_option(optgroup->get_option(opt_key, 3));
optgroup->append_line(line);
};
optgroup->append_single_option_line("enable_dynamic_overhang_speeds");
append_option_line(optgroup,"overhang_overlaps");
append_option_line(optgroup,"dynamic_overhang_speeds");
optgroup = page->new_optgroup(L("Speed for non-print moves")); optgroup = page->new_optgroup(L("Speed for non-print moves"));
optgroup->append_single_option_line("travel_speed"); optgroup->append_single_option_line("travel_speed");
optgroup->append_single_option_line("travel_speed_z"); optgroup->append_single_option_line("travel_speed_z");

View File

@ -176,7 +176,7 @@ SCENARIO("Cooling integration tests", "[Cooling]") {
{ "fan_below_layer_time", { 0 } }, { "fan_below_layer_time", { 0 } },
{ "slowdown_below_layer_time", { 0 } }, { "slowdown_below_layer_time", { 0 } },
{ "bridge_speed", 99 }, { "bridge_speed", 99 },
{ "overhangs", false }, { "enable_dynamic_overhang_speeds", false },
// internal bridges use solid_infil speed // internal bridges use solid_infil speed
{ "bottom_solid_layers", 1 }, { "bottom_solid_layers", 1 },
// internal bridges use solid_infil speed // internal bridges use solid_infil speed

View File

@ -309,7 +309,7 @@ SCENARIO("Perimeters", "[Perimeters]")
{ "perimeters", 1 }, { "perimeters", 1 },
{ "perimeter_speed", 77 }, { "perimeter_speed", 77 },
{ "external_perimeter_speed", 66 }, { "external_perimeter_speed", 66 },
{ "overhang_speed", 60 }, { "enable_dynamic_overhang_speeds", false },
{ "bridge_speed", 99 }, { "bridge_speed", 99 },
{ "cooling", "1" }, { "cooling", "1" },
{ "fan_below_layer_time", "0" }, { "fan_below_layer_time", "0" },
@ -330,11 +330,10 @@ SCENARIO("Perimeters", "[Perimeters]")
const double perimeter_speed = config.opt_float("perimeter_speed") * 60.; const double perimeter_speed = config.opt_float("perimeter_speed") * 60.;
const double external_perimeter_speed = config.get_abs_value("external_perimeter_speed") * 60.; const double external_perimeter_speed = config.get_abs_value("external_perimeter_speed") * 60.;
const double bridge_speed = config.opt_float("bridge_speed") * 60.; const double bridge_speed = config.opt_float("bridge_speed") * 60.;
const double overhang_speed = config.opt<ConfigOptionFloatOrPercent>("overhang_speed")->value * 60.;
const double nozzle_dmr = config.opt<ConfigOptionFloats>("nozzle_diameter")->get_at(0); const double nozzle_dmr = config.opt<ConfigOptionFloats>("nozzle_diameter")->get_at(0);
const double filament_dmr = config.opt<ConfigOptionFloats>("filament_diameter")->get_at(0); const double filament_dmr = config.opt<ConfigOptionFloats>("filament_diameter")->get_at(0);
const double bridge_mm_per_mm = sqr(nozzle_dmr / filament_dmr) * config.opt_float("bridge_flow_ratio"); const double bridge_mm_per_mm = sqr(nozzle_dmr / filament_dmr) * config.opt_float("bridge_flow_ratio");
parser.parse_buffer(gcode, [&layer_speeds, &fan_speed, perimeter_speed, external_perimeter_speed, bridge_speed, overhang_speed, nozzle_dmr, filament_dmr, bridge_mm_per_mm] parser.parse_buffer(gcode, [&layer_speeds, &fan_speed, perimeter_speed, external_perimeter_speed, bridge_speed, nozzle_dmr, filament_dmr, bridge_mm_per_mm]
(Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
{ {
if (line.cmd_is("M107")) if (line.cmd_is("M107"))
@ -343,14 +342,13 @@ SCENARIO("Perimeters", "[Perimeters]")
line.has_value('S', fan_speed); line.has_value('S', fan_speed);
else if (line.extruding(self) && line.dist_XY(self) > 0) { else if (line.extruding(self) && line.dist_XY(self) > 0) {
double feedrate = line.new_F(self); double feedrate = line.new_F(self);
REQUIRE((is_approx(feedrate, perimeter_speed) || is_approx(feedrate, bridge_speed) || REQUIRE((is_approx(feedrate, perimeter_speed) || is_approx(feedrate, external_perimeter_speed) || is_approx(feedrate, bridge_speed)));
(feedrate >= overhang_speed && feedrate <= external_perimeter_speed)));
layer_speeds[self.z()].insert(feedrate); layer_speeds[self.z()].insert(feedrate);
bool bridging = is_approx(feedrate, bridge_speed); bool bridging = is_approx(feedrate, bridge_speed);
double mm_per_mm = line.dist_E(self) / line.dist_XY(self); double mm_per_mm = line.dist_E(self) / line.dist_XY(self);
// Fan enabled at full speed when bridging, disabled when not bridging. // Fan enabled at full speed when bridging, disabled when not bridging.
REQUIRE((! bridging || fan_speed == 255)); REQUIRE((! bridging || fan_speed == 255));
// REQUIRE((bridging || fan_speed == 0)); not true. with dynamic overhangs slowdown, the fan is used as well (and the speed is anywhere between external perimeter speed and overhang speed) REQUIRE((bridging || fan_speed == 0));
// When bridging, bridge flow is applied. // When bridging, bridge flow is applied.
REQUIRE((! bridging || std::abs(mm_per_mm - bridge_mm_per_mm) <= 0.01)); REQUIRE((! bridging || std::abs(mm_per_mm - bridge_mm_per_mm) <= 0.01));
} }
@ -377,7 +375,6 @@ SCENARIO("Perimeters", "[Perimeters]")
{ "external_perimeter_speed", 99 }, { "external_perimeter_speed", 99 },
{ "small_perimeter_speed", 99 }, { "small_perimeter_speed", 99 },
{ "thin_walls", 0 }, { "thin_walls", 0 },
{ "overhangs", false },
}); });
std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::ipadstand }, config); std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::ipadstand }, config);
@ -533,7 +530,7 @@ SCENARIO("Perimeters3", "[Perimeters]")
{ "skirts", 0 }, { "skirts", 0 },
{ "perimeters", 3 }, { "perimeters", 3 },
{ "layer_height", 0.4 }, { "layer_height", 0.4 },
{ "overhang_speed", 5 }, { "enable_dynamic_overhang_speeds", false },
// to prevent bridging over sparse infill // to prevent bridging over sparse infill
{ "fill_density", 0 }, { "fill_density", 0 },
{ "overhangs", true }, { "overhangs", true },
@ -547,25 +544,26 @@ SCENARIO("Perimeters3", "[Perimeters]")
std::string gcode = Slic3r::Test::slice({ mesh(Slic3r::Test::TestMesh::V, Vec3d::Zero(), scale) }, config); std::string gcode = Slic3r::Test::slice({ mesh(Slic3r::Test::TestMesh::V, Vec3d::Zero(), scale) }, config);
GCodeReader parser; GCodeReader parser;
std::set<coord_t> z_with_bridges; std::set<coord_t> z_with_bridges;
const double overhang_speed = config.opt<ConfigOptionFloatOrPercent>("overhang_speed")->value * 60.; const double bridge_speed = config.opt_float("bridge_speed") * 60.;
parser.parse_buffer(gcode, [&z_with_bridges, overhang_speed](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) parser.parse_buffer(gcode, [&z_with_bridges, bridge_speed](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
{ {
if (line.extruding(self) && line.dist_XY(self) > 0 && if (line.extruding(self) && line.dist_XY(self) > 0 && is_approx<double>(line.new_F(self), bridge_speed))
(is_approx<double>(line.new_F(self), overhang_speed)))
z_with_bridges.insert(scaled<coord_t>(self.z())); z_with_bridges.insert(scaled<coord_t>(self.z()));
}); });
return z_with_bridges.size(); return z_with_bridges.size();
}; };
GIVEN("V shape, scaled 0.5x in X") { GIVEN("V shape, unscaled") {
int n = test(Vec3d(0.5, 1., 1.)); int n = test(Vec3d(1., 1., 1.));
THEN("no overhangs printed with overhangs speed") { // except for the two internal solid layers above void
REQUIRE(n == 0); THEN("no overhangs printed with bridge speed") {
REQUIRE(n == 1);
} }
} }
GIVEN("V shape, scaled 3x in X") { GIVEN("V shape, scaled 3x in X") {
int n = test(Vec3d(3., 1., 1.)); int n = test(Vec3d(3., 1., 1.));
THEN("overhangs printed with overhangs speed") { // except for the two internal solid layers above void
THEN("overhangs printed with bridge speed") {
REQUIRE(n > 2); REQUIRE(n > 2);
} }
} }