diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 6f99ff55f4..b2ab4d2943 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -404,359 +404,6 @@ void GCodeProcessor::TimeProcessor::reset() machines[static_cast(PrintEstimatedStatistics::ETimeMode::Normal)].enabled = true; } -void GCodeProcessor::TimeProcessor::post_process(const std::string& filename, std::vector& moves, std::vector& lines_ends, size_t total_layer_num) -{ - FilePtr in{ boost::nowide::fopen(filename.c_str(), "rb") }; - if (in.f == nullptr) - throw Slic3r::RuntimeError(std::string("Time estimator post process export failed.\nCannot open file for reading.\n")); - - const bool disable_m73 = this->disable_m73; - - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": before process %1%")%filename.c_str(); - // temporary file to contain modified gcode - std::string out_path = filename + ".postprocess"; - FilePtr out{ boost::nowide::fopen(out_path.c_str(), "wb") }; - if (out.f == nullptr) { - throw Slic3r::RuntimeError(std::string("Time estimator post process export failed.\nCannot open file for writing.\n")); - } - - auto time_in_minutes = [](float time_in_seconds) { - assert(time_in_seconds >= 0.f); - return int((time_in_seconds + 0.5f) / 60.0f); - }; - - auto time_in_last_minute = [](float time_in_seconds) { - assert(time_in_seconds <= 60.0f); - return time_in_seconds / 60.0f; - }; - - auto format_line_M73_main = [](const std::string& mask, int percent, int time) { - char line_M73[64]; - sprintf(line_M73, mask.c_str(), - std::to_string(percent).c_str(), - std::to_string(time).c_str()); - return std::string(line_M73); - }; - - auto format_line_M73_stop_int = [](const std::string& mask, int time) { - char line_M73[64]; - sprintf(line_M73, mask.c_str(), std::to_string(time).c_str()); - return std::string(line_M73); - }; - - auto format_line_exhaust_fan_control = [](const std::string& mask,int fan_index,int percent) { - char line_fan[64] = { 0 }; - sprintf(line_fan,mask.c_str(), - std::to_string(fan_index).c_str(), - std::to_string(int((percent/100.0)*255)).c_str()); - return std::string(line_fan); - }; - - auto format_time_float = [](float time) { - return Slic3r::float_to_string_decimal_point(time, 2); - }; - - auto format_line_M73_stop_float = [format_time_float](const std::string& mask, float time) { - char line_M73[64]; - sprintf(line_M73, mask.c_str(), format_time_float(time).c_str()); - return std::string(line_M73); - }; - - std::string gcode_line; - size_t g1_lines_counter = 0; - // keeps track of last exported pair - std::array, static_cast(PrintEstimatedStatistics::ETimeMode::Count)> last_exported_main; - for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { - last_exported_main[i] = { 0, time_in_minutes(machines[i].time) }; - } - - // keeps track of last exported remaining time to next printer stop - std::array(PrintEstimatedStatistics::ETimeMode::Count)> last_exported_stop; - for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { - last_exported_stop[i] = time_in_minutes(machines[i].time); - } - - // buffer line to export only when greater than 64K to reduce writing calls - std::string export_line; - - // 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) { - int extra_lines_count = 0; - - // remove trailing '\n' - auto line = std::string_view(gcode_line).substr(0, gcode_line.length() - 1); - - std::string ret; - if (line.length() > 1) { - line = line.substr(1); - if (line == reserved_tag(ETags::First_Line_M73_Placeholder) || line == reserved_tag(ETags::Last_Line_M73_Placeholder)) { - if (disable_m73) { - // Remove current line - gcode_line = ""; - return std::tuple(true, -1); - } - - for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { - const TimeMachine& machine = machines[i]; - if (machine.enabled) { - // export pair - 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; - - // 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); - 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; - } - } - } - } - else if (line == reserved_tag(ETags::Estimated_Printing_Time_Placeholder)) { - for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { - const TimeMachine& machine = machines[i]; - PrintEstimatedStatistics::ETimeMode mode = static_cast(i); - if (mode == PrintEstimatedStatistics::ETimeMode::Normal || machine.enabled) { - char buf[128]; - if(!s_IsBBLPrinter) - // SoftFever: compatibility with klipper_estimator - sprintf(buf, "; estimated printing time (normal mode) = %s\n", get_time_dhms(machine.time).c_str()); - else { - //sprintf(buf, "; estimated printing time (%s mode) = %s\n", - // (mode == PrintEstimatedStatistics::ETimeMode::Normal) ? "normal" : "silent", - // get_time_dhms(machine.time).c_str()); - sprintf(buf, "; model printing time: %s; total estimated time: %s\n", - get_time_dhms(machine.time - machine.prepare_time).c_str(), - get_time_dhms(machine.time).c_str()); - } - ret += buf; - } - } - } - //BBS: write total layer number - else if (line == reserved_tag(ETags::Total_Layer_Number_Placeholder)) { - char buf[128]; - sprintf(buf, "; total layer number: %zd\n", total_layer_num); - ret += buf; - } - } - - 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); - }; - - // check for temporary lines - auto is_temporary_decoration = [](const std::string_view gcode_line) { - // remove trailing '\n' - assert(! gcode_line.empty()); - assert(gcode_line.back() == '\n'); - - // return true for decorations which are used in processing the gcode but that should not be exported into the final gcode - // i.e.: - // bool ret = gcode_line.substr(0, gcode_line.length() - 1) == ";" + Layer_Change_Tag; - // ... - // return ret; - return false; - }; - - // Iterators for the normal and silent cached time estimate entry recently processed, used by process_line_G1. - auto g1_times_cache_it = Slic3r::reserve_vector::const_iterator>(machines.size()); - for (const auto& machine : machines) - g1_times_cache_it.emplace_back(machine.g1_times_cache.begin()); - - // add lines M73 to exported gcode - auto process_line_move = [ - // Lambdas, mostly for string formatting, all with an empty capture block. - time_in_minutes, format_time_float, format_line_M73_main, format_line_M73_stop_int, format_line_M73_stop_float, time_in_last_minute,format_line_exhaust_fan_control, - &self = std::as_const(*this), - // Caches, to be modified - &g1_times_cache_it, &last_exported_main, &last_exported_stop, - // String output - &export_line] - (const size_t g1_lines_counter) { - unsigned int exported_lines_count = 0; - for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { - const TimeMachine& machine = self.machines[i]; - if (machine.enabled) { - // export pair - // Skip all machine.g1_times_cache below g1_lines_counter. - auto& it = g1_times_cache_it[i]; - while (it != machine.g1_times_cache.end() && it->id < g1_lines_counter) - ++it; - if (it != machine.g1_times_cache.end() && it->id == g1_lines_counter) { - 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) { - export_line += format_line_M73_main(machine.line_m73_main_mask.c_str(), - to_export_main.first, to_export_main.second); - last_exported_main[i] = to_export_main; - ++exported_lines_count; - } - // export remaining time to next printer stop - auto it_stop = std::upper_bound(machine.stop_times.begin(), machine.stop_times.end(), it->elapsed_time, - [](float value, const TimeMachine::StopTime& t) { return value < t.elapsed_time; }); - if (it_stop != machine.stop_times.end()) { - int to_export_stop = time_in_minutes(it_stop->elapsed_time - it->elapsed_time); - if (last_exported_stop[i] != to_export_stop) { - if (to_export_stop > 0) { - if (last_exported_stop[i] != to_export_stop) { - export_line += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop); - last_exported_stop[i] = to_export_stop; - ++exported_lines_count; - } - } - else { - bool is_last = false; - auto next_it = it + 1; - is_last |= (next_it == machine.g1_times_cache.end()); - - if (next_it != machine.g1_times_cache.end()) { - auto next_it_stop = std::upper_bound(machine.stop_times.begin(), machine.stop_times.end(), next_it->elapsed_time, - [](float value, const TimeMachine::StopTime& t) { return value < t.elapsed_time; }); - is_last |= (next_it_stop != it_stop); - - std::string time_float_str = format_time_float(time_in_last_minute(it_stop->elapsed_time - it->elapsed_time)); - std::string next_time_float_str = format_time_float(time_in_last_minute(it_stop->elapsed_time - next_it->elapsed_time)); - is_last |= (string_to_double_decimal_point(time_float_str) > 0. && string_to_double_decimal_point(next_time_float_str) == 0.); - } - - if (is_last) { - 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)); - - last_exported_stop[i] = to_export_stop; - ++exported_lines_count; - } - } - } - } - } - } - } - return exported_lines_count; - }; - - // helper function to write to disk - size_t out_file_pos = 0; - lines_ends.clear(); - auto write_string = [&export_line, &out, &out_path, &out_file_pos, &lines_ends](const std::string& str) { - fwrite((const void*)export_line.c_str(), 1, export_line.length(), out.f); - if (ferror(out.f)) { - out.close(); - boost::nowide::remove(out_path.c_str()); - throw Slic3r::RuntimeError(std::string("Time estimator post process export failed.\nIs the disk full?\n")); - } - for (size_t i = 0; i < export_line.size(); ++ i) - if (export_line[i] == '\n') - lines_ends.emplace_back(out_file_pos + i + 1); - out_file_pos += export_line.size(); - export_line.clear(); - }; - - unsigned int line_id = 0; - std::vector> offsets; - - { - // Read the input stream 64kB at a time, extract lines and process them. - std::vector buffer(65536 * 10, 0); - // Line buffer. - assert(gcode_line.empty()); - for (;;) { - size_t cnt_read = ::fread(buffer.data(), 1, buffer.size(), in.f); - if (::ferror(in.f)) - throw Slic3r::RuntimeError(std::string("Time estimator post process export failed.\nError while reading from file.\n")); - bool eof = cnt_read == 0; - auto it = buffer.begin(); - auto it_bufend = buffer.begin() + cnt_read; - while (it != it_bufend || (eof && ! gcode_line.empty())) { - // Find end of line. - bool eol = false; - auto it_end = it; - for (; it_end != it_bufend && ! (eol = *it_end == '\r' || *it_end == '\n'); ++ it_end) ; - // End of line is indicated also if end of file was reached. - eol |= eof && it_end == it_bufend; - gcode_line.insert(gcode_line.end(), it, it_end); - if (eol) { - ++line_id; - - // determine the end of line character and pass to output - gcode_line += *it_end; - if(*it_end == '\r' && *(++ it_end) == '\n') - gcode_line += '\n'; - // replace placeholder lines - auto [processed, lines_added_count] = process_placeholders(gcode_line); - if (processed && lines_added_count != 0) - offsets.push_back({ line_id, lines_added_count }); - - if (!disable_m73 && !processed &&!is_temporary_decoration(gcode_line) && - (GCodeReader::GCodeLine::cmd_is(gcode_line, "G1") || - GCodeReader::GCodeLine::cmd_is(gcode_line, "G2") || - GCodeReader::GCodeLine::cmd_is(gcode_line, "G3") || - GCodeReader::GCodeLine::cmd_is(gcode_line, "G10")|| - GCodeReader::GCodeLine::cmd_is(gcode_line, "G11"))) { - // remove temporary lines, add lines M73 where needed - unsigned int extra_lines_count = process_line_move(g1_lines_counter ++); - if (extra_lines_count > 0) - offsets.push_back({ line_id, extra_lines_count }); - } - - if (disable_m73 && !processed && GCodeReader::GCodeLine::cmd_is(gcode_line, "M73")) { - // Remove any existing M73 command - gcode_line = ""; - offsets.push_back({line_id, -1}); - } - - export_line += gcode_line; - if (export_line.length() > 65535) - write_string(export_line); - gcode_line.clear(); - } - // Skip EOL. - it = it_end; - if (it != it_bufend && *it == '\r') - ++ it; - if (it != it_bufend && *it == '\n') - ++ it; - } - if (eof) - break; - } - } - - if (!export_line.empty()) - write_string(export_line); - - out.close(); - in.close(); - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": after process %1%")%filename.c_str(); - - // 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; - for (GCodeProcessorResult::MoveVertex& move : moves) { - while (curr_offset_id < static_cast(offsets.size()) && offsets[curr_offset_id].first <= move.gcode_id) { - total_offset += offsets[curr_offset_id].second; - ++curr_offset_id; - } - move.gcode_id += total_offset; - } - - if (rename_file(out_path, filename)) { - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": Failed to rename the output G-code file from %1% to %2%")%out_path.c_str() % filename.c_str(); - throw Slic3r::RuntimeError(std::string("Failed to rename the output G-code file from ") + out_path + " to " + filename + '\n' + - "Is " + out_path + " locked?" + '\n'); - } -} - void GCodeProcessor::UsedFilaments::reset() { color_change_cache = 0.0f; @@ -1136,7 +783,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config) DEFAULT_TRAVEL_ACCELERATION; } - m_time_processor.disable_m73 = config.disable_m73; + m_disable_m73 = config.disable_m73; const ConfigOptionFloat* initial_layer_print_height = config.option("initial_layer_print_height"); if (initial_layer_print_height != nullptr) @@ -1694,9 +1341,6 @@ void GCodeProcessor::finalize(bool post_process) m_height_compare.output(); m_width_compare.output(); #endif // ENABLE_GCODE_VIEWER_DATA_CHECKING - if (post_process){ - m_time_processor.post_process(m_result.filename, m_result.moves, m_result.lines_ends, m_layer_id); - } #if ENABLE_GCODE_VIEWER_STATISTICS m_result.time = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - m_start_time).count(); #endif // ENABLE_GCODE_VIEWER_STATISTICS @@ -4411,7 +4055,10 @@ void GCodeProcessor::run_post_process() return time_in_seconds / 60.0f; }; - auto format_line_M73_main = [](const std::string& mask, int percent, int time) { + auto format_line_M73_main = [this](const std::string& mask, int percent, int time) { + if(this->m_disable_m73) + return std::string(""); + char line_M73[64]; sprintf(line_M73, mask.c_str(), std::to_string(percent).c_str(), @@ -4419,7 +4066,9 @@ void GCodeProcessor::run_post_process() return std::string(line_M73); }; - auto format_line_M73_stop_int = [](const std::string& mask, int time) { + auto format_line_M73_stop_int = [this](const std::string& mask, int time) { + if (this->m_disable_m73) + return std::string(""); char line_M73[64]; sprintf(line_M73, mask.c_str(), std::to_string(time).c_str()); return std::string(line_M73); diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index e7b6e6f883..ce8d0e6f07 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -495,15 +495,10 @@ class Print; float filament_unload_times; //Orca: time for tool change float machine_tool_change_time; - bool disable_m73; std::array(PrintEstimatedStatistics::ETimeMode::Count)> machines; void reset(); - - // post process the file with the given filename to add remaining time lines M73 - // and updates moves' gcode ids accordingly - void post_process(const std::string& filename, std::vector& moves, std::vector& lines_ends, size_t total_layer_num); }; struct UsedFilaments // filaments per ColorChange @@ -735,6 +730,7 @@ class Print; bool m_single_extruder_multi_material; float m_preheat_time; int m_preheat_steps; + bool m_disable_m73; #if ENABLE_GCODE_VIEWER_STATISTICS std::chrono::time_point m_start_time; #endif // ENABLE_GCODE_VIEWER_STATISTICS