diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp index 44b6a3d24..97d6ab3ff 100644 --- a/src/libslic3r/GCodeTimeEstimator.cpp +++ b/src/libslic3r/GCodeTimeEstimator.cpp @@ -207,11 +207,8 @@ namespace Slic3r { { PROFILE_FUNC(); if (start_from_beginning) - { _reset_time(); - m_last_st_synchronized_block_id = -1; - } - _calculate_time(); + _calculate_time(0); if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f)) m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache }); @@ -221,6 +218,7 @@ namespace Slic3r { #endif // ENABLE_MOVE_STATS } +#if 0 void GCodeTimeEstimator::calculate_time_from_text(const std::string& gcode) { reset(); @@ -229,7 +227,7 @@ namespace Slic3r { [this](GCodeReader &reader, const GCodeReader::GCodeLine &line) { this->_process_gcode_line(reader, line); }); - _calculate_time(); + _calculate_time(0); if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f)) m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache }); @@ -244,7 +242,7 @@ namespace Slic3r { reset(); m_parser.parse_file(file, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2)); - _calculate_time(); + _calculate_time(0); if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f)) m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache }); @@ -262,7 +260,7 @@ namespace Slic3r { { this->_process_gcode_line(reader, line); }; for (const std::string& line : gcode_lines) m_parser.parse_line(line, action); - _calculate_time(); + _calculate_time(0); if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f)) m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache}); @@ -271,6 +269,7 @@ namespace Slic3r { _log_moves_stats(); #endif // ENABLE_MOVE_STATS } +#endif bool GCodeTimeEstimator::post_process(const std::string& filename, float interval_sec, const PostProcessData* const normal_mode, const PostProcessData* const silent_mode) { @@ -317,25 +316,25 @@ namespace Slic3r { if (data == nullptr) return; - assert((g1_line_id >= (int)data->g1_line_ids.size()) || (data->g1_line_ids[g1_line_id].first >= g1_lines_count)); - const Block* block = nullptr; - if (g1_line_id < (int)data->g1_line_ids.size()) + assert((g1_line_id >= (int)data->g1_times.size()) || (data->g1_times[g1_line_id].first >= (int)g1_lines_count)); + float elapsed_time = -1.0f; + if (g1_line_id < (int)data->g1_times.size()) { - const G1LineIdToBlockId& map_item = data->g1_line_ids[g1_line_id]; + const G1LineIdTime& map_item = data->g1_times[g1_line_id]; if (map_item.first == g1_lines_count) { - if (line.has_e() && (map_item.second < (unsigned int)data->blocks.size())) - block = &data->blocks[map_item.second]; + if (line.has_e()) + elapsed_time = map_item.second; ++g1_line_id; } } - if ((block != nullptr) && (block->elapsed_time != -1.0f)) + if (elapsed_time != -1.0f) { - float block_remaining_time = data->time - block->elapsed_time; + float block_remaining_time = data->time - elapsed_time; if (std::abs(last_recorded_time - block_remaining_time) > interval_sec) { - sprintf(line_M73, time_mask.c_str(), std::to_string((int)(100.0f * block->elapsed_time / data->time)).c_str(), _get_time_minutes(block_remaining_time).c_str()); + sprintf(line_M73, time_mask.c_str(), std::to_string((int)(100.0f * elapsed_time / data->time)).c_str(), _get_time_minutes(block_remaining_time).c_str()); gcode_line += line_M73; last_recorded_time = block_remaining_time; @@ -643,22 +642,6 @@ namespace Slic3r { m_state.extruder_id = m_state.extruder_id_unloaded; } - void GCodeTimeEstimator::add_additional_time(float timeSec) - { - PROFILE_FUNC(); - m_state.additional_time += timeSec; - } - - void GCodeTimeEstimator::set_additional_time(float timeSec) - { - m_state.additional_time = timeSec; - } - - float GCodeTimeEstimator::get_additional_time() const - { - return m_state.additional_time; - } - void GCodeTimeEstimator::set_default() { set_units(Millimeters); @@ -788,7 +771,7 @@ namespace Slic3r { { size_t out = sizeof(*this); out += SLIC3R_STDVEC_MEMSIZE(this->m_blocks, Block); - out += SLIC3R_STDVEC_MEMSIZE(this->m_g1_line_ids, G1LineIdToBlockId); + out += SLIC3R_STDVEC_MEMSIZE(this->m_g1_times, G1LineIdTime); return out; } @@ -807,13 +790,9 @@ namespace Slic3r { if (get_e_local_positioning_type() == Absolute) set_axis_position(E, 0.0f); - set_additional_time(0.0f); - reset_extruder_id(); reset_g1_line_id(); - m_g1_line_ids.clear(); - - m_last_st_synchronized_block_id = -1; + m_g1_times.clear(); m_needs_custom_gcode_times = false; m_custom_gcode_times.clear(); @@ -830,17 +809,19 @@ namespace Slic3r { m_blocks.clear(); } - void GCodeTimeEstimator::_calculate_time() + void GCodeTimeEstimator::_calculate_time(size_t keep_last_n_blocks) { PROFILE_FUNC(); + + assert(keep_last_n_blocks <= m_blocks.size()); + _forward_pass(); _reverse_pass(); _recalculate_trapezoids(); - m_time += get_additional_time(); - m_custom_gcode_time_cache += get_additional_time(); - - for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size(); ++i) + size_t n_blocks_process = m_blocks.size() - keep_last_n_blocks; + m_g1_times.reserve(m_g1_times.size() + n_blocks_process); + for (size_t i = 0; i < n_blocks_process; ++ i) { Block& block = m_blocks[i]; float block_time = 0.0f; @@ -848,7 +829,8 @@ namespace Slic3r { block_time += block.cruise_time(); block_time += block.deceleration_time(); m_time += block_time; - block.elapsed_time = m_time; + if (block.g1_line_id >= 0) + m_g1_times.emplace_back(block.g1_line_id, m_time); #if ENABLE_MOVE_STATS MovesStatsMap::iterator it = _moves_stats.find(block.move_type); @@ -862,9 +844,10 @@ namespace Slic3r { m_custom_gcode_time_cache += block_time; } - m_last_st_synchronized_block_id = (int)m_blocks.size() - 1; - // The additional time has been consumed (added to the total time), reset it to zero. - set_additional_time(0.); + if (keep_last_n_blocks) + m_blocks.erase(m_blocks.begin(), m_blocks.begin() + n_blocks_process); + else + m_blocks.clear(); } void GCodeTimeEstimator::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line) @@ -1208,8 +1191,11 @@ namespace Slic3r { #endif // ENABLE_MOVE_STATS // adds block to blocks list + block.g1_line_id = this->get_g1_line_id(); m_blocks.emplace_back(block); - m_g1_line_ids.emplace_back(G1LineIdToBlockIdMap::value_type(get_g1_line_id(), (unsigned int)m_blocks.size() - 1)); + + if (m_blocks.size() > planner_refresh_if_larger) + _calculate_time(planner_queue_size); } void GCodeTimeEstimator::_processG4(const GCodeReader::GCodeLine& line) @@ -1218,8 +1204,9 @@ namespace Slic3r { GCodeFlavor dialect = get_dialect(); float value; + float extra_time = 0.f; if (line.has_value('P', value)) - add_additional_time(value * MILLISEC_TO_SEC); + extra_time += value * MILLISEC_TO_SEC; // see: http://reprap.org/wiki/G-code#G4:_Dwell if ((dialect == gcfRepetier) || @@ -1228,10 +1215,10 @@ namespace Slic3r { (dialect == gcfRepRap)) { if (line.has_value('S', value)) - add_additional_time(value); + extra_time += value; } - _simulate_st_synchronize(); + _simulate_st_synchronize(extra_time); } void GCodeTimeEstimator::_processG20(const GCodeReader::GCodeLine& line) @@ -1296,7 +1283,7 @@ namespace Slic3r { anyFound = true; } else - _simulate_st_synchronize(); + _simulate_st_synchronize(0.f); if (!anyFound) { @@ -1310,7 +1297,7 @@ namespace Slic3r { void GCodeTimeEstimator::_processM1(const GCodeReader::GCodeLine& line) { PROFILE_FUNC(); - _simulate_st_synchronize(); + _simulate_st_synchronize(0.f); } void GCodeTimeEstimator::_processM82(const GCodeReader::GCodeLine& line) @@ -1462,9 +1449,9 @@ namespace Slic3r { // MK3 MMU2 specific M code: // M702 C is expected to be sent by the custom end G-code when finalizing a print. // The MK3 unit shall unload and park the active filament into the MMU2 unit. - add_additional_time(get_filament_unload_time(get_extruder_id())); + float extra_time = get_filament_unload_time(get_extruder_id()); reset_extruder_id(); - _simulate_st_synchronize(); + _simulate_st_synchronize(extra_time); } } @@ -1478,10 +1465,10 @@ namespace Slic3r { { // Specific to the MK3 MMU2: The initial extruder ID is set to -1 indicating // that the filament is parked in the MMU2 unit and there is nothing to be unloaded yet. - add_additional_time(get_filament_unload_time(get_extruder_id())); + float extra_time = get_filament_unload_time(get_extruder_id()); set_extruder_id(id); - add_additional_time(get_filament_load_time(get_extruder_id())); - _simulate_st_synchronize(); + extra_time += get_filament_load_time(get_extruder_id()); + _simulate_st_synchronize(extra_time); } } } @@ -1513,7 +1500,9 @@ namespace Slic3r { { PROFILE_FUNC(); m_needs_custom_gcode_times = true; - _calculate_time(); + //FIXME this simulates st_synchronize! is it correct? + // The estimated time may be longer than the real print time. + _simulate_st_synchronize(0.f); if (m_custom_gcode_time_cache != 0.0f) { m_custom_gcode_times.push_back({code, m_custom_gcode_time_cache}); @@ -1521,34 +1510,26 @@ namespace Slic3r { } } - void GCodeTimeEstimator::_simulate_st_synchronize() + void GCodeTimeEstimator::_simulate_st_synchronize(float extra_time) { PROFILE_FUNC(); - _calculate_time(); + m_time += extra_time; + m_custom_gcode_time_cache += extra_time; + _calculate_time(0); } void GCodeTimeEstimator::_forward_pass() { PROFILE_FUNC(); - if (m_blocks.size() > 1) - { - for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size() - 1; ++i) - { - _planner_forward_pass_kernel(m_blocks[i], m_blocks[i + 1]); - } - } + for (int i = 0; i + 1 < (int)m_blocks.size(); ++i) + _planner_forward_pass_kernel(m_blocks[i], m_blocks[i + 1]); } void GCodeTimeEstimator::_reverse_pass() { PROFILE_FUNC(); - if (m_blocks.size() > 1) - { - for (int i = (int)m_blocks.size() - 1; i >= m_last_st_synchronized_block_id + 2; --i) - { - _planner_reverse_pass_kernel(m_blocks[i - 1], m_blocks[i]); - } - } + for (int i = (int)m_blocks.size() - 1; i > 0; -- i) + _planner_reverse_pass_kernel(m_blocks[i - 1], m_blocks[i]); } void GCodeTimeEstimator::_planner_forward_pass_kernel(Block& prev, Block& curr) @@ -1598,7 +1579,7 @@ namespace Slic3r { Block* curr = nullptr; Block* next = nullptr; - for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size(); ++i) + for (size_t i = 0; i < m_blocks.size(); ++ i) { Block& b = m_blocks[i]; @@ -1657,7 +1638,7 @@ namespace Slic3r { { char buffer[64]; - int minutes = std::round(time_in_secs / 60.); + int minutes = int(std::round(time_in_secs / 60.)); if (minutes <= 0) { ::sprintf(buffer, "%ds", (int)time_in_secs); } else { diff --git a/src/libslic3r/GCodeTimeEstimator.hpp b/src/libslic3r/GCodeTimeEstimator.hpp index 7c364d9eb..0448fdcbe 100644 --- a/src/libslic3r/GCodeTimeEstimator.hpp +++ b/src/libslic3r/GCodeTimeEstimator.hpp @@ -85,7 +85,6 @@ namespace Slic3r { // hard limit for the acceleration, to which the firmware will clamp. float max_acceleration; // mm/s^2 float retract_acceleration; // mm/s^2 - float additional_time; // s float minimum_feedrate; // mm/s float minimum_travel_feedrate; // mm/s float extrude_factor_override_percentage; @@ -160,7 +159,9 @@ namespace Slic3r { FeedrateProfile feedrate; Trapezoid trapezoid; - float elapsed_time; + + // Ordnary index of this G1 line in the file. + int g1_line_id { -1 }; Block(); @@ -217,16 +218,13 @@ namespace Slic3r { #endif // ENABLE_MOVE_STATS public: - typedef std::pair G1LineIdToBlockId; - typedef std::vector G1LineIdToBlockIdMap; + typedef std::pair G1LineIdTime; + typedef std::vector G1LineIdsTimes; struct PostProcessData { - const G1LineIdToBlockIdMap& g1_line_ids; - const BlocksList& blocks; + const G1LineIdsTimes& g1_times; float time; - - PostProcessData(const G1LineIdToBlockIdMap& g1_line_ids, const BlocksList& blocks, float time) : g1_line_ids(g1_line_ids), blocks(blocks), time(time) {} }; private: @@ -236,10 +234,14 @@ namespace Slic3r { Feedrates m_curr; Feedrates m_prev; BlocksList m_blocks; - // Map between g1 line id and blocks id, used to speed up export of remaining times - G1LineIdToBlockIdMap m_g1_line_ids; - // Index of the last block already st_synchronized - int m_last_st_synchronized_block_id; + // Size of the firmware planner queue. The old 8-bit Marlins usually just managed 16 trapezoidal blocks. + // Let's be conservative and plan for newer boards with more memory. + static constexpr size_t planner_queue_size = 64; + // The firmware recalculates last planner_queue_size trapezoidal blocks each time a new block is added. + // We are not simulating the firmware exactly, we calculate a sequence of blocks once a reasonable number of blocks accumulate. + static constexpr size_t planner_refresh_if_larger = planner_queue_size * 4; + // Map from g1 line id to its elapsed time from the start of the print. + G1LineIdsTimes m_g1_times; float m_time; // s // data to calculate custom code times @@ -267,13 +269,13 @@ namespace Slic3r { void calculate_time(bool start_from_beginning); // Calculates the time estimate from the given gcode in string format - void calculate_time_from_text(const std::string& gcode); + //void calculate_time_from_text(const std::string& gcode); // Calculates the time estimate from the gcode contained in the file with the given filename - void calculate_time_from_file(const std::string& file); + //void calculate_time_from_file(const std::string& file); // Calculates the time estimate from the gcode contained in given list of gcode lines - void calculate_time_from_lines(const std::vector& gcode_lines); + //void calculate_time_from_lines(const std::vector& gcode_lines); // Process the gcode contained in the file with the given filename, // replacing placeholders with correspondent new lines M73 @@ -350,10 +352,6 @@ namespace Slic3r { unsigned int get_extruder_id() const; void reset_extruder_id(); - void add_additional_time(float timeSec); - void set_additional_time(float timeSec); - float get_additional_time() const; - void set_default(); // Call this method before to start adding lines using add_gcode_line() when reusing an instance of GCodeTimeEstimator @@ -389,7 +387,7 @@ namespace Slic3r { // Return an estimate of the memory consumed by the time estimator. size_t memory_used() const; - PostProcessData get_post_process_data() const { return PostProcessData(m_g1_line_ids, m_blocks, m_time); } + PostProcessData get_post_process_data() const { return PostProcessData{ m_g1_times, m_time }; } private: void _reset(); @@ -397,7 +395,7 @@ namespace Slic3r { void _reset_blocks(); // Calculates the time estimate - void _calculate_time(); + void _calculate_time(size_t keep_last_n_blocks); // Processes the given gcode line void _process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line); @@ -470,7 +468,7 @@ namespace Slic3r { void _process_custom_gcode_tag(CustomGcodeType code); // Simulates firmware st_synchronize() call - void _simulate_st_synchronize(); + void _simulate_st_synchronize(float additional_time); void _forward_pass(); void _reverse_pass();