diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 8d4a1a269..911c07cbf 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -472,7 +472,8 @@ sub new { fil_mm3 => L("Used Filament (mm³)"), fil_g => L("Used Filament (g)"), cost => L("Cost"), - time => L("Estimated printing time"), + default_time => L("Estimated printing time (default mode)"), + silent_time => L("Estimated printing time (silent mode)"), ); while (my $field = shift @info) { my $label = shift @info; @@ -1542,7 +1543,8 @@ sub on_export_completed { $self->{"print_info_cost"}->SetLabel(sprintf("%.2f" , $self->{print}->total_cost)); $self->{"print_info_fil_g"}->SetLabel(sprintf("%.2f" , $self->{print}->total_weight)); $self->{"print_info_fil_mm3"}->SetLabel(sprintf("%.2f" , $self->{print}->total_extruded_volume)); - $self->{"print_info_time"}->SetLabel($self->{print}->estimated_print_time); + $self->{"print_info_default_time"}->SetLabel($self->{print}->estimated_default_print_time); + $self->{"print_info_silent_time"}->SetLabel($self->{print}->estimated_silent_print_time); $self->{"print_info_fil_m"}->SetLabel(sprintf("%.2f" , $self->{print}->total_used_filament / 1000)); $self->{"print_info_box_show"}->(1); diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index b581b3e76..28c15e2fd 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -374,6 +374,9 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_ throw std::runtime_error(std::string("G-code export to ") + path + " failed\nIs the disk full?\n"); } fclose(file); + + GCodeTimeEstimator::post_process_elapsed_times(path_tmp, m_default_time_estimator.get_time(), m_silent_time_estimator.get_time()); + if (! this->m_placeholder_parser_failed_templates.empty()) { // G-code export proceeded, but some of the PlaceholderParser substitutions failed. std::string msg = std::string("G-code export to ") + path + " failed due to invalid custom G-code sections:\n\n"; @@ -403,9 +406,11 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) { PROFILE_FUNC(); - // resets time estimator - m_time_estimator.reset(); - m_time_estimator.set_dialect(print.config.gcode_flavor); + // resets time estimators + m_default_time_estimator.reset(); + m_default_time_estimator.set_dialect(print.config.gcode_flavor); + m_silent_time_estimator.reset(); + m_silent_time_estimator.set_dialect(print.config.gcode_flavor); // resets analyzer m_analyzer.reset(); @@ -596,6 +601,10 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) _writeln(file, buf); } + // before start gcode time estimation + _write(file, m_default_time_estimator.get_elapsed_time_string().c_str()); + _write(file, m_silent_time_estimator.get_elapsed_time_string().c_str()); + // Write the custom start G-code _writeln(file, start_gcode); // Process filament-specific gcode in extruder order. @@ -800,13 +809,17 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) for (const std::string &end_gcode : print.config.end_filament_gcode.values) _writeln(file, this->placeholder_parser_process("end_filament_gcode", end_gcode, (unsigned int)(&end_gcode - &print.config.end_filament_gcode.values.front()), &config)); } + // before end gcode time estimation + _write(file, m_default_time_estimator.get_elapsed_time_string().c_str()); + _write(file, m_silent_time_estimator.get_elapsed_time_string().c_str()); _writeln(file, this->placeholder_parser_process("end_gcode", print.config.end_gcode, m_writer.extruder()->id(), &config)); } _write(file, m_writer.update_progress(m_layer_count, m_layer_count, true)); // 100% _write(file, m_writer.postamble()); // calculates estimated printing time - m_time_estimator.calculate_time(); + m_default_time_estimator.calculate_time(); + m_silent_time_estimator.calculate_time(); // Get filament stats. print.filament_stats.clear(); @@ -814,7 +827,8 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) print.total_extruded_volume = 0.; print.total_weight = 0.; print.total_cost = 0.; - print.estimated_print_time = m_time_estimator.get_time_hms(); + print.estimated_default_print_time = m_default_time_estimator.get_time_dhms(); + print.estimated_silent_print_time = m_silent_time_estimator.get_time_dhms(); for (const Extruder &extruder : m_writer.extruders()) { double used_filament = extruder.used_filament(); double extruded_volume = extruder.extruded_volume(); @@ -834,7 +848,8 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) print.total_extruded_volume = print.total_extruded_volume + extruded_volume; } _write_format(file, "; total filament cost = %.1lf\n", print.total_cost); - _write_format(file, "; estimated printing time = %s\n", m_time_estimator.get_time_hms().c_str()); + _write_format(file, "; estimated printing time (default mode) = %s\n", m_default_time_estimator.get_time_dhms().c_str()); + _write_format(file, "; estimated printing time (silent mode) = %s\n", m_silent_time_estimator.get_time_dhms().c_str()); // Append full config. _write(file, "\n"); @@ -1399,8 +1414,12 @@ void GCode::process_layer( if (m_pressure_equalizer) gcode = m_pressure_equalizer->process(gcode.c_str(), false); // printf("G-code after filter:\n%s\n", out.c_str()); - + _write(file, gcode); + + // after layer time estimation + _write(file, m_default_time_estimator.get_elapsed_time_string().c_str()); + _write(file, m_silent_time_estimator.get_elapsed_time_string().c_str()); } void GCode::apply_print_config(const PrintConfig &print_config) @@ -2059,7 +2078,8 @@ void GCode::_write(FILE* file, const char *what) // writes string to file fwrite(gcode, 1, ::strlen(gcode), file); // updates time estimator and gcode lines vector - m_time_estimator.add_gcode_block(gcode); + m_default_time_estimator.add_gcode_block(gcode); + m_silent_time_estimator.add_gcode_block(gcode); } } diff --git a/xs/src/libslic3r/GCode.hpp b/xs/src/libslic3r/GCode.hpp index d028e90aa..b938604ef 100644 --- a/xs/src/libslic3r/GCode.hpp +++ b/xs/src/libslic3r/GCode.hpp @@ -133,6 +133,8 @@ public: m_last_height(GCodeAnalyzer::Default_Height), m_brim_done(false), m_second_layer_things_done(false), + m_default_time_estimator(GCodeTimeEstimator::Default), + m_silent_time_estimator(GCodeTimeEstimator::Silent), m_last_obj_copy(nullptr, Point(std::numeric_limits::max(), std::numeric_limits::max())) {} ~GCode() {} @@ -289,8 +291,9 @@ protected: // Index of a last object copy extruded. std::pair m_last_obj_copy; - // Time estimator - GCodeTimeEstimator m_time_estimator; + // Time estimators + GCodeTimeEstimator m_default_time_estimator; + GCodeTimeEstimator m_silent_time_estimator; // Analyzer GCodeAnalyzer m_analyzer; diff --git a/xs/src/libslic3r/GCodeTimeEstimator.cpp b/xs/src/libslic3r/GCodeTimeEstimator.cpp index 176159ff5..553ddba08 100644 --- a/xs/src/libslic3r/GCodeTimeEstimator.cpp +++ b/xs/src/libslic3r/GCodeTimeEstimator.cpp @@ -4,9 +4,14 @@ #include +#include +#include +#include + static const float MMMIN_TO_MMSEC = 1.0f / 60.0f; static const float MILLISEC_TO_SEC = 0.001f; static const float INCHES_TO_MM = 25.4f; + static const float DEFAULT_FEEDRATE = 1500.0f; // from Prusa Firmware (Marlin_main.cpp) static const float DEFAULT_ACCELERATION = 1500.0f; // Prusa Firmware 1_75mm_MK2 static const float DEFAULT_RETRACT_ACCELERATION = 1500.0f; // Prusa Firmware 1_75mm_MK2 @@ -17,8 +22,31 @@ static const float DEFAULT_MINIMUM_FEEDRATE = 0.0f; // from Prusa Firmware (Conf static const float DEFAULT_MINIMUM_TRAVEL_FEEDRATE = 0.0f; // from Prusa Firmware (Configuration_adv.h) static const float DEFAULT_EXTRUDE_FACTOR_OVERRIDE_PERCENTAGE = 1.0f; // 100 percent +static const float SILENT_FEEDRATE = 1500.0f; // from Prusa Firmware (Marlin_main.cpp) +static const float SILENT_ACCELERATION = 1250.0f; // Prusa Firmware 1_75mm_MK25-RAMBo13a-E3Dv6full +static const float SILENT_RETRACT_ACCELERATION = 1250.0f; // Prusa Firmware 1_75mm_MK25-RAMBo13a-E3Dv6full +static const float SILENT_AXIS_MAX_FEEDRATE[] = { 200.0f, 200.0f, 12.0f, 120.0f }; // Prusa Firmware 1_75mm_MK25-RAMBo13a-E3Dv6full +static const float SILENT_AXIS_MAX_ACCELERATION[] = { 1000.0f, 1000.0f, 200.0f, 5000.0f }; // Prusa Firmware 1_75mm_MK25-RAMBo13a-E3Dv6full +static const float SILENT_AXIS_MAX_JERK[] = { 10.0f, 10.0f, 0.4f, 2.5f }; // from Prusa Firmware (Configuration.h) +static const float SILENT_MINIMUM_FEEDRATE = 0.0f; // from Prusa Firmware (Configuration_adv.h) +static const float SILENT_MINIMUM_TRAVEL_FEEDRATE = 0.0f; // from Prusa Firmware (Configuration_adv.h) +static const float SILENT_EXTRUDE_FACTOR_OVERRIDE_PERCENTAGE = 1.0f; // 100 percent + static const float PREVIOUS_FEEDRATE_THRESHOLD = 0.0001f; +static const std::string ELAPSED_TIME_TAG_DEFAULT = ";_ELAPSED_TIME_DEFAULT: "; +static const std::string ELAPSED_TIME_TAG_SILENT = ";_ELAPSED_TIME_SILENT: "; + +#define REMAINING_TIME_USE_SINGLE_GCODE_COMMAND 1 +#if REMAINING_TIME_USE_SINGLE_GCODE_COMMAND +static const std::string REMAINING_TIME_CMD = "M998"; +#else +static const std::string REMAINING_TIME_CMD_DEFAULT = "M998"; +static const std::string REMAINING_TIME_CMD_SILENT = "M999"; +#endif // REMAINING_TIME_USE_SINGLE_GCODE_COMMAND + +static const std::string REMAINING_TIME_COMMENT = " ; estimated remaining time"; + #if ENABLE_MOVE_STATS static const std::string MOVE_TYPE_STR[Slic3r::GCodeTimeEstimator::Block::Num_Types] = { @@ -73,6 +101,11 @@ namespace Slic3r { return ::sqrt(value); } + GCodeTimeEstimator::Block::Block() + : st_synchronized(false) + { + } + float GCodeTimeEstimator::Block::move_length() const { float length = ::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z])); @@ -159,63 +192,13 @@ namespace Slic3r { } #endif // ENABLE_MOVE_STATS - GCodeTimeEstimator::GCodeTimeEstimator() + GCodeTimeEstimator::GCodeTimeEstimator(EMode mode) + : _mode(mode) { reset(); set_default(); } - void GCodeTimeEstimator::calculate_time_from_text(const std::string& gcode) - { - reset(); - - _parser.parse_buffer(gcode, - [this](GCodeReader &reader, const GCodeReader::GCodeLine &line) - { this->_process_gcode_line(reader, line); }); - - _calculate_time(); - -#if ENABLE_MOVE_STATS - _log_moves_stats(); -#endif // ENABLE_MOVE_STATS - - _reset_blocks(); - _reset(); - } - - void GCodeTimeEstimator::calculate_time_from_file(const std::string& file) - { - reset(); - - _parser.parse_file(file, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2)); - _calculate_time(); - -#if ENABLE_MOVE_STATS - _log_moves_stats(); -#endif // ENABLE_MOVE_STATS - - _reset_blocks(); - _reset(); - } - - void GCodeTimeEstimator::calculate_time_from_lines(const std::vector& gcode_lines) - { - reset(); - - auto action = [this](GCodeReader &reader, const GCodeReader::GCodeLine &line) - { this->_process_gcode_line(reader, line); }; - for (const std::string& line : gcode_lines) - _parser.parse_line(line, action); - _calculate_time(); - -#if ENABLE_MOVE_STATS - _log_moves_stats(); -#endif // ENABLE_MOVE_STATS - - _reset_blocks(); - _reset(); - } - void GCodeTimeEstimator::add_gcode_line(const std::string& gcode_line) { PROFILE_FUNC(); @@ -239,14 +222,157 @@ namespace Slic3r { void GCodeTimeEstimator::calculate_time() { PROFILE_FUNC(); + _reset_time(); + _set_blocks_st_synchronize(false); _calculate_time(); #if ENABLE_MOVE_STATS _log_moves_stats(); #endif // ENABLE_MOVE_STATS + } - _reset_blocks(); - _reset(); + void GCodeTimeEstimator::calculate_time_from_text(const std::string& gcode) + { + reset(); + + _parser.parse_buffer(gcode, + [this](GCodeReader &reader, const GCodeReader::GCodeLine &line) + { this->_process_gcode_line(reader, line); }); + + _calculate_time(); + +#if ENABLE_MOVE_STATS + _log_moves_stats(); +#endif // ENABLE_MOVE_STATS + } + + void GCodeTimeEstimator::calculate_time_from_file(const std::string& file) + { + reset(); + + _parser.parse_file(file, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2)); + _calculate_time(); + +#if ENABLE_MOVE_STATS + _log_moves_stats(); +#endif // ENABLE_MOVE_STATS + } + + void GCodeTimeEstimator::calculate_time_from_lines(const std::vector& gcode_lines) + { + reset(); + + auto action = [this](GCodeReader &reader, const GCodeReader::GCodeLine &line) + { this->_process_gcode_line(reader, line); }; + for (const std::string& line : gcode_lines) + _parser.parse_line(line, action); + _calculate_time(); + +#if ENABLE_MOVE_STATS + _log_moves_stats(); +#endif // ENABLE_MOVE_STATS + } + + std::string GCodeTimeEstimator::get_elapsed_time_string() + { + calculate_time(); + switch (_mode) + { + default: + case Default: + return ELAPSED_TIME_TAG_DEFAULT + std::to_string(get_time()) + "\n"; + case Silent: + return ELAPSED_TIME_TAG_SILENT + std::to_string(get_time()) + "\n"; + } + } + + bool GCodeTimeEstimator::post_process_elapsed_times(const std::string& filename, float default_time, float silent_time) + { + boost::nowide::ifstream in(filename); + if (!in.good()) + throw std::runtime_error(std::string("Remaining times estimation failed.\nCannot open file for reading.\n")); + + std::string path_tmp = filename + ".times"; + + FILE* out = boost::nowide::fopen(path_tmp.c_str(), "wb"); + if (out == nullptr) + throw std::runtime_error(std::string("Remaining times estimation failed.\nCannot open file for writing.\n")); + + std::string line; + while (std::getline(in, line)) + { + if (!in.good()) + { + fclose(out); + throw std::runtime_error(std::string("Remaining times estimation failed.\nError while reading from file.\n")); + } + +#if REMAINING_TIME_USE_SINGLE_GCODE_COMMAND + // this function expects elapsed time for default and silent mode to be into two consecutive lines inside the gcode + if (boost::contains(line, ELAPSED_TIME_TAG_DEFAULT)) + { + std::string default_elapsed_time_str = line.substr(ELAPSED_TIME_TAG_DEFAULT.length()); + line = REMAINING_TIME_CMD + " D:" + _get_time_dhms(default_time - (float)atof(default_elapsed_time_str.c_str())); + + std::string next_line; + std::getline(in, next_line); + if (!in.good()) + { + fclose(out); + throw std::runtime_error(std::string("Remaining times estimation failed.\nError while reading from file.\n")); + } + + if (boost::contains(next_line, ELAPSED_TIME_TAG_SILENT)) + { + std::string silent_elapsed_time_str = next_line.substr(ELAPSED_TIME_TAG_SILENT.length()); + line += " S:" + _get_time_dhms(silent_time - (float)atof(silent_elapsed_time_str.c_str())) + REMAINING_TIME_COMMENT; + } + else + // found horphaned default elapsed time, skip the remaining time line output + line = next_line; + } + else if (boost::contains(line, ELAPSED_TIME_TAG_SILENT)) + // found horphaned silent elapsed time, skip the remaining time line output + continue; +#else + bool processed = false; + if (boost::contains(line, ELAPSED_TIME_TAG_DEFAULT)) + { + std::string elapsed_time_str = line.substr(ELAPSED_TIME_TAG_DEFAULT.length()); + line = REMAINING_TIME_CMD_DEFAULT + " " + _get_time_dhms(default_time - (float)atof(elapsed_time_str.c_str())); + processed = true; + } + else if (boost::contains(line, ELAPSED_TIME_TAG_SILENT)) + { + std::string elapsed_time_str = line.substr(ELAPSED_TIME_TAG_SILENT.length()); + line = REMAINING_TIME_CMD_SILENT + " " + _get_time_dhms(silent_time - (float)atof(elapsed_time_str.c_str())); + processed = true; + } + + if (processed) + line += REMAINING_TIME_COMMENT; +#endif // REMAINING_TIME_USE_SINGLE_GCODE_COMMAND + + line += "\n"; + fwrite((const void*)line.c_str(), 1, line.length(), out); + if (ferror(out)) + { + in.close(); + fclose(out); + boost::nowide::remove(path_tmp.c_str()); + throw std::runtime_error(std::string("Remaining times estimation failed.\nIs the disk full?\n")); + } + } + + fclose(out); + in.close(); + + boost::nowide::remove(filename.c_str()); + if (boost::nowide::rename(path_tmp.c_str(), filename.c_str()) != 0) + throw std::runtime_error(std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + filename + '\n' + + "Is " + path_tmp + " locked?" + '\n'); + + return true; } void GCodeTimeEstimator::set_axis_position(EAxis axis, float position) @@ -411,6 +537,66 @@ namespace Slic3r { set_global_positioning_type(Absolute); set_e_local_positioning_type(Absolute); + switch (_mode) + { + default: + case Default: + { + _set_default_as_default(); + break; + } + case Silent: + { + _set_default_as_silent(); + break; + } + } + } + + void GCodeTimeEstimator::reset() + { + _reset_time(); +#if ENABLE_MOVE_STATS + _moves_stats.clear(); +#endif // ENABLE_MOVE_STATS + _reset_blocks(); + _reset(); + } + + float GCodeTimeEstimator::get_time() const + { + return _time; + } + + std::string GCodeTimeEstimator::get_time_dhms() const + { + return _get_time_dhms(get_time()); + } + + void GCodeTimeEstimator::_reset() + { + _curr.reset(); + _prev.reset(); + + set_axis_position(X, 0.0f); + set_axis_position(Y, 0.0f); + set_axis_position(Z, 0.0f); + + set_additional_time(0.0f); + } + + void GCodeTimeEstimator::_reset_time() + { + _time = 0.0f; + } + + void GCodeTimeEstimator::_reset_blocks() + { + _blocks.clear(); + } + + void GCodeTimeEstimator::_set_default_as_default() + { set_feedrate(DEFAULT_FEEDRATE); set_acceleration(DEFAULT_ACCELERATION); set_retract_acceleration(DEFAULT_RETRACT_ACCELERATION); @@ -427,55 +613,30 @@ namespace Slic3r { } } - void GCodeTimeEstimator::reset() + void GCodeTimeEstimator::_set_default_as_silent() { - _time = 0.0f; -#if ENABLE_MOVE_STATS - _moves_stats.clear(); -#endif // ENABLE_MOVE_STATS - _reset_blocks(); - _reset(); + set_feedrate(SILENT_FEEDRATE); + set_acceleration(SILENT_ACCELERATION); + set_retract_acceleration(SILENT_RETRACT_ACCELERATION); + set_minimum_feedrate(SILENT_MINIMUM_FEEDRATE); + set_minimum_travel_feedrate(SILENT_MINIMUM_TRAVEL_FEEDRATE); + set_extrude_factor_override_percentage(SILENT_EXTRUDE_FACTOR_OVERRIDE_PERCENTAGE); + + for (unsigned char a = X; a < Num_Axis; ++a) + { + EAxis axis = (EAxis)a; + set_axis_max_feedrate(axis, SILENT_AXIS_MAX_FEEDRATE[a]); + set_axis_max_acceleration(axis, SILENT_AXIS_MAX_ACCELERATION[a]); + set_axis_max_jerk(axis, SILENT_AXIS_MAX_JERK[a]); + } } - float GCodeTimeEstimator::get_time() const + void GCodeTimeEstimator::_set_blocks_st_synchronize(bool state) { - return _time; - } - - std::string GCodeTimeEstimator::get_time_hms() const - { - float timeinsecs = get_time(); - int hours = (int)(timeinsecs / 3600.0f); - timeinsecs -= (float)hours * 3600.0f; - int minutes = (int)(timeinsecs / 60.0f); - timeinsecs -= (float)minutes * 60.0f; - - char buffer[64]; - if (hours > 0) - ::sprintf(buffer, "%dh %dm %ds", hours, minutes, (int)timeinsecs); - else if (minutes > 0) - ::sprintf(buffer, "%dm %ds", minutes, (int)timeinsecs); - else - ::sprintf(buffer, "%ds", (int)timeinsecs); - - return buffer; - } - - void GCodeTimeEstimator::_reset() - { - _curr.reset(); - _prev.reset(); - - set_axis_position(X, 0.0f); - set_axis_position(Y, 0.0f); - set_axis_position(Z, 0.0f); - - set_additional_time(0.0f); - } - - void GCodeTimeEstimator::_reset_blocks() - { - _blocks.clear(); + for (Block& block : _blocks) + { + block.st_synchronized = state; + } } void GCodeTimeEstimator::_calculate_time() @@ -488,6 +649,9 @@ namespace Slic3r { for (const Block& block : _blocks) { + if (block.st_synchronized) + continue; + #if ENABLE_MOVE_STATS float block_time = 0.0f; block_time += block.acceleration_time(); @@ -1043,7 +1207,7 @@ namespace Slic3r { void GCodeTimeEstimator::_simulate_st_synchronize() { _calculate_time(); - _reset_blocks(); + _set_blocks_st_synchronize(true); } void GCodeTimeEstimator::_forward_pass() @@ -1051,7 +1215,10 @@ namespace Slic3r { if (_blocks.size() > 1) { for (unsigned int i = 0; i < (unsigned int)_blocks.size() - 1; ++i) - { + { + if (_blocks[i].st_synchronized || _blocks[i + 1].st_synchronized) + continue; + _planner_forward_pass_kernel(_blocks[i], _blocks[i + 1]); } } @@ -1063,6 +1230,9 @@ namespace Slic3r { { for (int i = (int)_blocks.size() - 1; i >= 1; --i) { + if (_blocks[i - 1].st_synchronized || _blocks[i].st_synchronized) + continue; + _planner_reverse_pass_kernel(_blocks[i - 1], _blocks[i]); } } @@ -1115,6 +1285,9 @@ namespace Slic3r { for (Block& b : _blocks) { + if (b.st_synchronized) + continue; + curr = next; next = &b; @@ -1144,6 +1317,28 @@ namespace Slic3r { } } + std::string GCodeTimeEstimator::_get_time_dhms(float time_in_secs) + { + int days = (int)(time_in_secs / 86400.0f); + time_in_secs -= (float)days * 86400.0f; + int hours = (int)(time_in_secs / 3600.0f); + time_in_secs -= (float)hours * 3600.0f; + int minutes = (int)(time_in_secs / 60.0f); + time_in_secs -= (float)minutes * 60.0f; + + char buffer[64]; + if (days > 0) + ::sprintf(buffer, "%dd %dh %dm %ds", days, hours, minutes, (int)time_in_secs); + else if (hours > 0) + ::sprintf(buffer, "%dh %dm %ds", hours, minutes, (int)time_in_secs); + else if (minutes > 0) + ::sprintf(buffer, "%dm %ds", minutes, (int)time_in_secs); + else + ::sprintf(buffer, "%ds", (int)time_in_secs); + + return buffer; + } + #if ENABLE_MOVE_STATS void GCodeTimeEstimator::_log_moves_stats() const { diff --git a/xs/src/libslic3r/GCodeTimeEstimator.hpp b/xs/src/libslic3r/GCodeTimeEstimator.hpp index 8f948abd1..c3fe0f04c 100644 --- a/xs/src/libslic3r/GCodeTimeEstimator.hpp +++ b/xs/src/libslic3r/GCodeTimeEstimator.hpp @@ -17,6 +17,12 @@ namespace Slic3r { class GCodeTimeEstimator { public: + enum EMode : unsigned char + { + Default, + Silent + }; + enum EUnits : unsigned char { Millimeters, @@ -135,6 +141,10 @@ namespace Slic3r { FeedrateProfile feedrate; Trapezoid trapezoid; + bool st_synchronized; + + Block(); + // Returns the length of the move covered by this block, in mm float move_length() const; @@ -188,18 +198,29 @@ namespace Slic3r { #endif // ENABLE_MOVE_STATS private: + EMode _mode; GCodeReader _parser; State _state; Feedrates _curr; Feedrates _prev; BlocksList _blocks; float _time; // s + #if ENABLE_MOVE_STATS MovesStatsMap _moves_stats; #endif // ENABLE_MOVE_STATS public: - GCodeTimeEstimator(); + explicit GCodeTimeEstimator(EMode mode); + + // Adds the given gcode line + void add_gcode_line(const std::string& gcode_line); + + void add_gcode_block(const char *ptr); + void add_gcode_block(const std::string &str) { this->add_gcode_block(str.c_str()); } + + // Calculates the time estimate from the gcode lines added using add_gcode_line() or add_gcode_block() + void calculate_time(); // Calculates the time estimate from the given gcode in string format void calculate_time_from_text(const std::string& gcode); @@ -210,14 +231,12 @@ namespace Slic3r { // Calculates the time estimate from the gcode contained in given list of gcode lines void calculate_time_from_lines(const std::vector& gcode_lines); - // Adds the given gcode line - void add_gcode_line(const std::string& gcode_line); + // Calculates the time estimate from the gcode lines added using add_gcode_line() or add_gcode_block() + // and returns it in a formatted string + std::string get_elapsed_time_string(); - void add_gcode_block(const char *ptr); - void add_gcode_block(const std::string &str) { this->add_gcode_block(str.c_str()); } - - // Calculates the time estimate from the gcode lines added using add_gcode_line() - void calculate_time(); + // Converts elapsed time lines, contained in the gcode saved with the given filename, into remaining time commands + static bool post_process_elapsed_times(const std::string& filename, float default_time, float silent_time); // Set current position on the given axis with the given value void set_axis_position(EAxis axis, float position); @@ -275,13 +294,19 @@ namespace Slic3r { // Returns the estimated time, in seconds float get_time() const; - // Returns the estimated time, in format HHh MMm SSs - std::string get_time_hms() const; + // Returns the estimated time, in format DDd HHh MMm SSs + std::string get_time_dhms() const; private: void _reset(); + void _reset_time(); void _reset_blocks(); + void _set_default_as_default(); + void _set_default_as_silent(); + + void _set_blocks_st_synchronize(bool state); + // Calculates the time estimate void _calculate_time(); @@ -353,6 +378,9 @@ namespace Slic3r { void _recalculate_trapezoids(); + // Returns the given time is seconds in format DDd HHh MMm SSs + static std::string _get_time_dhms(float time_in_secs); + #if ENABLE_MOVE_STATS void _log_moves_stats() const; #endif // ENABLE_MOVE_STATS diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index c56e64c6c..c5b0edbdd 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -233,7 +233,8 @@ public: PrintRegionPtrs regions; PlaceholderParser placeholder_parser; // TODO: status_cb - std::string estimated_print_time; + std::string estimated_default_print_time; + std::string estimated_silent_print_time; double total_used_filament, total_extruded_volume, total_cost, total_weight; std::map filament_stats; PrintState state; diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index ef9c5345f..7ccbe0111 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -152,8 +152,10 @@ _constant() %code%{ RETVAL = &THIS->skirt; %}; Ref brim() %code%{ RETVAL = &THIS->brim; %}; - std::string estimated_print_time() - %code%{ RETVAL = THIS->estimated_print_time; %}; + std::string estimated_default_print_time() + %code%{ RETVAL = THIS->estimated_default_print_time; %}; + std::string estimated_silent_print_time() + %code%{ RETVAL = THIS->estimated_silent_print_time; %}; PrintObjectPtrs* objects() %code%{ RETVAL = &THIS->objects; %};