From c9724ae6fdbdff248f2d7ed1d1a291490eb60acd Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 18 Jan 2023 11:00:20 +0100 Subject: [PATCH] Modify gcode post-process to allow to insert new gcode lines by backtracing from the current processed line. Current state is a prototype and the new code is embedded into a new tech: ENABLE_GCODE_POSTPROCESS_BACKTRACE --- src/libslic3r/GCode/GCodeProcessor.cpp | 367 ++++++++++++++++++++++++- src/libslic3r/GCode/GCodeProcessor.hpp | 3 + src/libslic3r/GCodeReader.hpp | 12 + src/libslic3r/Technologies.hpp | 2 + 4 files changed, 382 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 9b371e405..b5fc12e5a 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -441,6 +441,9 @@ void GCodeProcessorResult::reset() { max_print_height = 0.0f; settings_ids.reset(); extruders_count = 0; +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + backtrace_enabled = false; +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE extruder_colors = std::vector(); filament_diameters = std::vector(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER); filament_densities = std::vector(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY); @@ -458,6 +461,9 @@ void GCodeProcessorResult::reset() { max_print_height = 0.0f; settings_ids.reset(); extruders_count = 0; +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + backtrace_enabled = false; +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE extruder_colors = std::vector(); filament_diameters = std::vector(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER); filament_densities = std::vector(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY); @@ -551,6 +557,11 @@ void GCodeProcessor::apply_config(const PrintConfig& config) m_producer = EProducer::PrusaSlicer; m_flavor = config.gcode_flavor; +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + m_result.backtrace_enabled = config.printer_model.value == "MK3MMU2" || config.printer_model.value == "MK3SMMU2S" || + config.printer_model.value == "MK2.5MMU2" || config.printer_model.value == "MK2.5SMMU2S" || config.printer_model.value == "MK2SMM"; +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE + size_t extruders_count = config.nozzle_diameter.values.size(); m_result.extruders_count = extruders_count; @@ -3461,18 +3472,259 @@ void GCodeProcessor::post_process() last_exported_stop[i] = time_in_minutes(m_time_processor.machines[i].time); } +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + // Helper class to modify and export gcode to file + class ExportLines + { + public: + struct Backtrace + { + float time{ 60.0f }; + unsigned int steps{ 10 }; + float time_step() const { return time / float(steps); } + }; + + enum class EWriteType + { + BySize, + ByTime + }; + + private: + struct LineData + { + std::string line; + float time; + }; + +#ifndef NDEBUG + class Statistics + { + ExportLines& m_parent; + size_t m_max_size{ 0 }; + size_t m_lines_count{ 0 }; + size_t m_max_lines_count{ 0 }; + + public: + explicit Statistics(ExportLines& parent) + : m_parent(parent) + {} + + void add_line(size_t line_size) { + ++m_lines_count; + m_max_size = std::max(m_max_size, m_parent.get_size() + line_size); + m_max_lines_count = std::max(m_max_lines_count, m_lines_count); + } + + void remove_line() { --m_lines_count; } + void remove_all_lines() { m_lines_count = 0; } + }; + + Statistics m_statistics; +#endif // NDEBUG + + EWriteType m_write_type{ EWriteType::BySize }; + // Time machine containing g1 times cache + TimeMachine& m_machine; + // Current time + float m_time{ 0.0f }; + // Current size in bytes + size_t m_size{ 0 }; + + // gcode lines cache + std::deque m_lines; + size_t m_added_lines_counter{ 0 }; + // map of gcode line ids from original to final + // used to update m_result.moves[].gcode_id + std::vector> m_gcode_lines_map; + + size_t m_curr_g1_id{ 0 }; + size_t m_out_file_pos{ 0 }; + + public: + ExportLines(EWriteType type, TimeMachine& machine) +#ifndef NDEBUG + : m_statistics(*this), m_write_type(type), m_machine(machine) {} +#else + : m_write_type(type), m_machine(machine) {} +#endif // NDEBUG + + void update(size_t lines_counter, size_t g1_lines_counter) { + m_gcode_lines_map.push_back({ lines_counter, 0 }); + + if (g1_lines_counter == 0) + return; + + auto init_it = m_machine.g1_times_cache.begin() + m_curr_g1_id; + auto it = init_it; + while (it != m_machine.g1_times_cache.end() && it->id < g1_lines_counter + 1) { + ++it; + ++m_curr_g1_id; + } + + if (it != init_it || m_curr_g1_id == 0) + m_time = it->elapsed_time; + } + + // add the given gcode line to the cache + void append_line(const std::string& line) { + m_lines.push_back({ line, m_time }); +#ifndef NDEBUG + m_statistics.add_line(line.length()); +#endif // NDEBUG + m_size += line.length(); + ++m_added_lines_counter; + assert(!m_gcode_lines_map.empty()); + m_gcode_lines_map.back().second = m_added_lines_counter; + } + + // Insert the gcode lines required by the command cmd by backtracing into the cache + void insert_lines(const Backtrace& backtrace, const std::string& cmd, std::function line_inserter) { + assert(!m_lines.empty()); + const float time_step = backtrace.time_step(); + size_t rev_it_dist = 0; // distance from the end of the cache of the starting point of the backtrace + float last_time_insertion = 0.0f; // used to avoid inserting two lines at the same time + for (unsigned int i = 0; i < backtrace.steps; ++i) { + const float backtrace_time_i = (i + 1) * time_step; + const float time_threshold_i = m_time - backtrace_time_i; + auto rev_it = m_lines.rbegin() + rev_it_dist; + auto start_rev_it = rev_it; + + // backtrace into the cache to find the place where to insert the line + while (rev_it != m_lines.rend() && rev_it->time > time_threshold_i && GCodeReader::GCodeLine::extract_cmd(rev_it->line) != cmd) { + ++rev_it; + } + + // we met the previous evenience of cmd. stop inserting lines + if (rev_it != m_lines.rend() && GCodeReader::GCodeLine::extract_cmd(rev_it->line) == cmd) + break; + + // insert the line for the current step + if (rev_it != m_lines.rend() && rev_it != start_rev_it && rev_it->time != last_time_insertion) { + last_time_insertion = rev_it->time; + const std::string out_line = line_inserter(i + 1, last_time_insertion, m_time - last_time_insertion); + rev_it_dist = std::distance(m_lines.rbegin(), rev_it) + 1; + const auto new_it = m_lines.insert(rev_it.base(), { out_line, rev_it->time }); +#ifndef NDEBUG + m_statistics.add_line(out_line.length()); +#endif // NDEBUG + m_size += out_line.length(); + // synchronize gcode lines map + for (auto map_it = m_gcode_lines_map.rbegin(); map_it != m_gcode_lines_map.rbegin() + rev_it_dist - 1; ++map_it) { + ++map_it->second; + } + + ++m_added_lines_counter; + } + } + } + + // write to file: + // m_write_type == EWriteType::ByTime - all lines older than m_time - backtrace_time + // m_write_type == EWriteType::BySize - all lines if current size is greater than 65535 bytes + void write(FilePtr& out, float backtrace_time, GCodeProcessorResult& result, const std::string& out_path) { + if (m_lines.empty()) + return; + + // collect lines to write into a single string + std::string out_string; + if (!m_lines.empty()) { + if (m_write_type == EWriteType::ByTime) { + while (m_lines.front().time < m_time - backtrace_time) { + const LineData& data = m_lines.front(); + out_string += data.line; + m_size -= data.line.length(); + m_lines.pop_front(); +#ifndef NDEBUG + m_statistics.remove_line(); +#endif // NDEBUG + } + } + else { + if (m_size > 65535) { + while (!m_lines.empty()) { + out_string += m_lines.front().line; + m_lines.pop_front(); + } + m_size = 0; +#ifndef NDEBUG + m_statistics.remove_all_lines(); +#endif // NDEBUG + } + } + } + + write_to_file(out, out_string, result, out_path); + } + + // flush the current content of the cache to file + void flush(FilePtr& out, GCodeProcessorResult& result, const std::string& out_path) { + // collect lines to flush into a single string + std::string out_string; + while (!m_lines.empty()) { + out_string += m_lines.front().line; + m_lines.pop_front(); + } + m_size = 0; +#ifndef NDEBUG + m_statistics.remove_all_lines(); +#endif // NDEBUG + + write_to_file(out, out_string, result, out_path); + } + + void synchronize_moves(GCodeProcessorResult& result) const { + auto it = m_gcode_lines_map.begin(); + for (GCodeProcessorResult::MoveVertex& move : result.moves) { + while (it != m_gcode_lines_map.end() && it->first < move.gcode_id) { + ++it; + } + if (it != m_gcode_lines_map.end() && it->first == move.gcode_id) + move.gcode_id = it->second; + } + } + + size_t get_size() const { return m_size; } + + private: + void write_to_file(FilePtr& out, const std::string& out_string, GCodeProcessorResult& result, const std::string& out_path) { + if (!out_string.empty()) { + fwrite((const void*)out_string.c_str(), 1, out_string.length(), out.f); + if (ferror(out.f)) { + out.close(); + boost::nowide::remove(out_path.c_str()); + throw Slic3r::RuntimeError(std::string("GCode processor post process export failed.\nIs the disk full?\n")); + } + for (size_t i = 0; i < out_string.size(); ++i) { + if (out_string[i] == '\n') + result.lines_ends.emplace_back(m_out_file_pos + i + 1); + } + m_out_file_pos += out_string.size(); + } + } + }; + + ExportLines export_lines(m_result.backtrace_enabled ? ExportLines::EWriteType::ByTime : ExportLines::EWriteType::BySize, m_time_processor.machines[0]); +#else // buffer line to export only when greater than 64K to reduce writing calls std::string export_line; +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE // replace placeholder lines with the proper final value // gcode_line is in/out parameter, to reduce expensive memory allocation auto process_placeholders = [&](std::string& gcode_line) { +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + bool processed = false; +#else unsigned int extra_lines_count = 0; +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE // remove trailing '\n' auto line = std::string_view(gcode_line).substr(0, gcode_line.length() - 1); +#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE std::string ret; +#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE if (line.length() > 1) { line = line.substr(1); if (m_time_processor.export_remaining_time_enabled && @@ -3481,17 +3733,29 @@ void GCodeProcessor::post_process() const TimeMachine& machine = m_time_processor.machines[i]; if (machine.enabled) { // export pair +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + export_lines.append_line(format_line_M73_main(machine.line_m73_main_mask.c_str(), + (line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? 0 : 100, + (line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? time_in_minutes(machine.time) : 0)); + processed = true; +#else ret += format_line_M73_main(machine.line_m73_main_mask.c_str(), (line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? 0 : 100, (line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? time_in_minutes(machine.time) : 0); ++extra_lines_count; +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE // export remaining time to next printer stop if (line == reserved_tag(ETags::First_Line_M73_Placeholder) && !machine.stop_times.empty()) { - int to_export_stop = time_in_minutes(machine.stop_times.front().elapsed_time); + const int to_export_stop = time_in_minutes(machine.stop_times.front().elapsed_time); +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + export_lines.append_line(format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop)); + last_exported_stop[i] = to_export_stop; +#else ret += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop); last_exported_stop[i] = to_export_stop; ++extra_lines_count; +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE } } } @@ -3505,7 +3769,12 @@ void GCodeProcessor::post_process() sprintf(buf, "; estimated printing time (%s mode) = %s\n", (mode == PrintEstimatedStatistics::ETimeMode::Normal) ? "normal" : "silent", get_time_dhms(machine.time).c_str()); +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + export_lines.append_line(buf); + processed = true; +#else ret += buf; +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE } } for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { @@ -3516,16 +3785,25 @@ void GCodeProcessor::post_process() sprintf(buf, "; estimated first layer printing time (%s mode) = %s\n", (mode == PrintEstimatedStatistics::ETimeMode::Normal) ? "normal" : "silent", get_time_dhms(machine.layers_time.empty() ? 0.f : machine.layers_time.front()).c_str()); +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + export_lines.append_line(buf); + processed = true; +#else ret += buf; +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE } } } } +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + return processed; +#else if (!ret.empty()) // Not moving the move operator on purpose, so that the gcode_line allocation will grow and it will not be reallocated after handful of lines are processed. gcode_line = ret; return std::tuple(!ret.empty(), (extra_lines_count == 0) ? extra_lines_count : extra_lines_count - 1); +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE }; std::vector filament_mm(m_result.extruders_count, 0.0); @@ -3599,10 +3877,16 @@ void GCodeProcessor::post_process() time_in_minutes, format_time_float, format_line_M73_main, format_line_M73_stop_int, format_line_M73_stop_float, time_in_last_minute, // Caches, to be modified &g1_times_cache_it, &last_exported_main, &last_exported_stop, +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + &export_lines] +#else // String output &export_line] +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE (const size_t g1_lines_counter) { +#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE unsigned int exported_lines_count = 0; +#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE if (m_time_processor.export_remaining_time_enabled) { for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { const TimeMachine& machine = m_time_processor.machines[i]; @@ -3616,10 +3900,17 @@ void GCodeProcessor::post_process() std::pair to_export_main = { int(100.0f * it->elapsed_time / machine.time), time_in_minutes(machine.time - it->elapsed_time) }; if (last_exported_main[i] != to_export_main) { +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + export_lines.append_line(format_line_M73_main(machine.line_m73_main_mask.c_str(), + to_export_main.first, to_export_main.second)); +#else export_line += format_line_M73_main(machine.line_m73_main_mask.c_str(), to_export_main.first, to_export_main.second); +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE last_exported_main[i] = to_export_main; +#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE ++exported_lines_count; +#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE } // export remaining time to next printer stop auto it_stop = std::upper_bound(machine.stop_times.begin(), machine.stop_times.end(), it->elapsed_time, @@ -3629,9 +3920,15 @@ void GCodeProcessor::post_process() if (last_exported_stop[i] != to_export_stop) { if (to_export_stop > 0) { if (last_exported_stop[i] != to_export_stop) { +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + export_lines.append_line(format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop)); +#else export_line += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop); +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE last_exported_stop[i] = to_export_stop; +#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE ++exported_lines_count; +#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE } } else { @@ -3650,13 +3947,22 @@ void GCodeProcessor::post_process() } if (is_last) { +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + if (std::distance(machine.stop_times.begin(), it_stop) == static_cast(machine.stop_times.size() - 1)) + export_lines.append_line(format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop)); + else + export_lines.append_line(format_line_M73_stop_float(machine.line_m73_stop_mask.c_str(), time_in_last_minute(it_stop->elapsed_time - it->elapsed_time))); +#else if (std::distance(machine.stop_times.begin(), it_stop) == static_cast(machine.stop_times.size() - 1)) export_line += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop); else export_line += format_line_M73_stop_float(machine.line_m73_stop_mask.c_str(), time_in_last_minute(it_stop->elapsed_time - it->elapsed_time)); +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE last_exported_stop[i] = to_export_stop; +#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE ++exported_lines_count; +#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE } } } @@ -3665,12 +3971,26 @@ void GCodeProcessor::post_process() } } } +#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE return exported_lines_count; +#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE }; +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + // add lines XXX to exported gcode + auto process_line_T = [this, &export_lines](const std::string& gcode_line, const size_t g1_lines_counter, const ExportLines::Backtrace& backtrace) { + const std::string cmd = GCodeReader::GCodeLine::extract_cmd(gcode_line); + export_lines.insert_lines(backtrace, cmd, [](unsigned int id, float time, float time_diff) { + const std::string out = "XYYY ; id:" + std::to_string(id) + " time:" + std::to_string(time) + " time diff:" + std::to_string(time_diff) + "\n"; + return out; + }); + }; +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE + + m_result.lines_ends.clear(); +#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE // helper function to write to disk size_t out_file_pos = 0; - m_result.lines_ends.clear(); auto write_string = [this, &export_line, &out, &out_path, &out_file_pos](const std::string& str) { fwrite((const void*)export_line.c_str(), 1, export_line.length(), out.f); if (ferror(out.f)) { @@ -3684,9 +4004,18 @@ void GCodeProcessor::post_process() out_file_pos += export_line.size(); export_line.clear(); }; +#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE unsigned int line_id = 0; +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + // Backtrace data for Tx gcode lines + static const ExportLines::Backtrace backtrace_T = { 60.0f, 10 }; + // In case there are multiple sources of backtracing, keeps track of the longest backtrack time needed + // to flush the backtrace cache accordingly + float max_backtrace_time = 60.0f; +#else std::vector> offsets; +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE { // Read the input stream 64kB at a time, extract lines and process them. @@ -3710,14 +4039,39 @@ void GCodeProcessor::post_process() gcode_line.insert(gcode_line.end(), it, it_end); if (eol) { ++line_id; +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + export_lines.update(line_id, g1_lines_counter); +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE gcode_line += "\n"; // replace placeholder lines +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + bool processed = process_placeholders(gcode_line); + if (processed) + gcode_line.clear(); +#else auto [processed, lines_added_count] = process_placeholders(gcode_line); if (processed && lines_added_count > 0) offsets.push_back({ line_id, lines_added_count }); +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE if (!processed) processed = process_used_filament(gcode_line); +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + if (!processed && !is_temporary_decoration(gcode_line)) { + if (GCodeReader::GCodeLine::cmd_is(gcode_line, "G1")) + // add lines M73 where needed + process_line_G1(g1_lines_counter++); + else if (m_result.backtrace_enabled && GCodeReader::GCodeLine::cmd_starts_with(gcode_line, "T")) { + // add lines XXX where needed + process_line_T(gcode_line, g1_lines_counter, backtrace_T); + max_backtrace_time = std::max(max_backtrace_time, backtrace_T.time); + } + } + + if (!gcode_line.empty()) + export_lines.append_line(gcode_line); + export_lines.write(out, 1.1f * max_backtrace_time, m_result, out_path); +#else if (!processed && !is_temporary_decoration(gcode_line) && GCodeReader::GCodeLine::cmd_is(gcode_line, "G1")) { // remove temporary lines, add lines M73 where needed unsigned int extra_lines_count = process_line_G1(g1_lines_counter++); @@ -3728,6 +4082,7 @@ void GCodeProcessor::post_process() export_line += gcode_line; if (export_line.length() > 65535) write_string(export_line); +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE gcode_line.clear(); } // Skip EOL. @@ -3742,12 +4097,19 @@ void GCodeProcessor::post_process() } } +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + export_lines.flush(out, m_result, out_path); +#else if (!export_line.empty()) write_string(export_line); +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE out.close(); in.close(); +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + export_lines.synchronize_moves(m_result); +#else // updates moves' gcode ids which have been modified by the insertion of the M73 lines unsigned int curr_offset_id = 0; unsigned int total_offset = 0; @@ -3758,6 +4120,7 @@ void GCodeProcessor::post_process() } move.gcode_id += total_offset; } +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE if (rename_file(out_path, m_result.filename)) throw Slic3r::RuntimeError(std::string("Failed to rename the output G-code file from ") + out_path + " to " + m_result.filename + '\n' + diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index 05656c7fd..c63e095ee 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -125,6 +125,9 @@ namespace Slic3r { float max_print_height; SettingsIds settings_ids; size_t extruders_count; +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + bool backtrace_enabled; +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE std::vector extruder_colors; std::vector filament_diameters; std::vector filament_densities; diff --git a/src/libslic3r/GCodeReader.hpp b/src/libslic3r/GCodeReader.hpp index 25ba6ee0b..d8bc99bf9 100644 --- a/src/libslic3r/GCodeReader.hpp +++ b/src/libslic3r/GCodeReader.hpp @@ -71,6 +71,18 @@ public: return strncmp(cmd, cmd_test, len) == 0 && GCodeReader::is_end_of_word(cmd[len]); } +#if ENABLE_GCODE_POSTPROCESS_BACKTRACE + static bool cmd_starts_with(const std::string& gcode_line, const char* cmd_test) { + return strncmp(GCodeReader::skip_whitespaces(gcode_line.c_str()), cmd_test, strlen(cmd_test)) == 0; + } + + static std::string extract_cmd(const std::string& gcode_line) { + GCodeLine temp; + temp.m_raw = gcode_line; + return temp.cmd().data(); + } +#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE + private: std::string m_raw; float m_axis[NUM_AXES]; diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 60d89c9e9..c33f24311 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -58,6 +58,8 @@ // Enable alternative version of file_wildcards() #define ENABLE_ALTERNATIVE_FILE_WILDCARDS_GENERATOR (1 && ENABLE_2_6_0_ALPHA1) +// Enable gcode postprocess modified to allow for backward insertion of new lines +#define ENABLE_GCODE_POSTPROCESS_BACKTRACE (1 && ENABLE_2_6_0_ALPHA1) #endif // _prusaslicer_technologies_h_