diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 8e7d5e7557..f41a4443fb 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -3598,6 +3598,10 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) if (has_scarf_joint_seam != nullptr) m_detect_layer_based_on_tag = m_detect_layer_based_on_tag || has_scarf_joint_seam->value; + const ConfigOptionBool* manual_filament_change = config.option("manual_filament_change"); + if (manual_filament_change != nullptr) + m_manual_filament_change = manual_filament_change->value; + const ConfigOptionEnumGeneric *bed_type = config.option("curr_bed_type"); if (bed_type != nullptr) m_result.bed_type = (BedType)bed_type->value; diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index f5b9985f0e..270aceb1c3 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -1228,7 +1228,7 @@ inline constexpr float DEFAULT_FILAMENT_DENSITY = 1.245f; // m_result.nozzle_group_result, which is handed over only after the stream for the // pre-heat injector's second pass and gates the richer change-time model. std::shared_ptr m_nozzle_group_result; - bool m_manual_filament_change; + bool m_manual_filament_change{ false }; //BBS: x, y offset for gcode generated double m_x_offset{ 0 }; diff --git a/tests/fff_print/test_gcodeprocessor.cpp b/tests/fff_print/test_gcodeprocessor.cpp index 0be8cc1c12..48cf3e8ae9 100644 --- a/tests/fff_print/test_gcodeprocessor.cpp +++ b/tests/fff_print/test_gcodeprocessor.cpp @@ -178,6 +178,61 @@ bool is_block_move(const GCodeProcessorResult::MoveVertex &move) } // namespace +TEST_CASE("Loaded manual tool change comments switch subsequent moves when enabled", "[GCodeProcessor][Regression]") +{ + const bool manual_filament_change = GENERATE(false, true); + CAPTURE(manual_filament_change); + const DynamicPrintConfig config = Test::multifilament_config(2, { + { "gcode_flavor", "marlin" }, + { "filament_type", "PLA;PETG" }, + { "manual_filament_change", manual_filament_change }, + }); + const bool was_bbl_printer = GCodeProcessor::s_IsBBLPrinter; + const ScopeGuard restore_bbl_printer([was_bbl_printer] { GCodeProcessor::s_IsBBLPrinter = was_bbl_printer; }); + GCodeProcessor::s_IsBBLPrinter = false; + + ScopedTemporaryFile temp(".gcode"); + { + std::ofstream out(temp.string()); + REQUIRE(out.is_open()); + out << "; generated by OrcaSlicer\n" + << "G90\nM83\nT0\n" + << "G1 X10 Y10 Z0.2 F3000\n" + << "G1 X20 E1\n" + << "; MANUAL_TOOL_CHANGE T1\n" + << "G1 X30\nG1 X40 E1\nG1 X50\nG1 X60 E1\n"; + // Let process_file load the embedded DynamicPrintConfig, as the standalone viewer does. + out << "; CONFIG_BLOCK_START\n"; + for (const std::string &key : config.keys()) + out << "; " << key << " = " << config.opt_serialize(key) << '\n'; + out << "; CONFIG_BLOCK_END\n"; + REQUIRE(out.good()); + } + + GCodeProcessor processor; + processor.process_file(temp.string()); + const auto &result = processor.get_result(); + REQUIRE(result.filaments_count == 2); + + constexpr unsigned int tool_change_line = 7; + size_t before = 0; + size_t after = 0; + for (const auto &move : result.moves) { + if (!is_block_move(move)) + continue; + CAPTURE(move.gcode_id, move.type); + if (move.gcode_id < tool_change_line) { + ++before; + CHECK(move.extruder_id == 0); + } else if (move.gcode_id > tool_change_line) { + ++after; + CHECK(move.extruder_id == (manual_filament_change ? 1 : 0)); + } + } + REQUIRE(before > 0); + REQUIRE(after > 0); +} + TEST_CASE("Actual speed moves are inserted on their block's segment just before its move", "[GCodeProcessor]") { // 60 squares take several planner passes, which remap the blocks kept between passes.