From 1717c0f263c05cc9411db9b694d53e84c4ab2d21 Mon Sep 17 00:00:00 2001 From: Robert J Audas Date: Mon, 6 Jul 2026 16:04:32 -0600 Subject: [PATCH] Fix brim first layer speed (#14616) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/libslic3r/GCode.cpp | 5 ++-- tests/fff_print/test_skirt_brim.cpp | 43 +++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 6740b2d234..0b62fd0d6f 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -6613,8 +6613,9 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, //BBS: for solid infill of first layer, speed can be higher as long as //wall lines have be attached if (path.role() != erBottomSurface) { - speed = is_perimeter(path.role()) ? NOZZLE_CONFIG(initial_layer_speed) : - NOZZLE_CONFIG(initial_layer_infill_speed); + const bool use_first_layer_speed = is_perimeter(path.role()) || path.role() == erBrim; + speed = use_first_layer_speed ? NOZZLE_CONFIG(initial_layer_speed) : + NOZZLE_CONFIG(initial_layer_infill_speed); } } else if (m_config.slow_down_layers > 1 && m_config.raft_layers == 0) { diff --git a/tests/fff_print/test_skirt_brim.cpp b/tests/fff_print/test_skirt_brim.cpp index a9df0fee69..2ff4baa6fb 100644 --- a/tests/fff_print/test_skirt_brim.cpp +++ b/tests/fff_print/test_skirt_brim.cpp @@ -191,6 +191,24 @@ SCENARIO("Brim has the configured number of loops", "[SkirtBrim]") { } } +static double first_extrusion_feedrate_for_feature(const std::string &gcode, const std::string_view feature) +{ + double feedrate = 0.0; + bool feature_active = false; + GCodeReader parser; + parser.parse_buffer(gcode, [&feedrate, &feature_active, feature] (GCodeReader &self, const GCodeReader::GCodeLine &line) { + const std::string_view comment = line.comment(); + if (comment.find("FEATURE:") != std::string_view::npos || comment.find("TYPE:") != std::string_view::npos) + feature_active = comment.find(feature) != std::string_view::npos; + + if (feature_active && line.extruding(self) && line.dist_XY(self) > 0) { + feedrate = line.new_F(self); + self.quit_parsing(); + } + }); + return feedrate; +} + TEST_CASE("Skirt height is honored", "[SkirtBrim]") { DynamicPrintConfig config = DynamicPrintConfig::full_print_config(); config.set_deserialize_strict({ @@ -210,6 +228,31 @@ TEST_CASE("Skirt height is honored", "[SkirtBrim]") { REQUIRE(layers_with_role(gcode, "skirt").size() == (size_t) config.opt_int("skirt_height")); } +TEST_CASE("Brim uses first layer speed", "[SkirtBrim]") { + DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "brim_type", "outer_only" }, + { "brim_width", 5 }, + { "gcode_comments", true }, + { "initial_layer_speed", 10 }, + { "initial_layer_infill_speed", 20 }, + { "machine_start_gcode", "" }, + { "skirt_loops", 0 }, + { "slow_down_for_layer_cooling", false }, + { "z_hop", 0 } + }); + + const std::string gcode = Slic3r::Test::slice({TestMesh::cube_20x20x20}, config); + + const double brim_feedrate = first_extrusion_feedrate_for_feature(gcode, "Brim"); + REQUIRE(brim_feedrate > 0.0); + REQUIRE_THAT(brim_feedrate, Catch::Matchers::WithinAbs(600.0, 1e-3)); + + const double bottom_surface_feedrate = first_extrusion_feedrate_for_feature(gcode, "Bottom surface"); + REQUIRE(bottom_surface_feedrate > 0.0); + REQUIRE_THAT(bottom_surface_feedrate, Catch::Matchers::WithinAbs(1200.0, 1e-3)); +} + SCENARIO("Skirt and brim generation", "[SkirtBrim]") { GIVEN("A default configuration") { DynamicPrintConfig config = DynamicPrintConfig::full_print_config();