diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index bf4b82216..ee72c16a9 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -851,7 +851,6 @@ namespace DoExport { if (region.config().get_abs_value("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("overhang_speed") == 0 || region.config().get_abs_value("bridge_speed") == 0) mm3_per_mm.push_back(layerm->perimeters().min_mm3_per_mm()); 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"); } else if (path.role() == erExternalPerimeter) { speed = m_config.get_abs_value("external_perimeter_speed"); - }else if (path.role() == erOverhangPerimeter){ - speed = m_config.get_abs_value("overhang_speed"); - } else if (path.role() == erBridgeInfill) { + } else if (path.role() == erOverhangPerimeter || path.role() == erBridgeInfill) { speed = m_config.get_abs_value("bridge_speed"); } else if (path.role() == erInternalInfill) { 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; std::vector new_points{}; - if (this->m_config.overhangs && !this->on_first_layer() && is_perimeter(path.role())) { - new_points = m_extrusion_quality_estimator.estimate_extrusion_quality(path); - variable_speed = std::any_of(new_points.begin(), new_points.end(), [](const ProcessedPoint &p) { return p.speed_factor != 1.0; }); + 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, m_config.overhang_overlaps, + 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 @@ -2987,7 +2986,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de if (!variable_speed) { // F is mm per minute. gcode += m_writer.set_speed(F, "", comment); - double path_length = 0.; + double path_length = 0.; std::string comment; if (m_config.gcode_comments) { 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()); auto it = path.polyline.points.begin(); auto end = path.polyline.points.end(); - for (++it; it != end; ++it) { - Vec2d p = this->point_to_gcode_quantized(*it); + for (++ it; it != end; ++ it) { + Vec2d p = this->point_to_gcode_quantized(*it); const double line_length = (p - prev).norm(); path_length += line_length; gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment); prev = p; } } else { - double overhang_speed = m_config.get_abs_value("overhang_speed"); std::string comment; if (m_config.gcode_comments) { comment = description; 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); Vec2d prev = this->point_to_gcode_quantized(new_points[0].p); for (size_t i = 1; i < new_points.size(); i++) { - const ProcessedPoint& procesed_point = new_points[i]; - Vec2d p = this->point_to_gcode_quantized(procesed_point.p); + const ProcessedPoint& processed_point = new_points[i]; + Vec2d p = this->point_to_gcode_quantized(processed_point.p); const double line_length = (p - prev).norm(); gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment); 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) { gcode += m_writer.set_speed(new_speed, "", comment); last_set_speed = new_speed; diff --git a/src/libslic3r/GCode/ExtrusionProcessor.hpp b/src/libslic3r/GCode/ExtrusionProcessor.hpp index 2b8de6c77..e44083c68 100644 --- a/src/libslic3r/GCode/ExtrusionProcessor.hpp +++ b/src/libslic3r/GCode/ExtrusionProcessor.hpp @@ -12,6 +12,7 @@ #include "../Polygon.hpp" #include "../ClipperUtils.hpp" #include "../Flow.hpp" +#include "../Config.hpp" #include #include @@ -19,6 +20,7 @@ #include #include #include +#include #include namespace Slic3r { @@ -67,8 +69,8 @@ public: class CurvatureEstimator { - static const size_t sliders_count = 3; - SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{2.0}, {4.0}, {8.0}}; + static const size_t sliders_count = 2; + SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{1.5}, {3.0}}; public: void add_point(float distance, float angle) @@ -189,7 +191,7 @@ std::vector estimate_points_properties(const std::vector

struct ProcessedPoint { Point p; - float speed_factor = 1.0f; + float speed = 1.0f; }; class ExtrusionQualityEstimator @@ -209,33 +211,53 @@ public: next_layer_boundaries[object] = AABBTreeLines::LinesDistancer{to_unscaled_linesf(layer->lslices)}; } - std::vector estimate_extrusion_quality(const ExtrusionPath &path) + std::vector 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> 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 &a, const std::pair &b) { return a.first < b.first; }); + std::vector extended_points = estimate_points_properties(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 processed_points; processed_points.reserve(extended_points.size()); for (size_t i = 0; i < extended_points.size(); i++) { const ExtendedPoint &curr = extended_points[i]; const ExtendedPoint &next = extended_points[i + 1 < extended_points.size() ? i + 1 : i]; - float extrusion_speed_factor = 1.0f; - if (std::max(curr.distance, next.distance) < min_malformation_dist) { - extrusion_speed_factor = 1.0f; - } else { - float curvature_penalty = std::min(1.0f, next.curvature); - float distance_penalty = (std::max(curr.distance, next.distance) - min_malformation_dist) / - (peak_malformation_dist - min_malformation_dist); - distance_penalty = std::min(1.0f, distance_penalty); + auto calculate_speed = [&speed_sections, &original_speed](float distance) { + float final_speed; + if (distance <= speed_sections.front().first) { + final_speed = original_speed; + } else if (distance >= speed_sections.back().first) { + final_speed = speed_sections.back().second; + } else { + 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; } diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 2ace05a9a..35b4a331a 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -474,7 +474,6 @@ void Layer::make_perimeters() && config.perimeters == other_config.perimeters && config.perimeter_speed == other_config.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.) == (other_config.gap_fill_enabled ? other_config.gap_fill_speed.value : 0.) && config.overhangs == other_config.overhangs diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index fcbe87d1e..7d61a138e 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -428,7 +428,8 @@ static std::vector s_Preset_print_options { "max_print_speed", "max_volumetric_speed", "avoid_crossing_perimeters_max_detour", "fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_dist", "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", "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", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 39c028aca..df3302ca3 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -528,6 +528,36 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; 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->label = L("Brim width"); def->category = L("Skirt and brim"); @@ -2358,18 +2388,6 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; 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->label = L("Solid infill threshold area"); def->category = L("Infill"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 0d726ec8b..ba4d1d26b 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -564,7 +564,9 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionEnum, bottom_fill_pattern)) ((ConfigOptionFloatOrPercent, external_perimeter_extrusion_width)) ((ConfigOptionFloatOrPercent, external_perimeter_speed)) - ((ConfigOptionFloatOrPercent, overhang_speed)) + ((ConfigOptionBool, enable_dynamic_overhang_speeds)) + ((ConfigOptionPercents, overhang_overlaps)) + ((ConfigOptionFloatsOrPercents, dynamic_overhang_speeds)) ((ConfigOptionBool, external_perimeters_first)) ((ConfigOptionBool, extra_perimeters)) ((ConfigOptionBool, extra_perimeters_on_overhangs)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 397a25a37..6f771b1d2 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -748,7 +748,9 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "support_material_speed" || opt_key == "support_material_interface_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 == "infill_speed" || opt_key == "perimeter_speed" diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 5612d9c78..131adee60 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -220,9 +220,12 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) bool have_perimeters = config->opt_int("perimeters") > 0; 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", - "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("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("fill_density")->value > 0; // infill_extruder uses the same logic as in Print::extruders() for (auto el : { "fill_pattern", "infill_every_layers", "infill_only_where_needed", diff --git a/src/slic3r/GUI/PresetHints.cpp b/src/slic3r/GUI/PresetHints.cpp index d17b15dff..ce709d9eb 100644 --- a/src/slic3r/GUI/PresetHints.cpp +++ b/src/slic3r/GUI/PresetHints.cpp @@ -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 perimeter_speed = print_config.opt_float("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 infill_speed = print_config.opt_float("infill_speed"); double small_perimeter_speed = print_config.get_abs_value("small_perimeter_speed", perimeter_speed); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index ae519e9cf..6cf2509f5 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1,4 +1,5 @@ // #include "libslic3r/GCodeSender.hpp" +#include "slic3r/GUI/BedShapeDialog.hpp" #include "slic3r/Utils/Serial.hpp" #include "Tab.hpp" #include "PresetHints.hpp" @@ -1541,7 +1542,6 @@ void TabPrint::build() optgroup->append_single_option_line("perimeter_speed"); optgroup->append_single_option_line("small_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("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("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->append_single_option_line("travel_speed"); optgroup->append_single_option_line("travel_speed_z"); diff --git a/tests/fff_print/test_cooling.cpp b/tests/fff_print/test_cooling.cpp index c84026626..361a4c311 100644 --- a/tests/fff_print/test_cooling.cpp +++ b/tests/fff_print/test_cooling.cpp @@ -176,7 +176,7 @@ SCENARIO("Cooling integration tests", "[Cooling]") { { "fan_below_layer_time", { 0 } }, { "slowdown_below_layer_time", { 0 } }, { "bridge_speed", 99 }, - { "overhangs", false }, + { "enable_dynamic_overhang_speeds", false }, // internal bridges use solid_infil speed { "bottom_solid_layers", 1 }, // internal bridges use solid_infil speed diff --git a/tests/fff_print/test_perimeters.cpp b/tests/fff_print/test_perimeters.cpp index 3c9a2f4ad..1434f35a4 100644 --- a/tests/fff_print/test_perimeters.cpp +++ b/tests/fff_print/test_perimeters.cpp @@ -309,7 +309,7 @@ SCENARIO("Perimeters", "[Perimeters]") { "perimeters", 1 }, { "perimeter_speed", 77 }, { "external_perimeter_speed", 66 }, - { "overhang_speed", 60 }, + { "enable_dynamic_overhang_speeds", false }, { "bridge_speed", 99 }, { "cooling", "1" }, { "fan_below_layer_time", "0" }, @@ -330,11 +330,10 @@ SCENARIO("Perimeters", "[Perimeters]") 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 bridge_speed = config.opt_float("bridge_speed") * 60.; - const double overhang_speed = config.opt("overhang_speed")->value * 60.; const double nozzle_dmr = config.opt("nozzle_diameter")->get_at(0); const double filament_dmr = config.opt("filament_diameter")->get_at(0); 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) { if (line.cmd_is("M107")) @@ -343,14 +342,13 @@ SCENARIO("Perimeters", "[Perimeters]") line.has_value('S', fan_speed); else if (line.extruding(self) && line.dist_XY(self) > 0) { double feedrate = line.new_F(self); - REQUIRE((is_approx(feedrate, perimeter_speed) || is_approx(feedrate, bridge_speed) || - (feedrate >= overhang_speed && feedrate <= external_perimeter_speed))); + REQUIRE((is_approx(feedrate, perimeter_speed) || is_approx(feedrate, external_perimeter_speed) || is_approx(feedrate, bridge_speed))); layer_speeds[self.z()].insert(feedrate); bool bridging = is_approx(feedrate, bridge_speed); double mm_per_mm = line.dist_E(self) / line.dist_XY(self); // Fan enabled at full speed when bridging, disabled when not bridging. 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. REQUIRE((! bridging || std::abs(mm_per_mm - bridge_mm_per_mm) <= 0.01)); } @@ -377,7 +375,6 @@ SCENARIO("Perimeters", "[Perimeters]") { "external_perimeter_speed", 99 }, { "small_perimeter_speed", 99 }, { "thin_walls", 0 }, - { "overhangs", false }, }); std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::ipadstand }, config); @@ -533,7 +530,7 @@ SCENARIO("Perimeters3", "[Perimeters]") { "skirts", 0 }, { "perimeters", 3 }, { "layer_height", 0.4 }, - { "overhang_speed", 5 }, + { "enable_dynamic_overhang_speeds", false }, // to prevent bridging over sparse infill { "fill_density", 0 }, { "overhangs", true }, @@ -547,25 +544,26 @@ SCENARIO("Perimeters3", "[Perimeters]") std::string gcode = Slic3r::Test::slice({ mesh(Slic3r::Test::TestMesh::V, Vec3d::Zero(), scale) }, config); GCodeReader parser; std::set z_with_bridges; - const double overhang_speed = config.opt("overhang_speed")->value * 60.; - parser.parse_buffer(gcode, [&z_with_bridges, overhang_speed](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) + const double bridge_speed = config.opt_float("bridge_speed") * 60.; + 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 && - (is_approx(line.new_F(self), overhang_speed))) + if (line.extruding(self) && line.dist_XY(self) > 0 && is_approx(line.new_F(self), bridge_speed)) z_with_bridges.insert(scaled(self.z())); }); return z_with_bridges.size(); }; - GIVEN("V shape, scaled 0.5x in X") { - int n = test(Vec3d(0.5, 1., 1.)); - THEN("no overhangs printed with overhangs speed") { - REQUIRE(n == 0); + GIVEN("V shape, unscaled") { + int n = test(Vec3d(1., 1., 1.)); + // except for the two internal solid layers above void + THEN("no overhangs printed with bridge speed") { + REQUIRE(n == 1); } } GIVEN("V shape, scaled 3x in X") { 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); } }