diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 1701382e3d..a08554654a 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -730,6 +730,42 @@ static std::vector get_path_of_change_filament(const Print& print) return temp_set_by_gcode; } + struct CustomGCodeMotionStateChanges + { + bool acceleration = false; + bool jerk = false; + }; + + static bool custom_gcode_line_has_xy_parameter(const std::string &raw) + { + const size_t comment_pos = raw.find(';'); + const std::string_view code(raw.data(), comment_pos == std::string::npos ? raw.size() : comment_pos); + return code.find_first_of("XxYy") != std::string_view::npos; + } + + static CustomGCodeMotionStateChanges custom_gcode_motion_state_changes(const std::string &gcode) + { + CustomGCodeMotionStateChanges changes; + GCodeReader parser; + parser.parse_buffer(gcode, [&changes](GCodeReader &parser, const GCodeReader::GCodeLine &line) { + const std::string_view cmd = line.cmd(); + if (boost::iequals(cmd, "M204") || boost::iequals(cmd, "M201") || + boost::iequals(cmd, "M202")) + changes.acceleration = true; + else if ((boost::iequals(cmd, "M205") || boost::iequals(cmd, "M207") || boost::iequals(cmd, "M566")) && + custom_gcode_line_has_xy_parameter(line.raw())) + changes.jerk = true; + else if (boost::iequals(cmd, "SET_VELOCITY_LIMIT")) { + changes.acceleration |= boost::icontains(line.raw(), "ACCEL="); + changes.jerk |= boost::icontains(line.raw(), "SQUARE_CORNER_VELOCITY="); + } + + if (changes.acceleration && changes.jerk) + parser.quit_parsing(); + }); + return changes; + } + // BBS // start_pos refers to the last position before the wipe_tower. // end_pos refers to the wipe tower's start_pos. @@ -4335,6 +4371,11 @@ PlaceholderParserIntegration &ppi = m_placeholder_parser_integration; ppi.update_from_gcodewriter(m_writer); std::string output = ppi.parser.process(templ, current_filament_id, config_override, &ppi.output_config, &ppi.context); ppi.validate_output_vector_variables(); + const CustomGCodeMotionStateChanges motion_state_changes = custom_gcode_motion_state_changes(output); + if (motion_state_changes.acceleration) + m_writer.invalidate_acceleration(); + if (motion_state_changes.jerk) + m_writer.invalidate_jerk(); if (const std::vector &pos = ppi.opt_position->values; ppi.position != pos) { // Update G-code writer. diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index e904f3f35b..fcb63c3e96 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -133,6 +133,8 @@ public: const bool is_bbl_printers() const {return m_is_bbl_printers;} void set_is_first_layer(bool bval) { m_is_first_layer = bval; } GCodeFlavor get_gcode_flavor() const { return config.gcode_flavor; } + void invalidate_acceleration() { m_last_acceleration = 0; m_last_travel_acceleration = 0; } + void invalidate_jerk() { m_last_jerk = 0; } // Returns whether this flavor supports separate print and travel acceleration. static bool supports_separate_travel_acceleration(GCodeFlavor flavor); diff --git a/src/slic3r/GUI/LibVGCode/LibVGCodeWrapper.cpp b/src/slic3r/GUI/LibVGCode/LibVGCodeWrapper.cpp index 5b5c7da076..8a3c497eae 100644 --- a/src/slic3r/GUI/LibVGCode/LibVGCodeWrapper.cpp +++ b/src/slic3r/GUI/LibVGCode/LibVGCodeWrapper.cpp @@ -215,8 +215,8 @@ GCodeInputData convert(const Slic3r::GCodeProcessorResult& result, const std::ve const EOptionType option_type = move_type_to_option(curr_type); if (option_type == EOptionType::COUNT || option_type == EOptionType::Travels || option_type == EOptionType::Wipes) { if (ret.vertices.empty() || prev.type != curr.type || prev.extrusion_role != curr.extrusion_role - // ORCA: Fix issue with flow rate changes being visualized incorrectly - || prev.mm3_per_mm != curr.mm3_per_mm) { + // ORCA: Split the path when a preview value changes. + || prev.mm3_per_mm != curr.mm3_per_mm || prev.acceleration != curr.acceleration || prev.jerk != curr.jerk) { // to allow libvgcode to properly detect the start/end of a path we need to add a 'phantom' vertex // equal to the current one with the exception of the position, which should match the previous move position, // and the times, which are set to zero diff --git a/tests/fff_print/test_gcodewriter.cpp b/tests/fff_print/test_gcodewriter.cpp index 022b7841fc..b09b38e794 100644 --- a/tests/fff_print/test_gcodewriter.cpp +++ b/tests/fff_print/test_gcodewriter.cpp @@ -820,3 +820,30 @@ SCENARIO("Shipped dual-nozzle change_filament_gcode resolves during a real slice } } } + +TEST_CASE("Custom G-code motion limits are restored before generated moves", "[GCodeWriter]") +{ + const std::string gcode = Slic3r::Test::slice({ cube(20) }, { + { "gcode_flavor", "marlin" }, + { "gcode_comments", "1" }, + { "machine_start_gcode", "" }, + { "layer_change_gcode", "M204 S5000\nm205 x5 y5\n" }, + { "layer_height", "0.2" }, + { "initial_layer_print_height", "0.2" }, + { "initial_layer_line_width", "0" }, + { "z_hop", "0" }, + { "default_acceleration", "6000" }, + { "initial_layer_acceleration", "6000" }, + { "outer_wall_acceleration", "6000" }, + { "inner_wall_acceleration", "0" }, + { "default_jerk", "8" }, + { "initial_layer_jerk", "8" }, + { "outer_wall_jerk", "8" }, + { "inner_wall_jerk", "0" }, + }); + + const size_t custom_gcode_pos = gcode.find("m205 x5 y5"); + REQUIRE(custom_gcode_pos != std::string::npos); + REQUIRE(gcode.find("M204 S6000 ; adjust acceleration", custom_gcode_pos) != std::string::npos); + REQUIRE(gcode.find("M205 X8 Y8 ; adjust jerk", custom_gcode_pos) != std::string::npos); +}