diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index c03431a30..d2e581493 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1057,6 +1057,10 @@ void GCode::_do_export(Print &print, FILE *file) print.m_print_statistics.clear(); print.m_print_statistics.estimated_normal_print_time = m_normal_time_estimator.get_time_dhms(); print.m_print_statistics.estimated_silent_print_time = m_silent_time_estimator_enabled ? m_silent_time_estimator.get_time_dhms() : "N/A"; + print.m_print_statistics.estimated_normal_color_print_times = m_normal_time_estimator.get_color_times_dhms(); + if (m_silent_time_estimator_enabled) + print.m_print_statistics.estimated_silent_color_print_times = m_silent_time_estimator.get_color_times_dhms(); + std::vector<Extruder> extruders = m_writer.extruders(); if (! extruders.empty()) { std::pair<std::string, unsigned int> out_filament_used_mm ("; filament used [mm] = ", 0); diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp index b87305da8..33dc9f4b7 100644 --- a/src/libslic3r/GCodeTimeEstimator.cpp +++ b/src/libslic3r/GCodeTimeEstimator.cpp @@ -174,7 +174,7 @@ namespace Slic3r { const std::string GCodeTimeEstimator::Silent_Last_M73_Output_Placeholder_Tag = "; SILENT_LAST_M73_OUTPUT_PLACEHOLDER"; GCodeTimeEstimator::GCodeTimeEstimator(EMode mode) - : _mode(mode) + : m_mode(mode) { reset(); set_default(); @@ -183,7 +183,7 @@ namespace Slic3r { void GCodeTimeEstimator::add_gcode_line(const std::string& gcode_line) { PROFILE_FUNC(); - _parser.parse_line(gcode_line, + m_parser.parse_line(gcode_line, [this](GCodeReader &reader, const GCodeReader::GCodeLine &line) { this->_process_gcode_line(reader, line); }); } @@ -196,7 +196,7 @@ namespace Slic3r { { this->_process_gcode_line(reader, line); }; for (; *ptr != 0;) { gline.reset(); - ptr = _parser.parse_line(ptr, gline, action); + ptr = m_parser.parse_line(ptr, gline, action); } } @@ -206,10 +206,13 @@ namespace Slic3r { if (start_from_beginning) { _reset_time(); - _last_st_synchronized_block_id = -1; + m_last_st_synchronized_block_id = -1; } _calculate_time(); + if (m_needs_color_times && (m_color_time_cache != 0.0f)) + m_color_times.push_back(m_color_time_cache); + #if ENABLE_MOVE_STATS _log_moves_stats(); #endif // ENABLE_MOVE_STATS @@ -219,12 +222,15 @@ namespace Slic3r { { reset(); - _parser.parse_buffer(gcode, + m_parser.parse_buffer(gcode, [this](GCodeReader &reader, const GCodeReader::GCodeLine &line) { this->_process_gcode_line(reader, line); }); _calculate_time(); + if (m_needs_color_times && (m_color_time_cache != 0.0f)) + m_color_times.push_back(m_color_time_cache); + #if ENABLE_MOVE_STATS _log_moves_stats(); #endif // ENABLE_MOVE_STATS @@ -234,9 +240,12 @@ namespace Slic3r { { reset(); - _parser.parse_file(file, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2)); + m_parser.parse_file(file, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2)); _calculate_time(); + if (m_needs_color_times && (m_color_time_cache != 0.0f)) + m_color_times.push_back(m_color_time_cache); + #if ENABLE_MOVE_STATS _log_moves_stats(); #endif // ENABLE_MOVE_STATS @@ -249,9 +258,12 @@ namespace Slic3r { 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); + m_parser.parse_line(line, action); _calculate_time(); + if (m_needs_color_times && (m_color_time_cache != 0.0f)) + m_color_times.push_back(m_color_time_cache); + #if ENABLE_MOVE_STATS _log_moves_stats(); #endif // ENABLE_MOVE_STATS @@ -270,7 +282,7 @@ namespace Slic3r { throw std::runtime_error(std::string("Remaining times export failed.\nCannot open file for writing.\n")); std::string time_mask; - switch (_mode) + switch (m_mode) { default: case Normal: @@ -291,7 +303,7 @@ namespace Slic3r { // buffer line to export only when greater than 64K to reduce writing calls std::string export_line; char time_line[64]; - G1LineIdToBlockIdMap::const_iterator it_line_id = _g1_line_ids.begin(); + G1LineIdToBlockIdMap::const_iterator it_line_id = m_g1_line_ids.begin(); while (std::getline(in, gcode_line)) { if (!in.good()) @@ -301,15 +313,15 @@ namespace Slic3r { } // replaces placeholders for initial line M73 with the real lines - if (((_mode == Normal) && (gcode_line == Normal_First_M73_Output_Placeholder_Tag)) || - ((_mode == Silent) && (gcode_line == Silent_First_M73_Output_Placeholder_Tag))) + if (((m_mode == Normal) && (gcode_line == Normal_First_M73_Output_Placeholder_Tag)) || + ((m_mode == Silent) && (gcode_line == Silent_First_M73_Output_Placeholder_Tag))) { - sprintf(time_line, time_mask.c_str(), "0", _get_time_minutes(_time).c_str()); + sprintf(time_line, time_mask.c_str(), "0", _get_time_minutes(m_time).c_str()); gcode_line = time_line; } // replaces placeholders for final line M73 with the real lines - else if (((_mode == Normal) && (gcode_line == Normal_Last_M73_Output_Placeholder_Tag)) || - ((_mode == Silent) && (gcode_line == Silent_Last_M73_Output_Placeholder_Tag))) + else if (((m_mode == Normal) && (gcode_line == Normal_Last_M73_Output_Placeholder_Tag)) || + ((m_mode == Silent) && (gcode_line == Silent_Last_M73_Output_Placeholder_Tag))) { sprintf(time_line, time_mask.c_str(), "100", "0"); gcode_line = time_line; @@ -319,27 +331,27 @@ namespace Slic3r { // add remaining time lines where needed - _parser.parse_line(gcode_line, + m_parser.parse_line(gcode_line, [this, &it_line_id, &g1_lines_count, &last_recorded_time, &time_line, &gcode_line, time_mask, interval](GCodeReader& reader, const GCodeReader::GCodeLine& line) { if (line.cmd_is("G1")) { ++g1_lines_count; - assert(it_line_id == _g1_line_ids.end() || it_line_id->first >= g1_lines_count); + assert(it_line_id == m_g1_line_ids.end() || it_line_id->first >= g1_lines_count); const Block *block = nullptr; - if (it_line_id != _g1_line_ids.end() && it_line_id->first == g1_lines_count) { - if (line.has_e() && it_line_id->second < (unsigned int)_blocks.size()) - block = &_blocks[it_line_id->second]; + if (it_line_id != m_g1_line_ids.end() && it_line_id->first == g1_lines_count) { + if (line.has_e() && it_line_id->second < (unsigned int)m_blocks.size()) + block = &m_blocks[it_line_id->second]; ++it_line_id; } if (block != nullptr && block->elapsed_time != -1.0f) { - float block_remaining_time = _time - block->elapsed_time; + float block_remaining_time = m_time - block->elapsed_time; if (std::abs(last_recorded_time - block_remaining_time) > interval) { - sprintf(time_line, time_mask.c_str(), std::to_string((int)(100.0f * block->elapsed_time / _time)).c_str(), _get_time_minutes(block_remaining_time).c_str()); + sprintf(time_line, time_mask.c_str(), std::to_string((int)(100.0f * block->elapsed_time / m_time)).c_str(), _get_time_minutes(block_remaining_time).c_str()); gcode_line += time_line; last_recorded_time = block_remaining_time; @@ -387,240 +399,240 @@ namespace Slic3r { void GCodeTimeEstimator::set_axis_position(EAxis axis, float position) { - _state.axis[axis].position = position; + m_state.axis[axis].position = position; } void GCodeTimeEstimator::set_axis_max_feedrate(EAxis axis, float feedrate_mm_sec) { - _state.axis[axis].max_feedrate = feedrate_mm_sec; + m_state.axis[axis].max_feedrate = feedrate_mm_sec; } void GCodeTimeEstimator::set_axis_max_acceleration(EAxis axis, float acceleration) { - _state.axis[axis].max_acceleration = acceleration; + m_state.axis[axis].max_acceleration = acceleration; } void GCodeTimeEstimator::set_axis_max_jerk(EAxis axis, float jerk) { - _state.axis[axis].max_jerk = jerk; + m_state.axis[axis].max_jerk = jerk; } float GCodeTimeEstimator::get_axis_position(EAxis axis) const { - return _state.axis[axis].position; + return m_state.axis[axis].position; } float GCodeTimeEstimator::get_axis_max_feedrate(EAxis axis) const { - return _state.axis[axis].max_feedrate; + return m_state.axis[axis].max_feedrate; } float GCodeTimeEstimator::get_axis_max_acceleration(EAxis axis) const { - return _state.axis[axis].max_acceleration; + return m_state.axis[axis].max_acceleration; } float GCodeTimeEstimator::get_axis_max_jerk(EAxis axis) const { - return _state.axis[axis].max_jerk; + return m_state.axis[axis].max_jerk; } void GCodeTimeEstimator::set_feedrate(float feedrate_mm_sec) { - _state.feedrate = feedrate_mm_sec; + m_state.feedrate = feedrate_mm_sec; } float GCodeTimeEstimator::get_feedrate() const { - return _state.feedrate; + return m_state.feedrate; } void GCodeTimeEstimator::set_acceleration(float acceleration_mm_sec2) { - _state.acceleration = (_state.max_acceleration == 0) ? + m_state.acceleration = (m_state.max_acceleration == 0) ? acceleration_mm_sec2 : // Clamp the acceleration with the maximum. - std::min(_state.max_acceleration, acceleration_mm_sec2); + std::min(m_state.max_acceleration, acceleration_mm_sec2); } float GCodeTimeEstimator::get_acceleration() const { - return _state.acceleration; + return m_state.acceleration; } void GCodeTimeEstimator::set_max_acceleration(float acceleration_mm_sec2) { - _state.max_acceleration = acceleration_mm_sec2; + m_state.max_acceleration = acceleration_mm_sec2; if (acceleration_mm_sec2 > 0) - _state.acceleration = acceleration_mm_sec2; + m_state.acceleration = acceleration_mm_sec2; } float GCodeTimeEstimator::get_max_acceleration() const { - return _state.max_acceleration; + return m_state.max_acceleration; } void GCodeTimeEstimator::set_retract_acceleration(float acceleration_mm_sec2) { - _state.retract_acceleration = acceleration_mm_sec2; + m_state.retract_acceleration = acceleration_mm_sec2; } float GCodeTimeEstimator::get_retract_acceleration() const { - return _state.retract_acceleration; + return m_state.retract_acceleration; } void GCodeTimeEstimator::set_minimum_feedrate(float feedrate_mm_sec) { - _state.minimum_feedrate = feedrate_mm_sec; + m_state.minimum_feedrate = feedrate_mm_sec; } float GCodeTimeEstimator::get_minimum_feedrate() const { - return _state.minimum_feedrate; + return m_state.minimum_feedrate; } void GCodeTimeEstimator::set_minimum_travel_feedrate(float feedrate_mm_sec) { - _state.minimum_travel_feedrate = feedrate_mm_sec; + m_state.minimum_travel_feedrate = feedrate_mm_sec; } float GCodeTimeEstimator::get_minimum_travel_feedrate() const { - return _state.minimum_travel_feedrate; + return m_state.minimum_travel_feedrate; } void GCodeTimeEstimator::set_filament_load_times(const std::vector<double> &filament_load_times) { - _state.filament_load_times.clear(); + m_state.filament_load_times.clear(); for (double t : filament_load_times) - _state.filament_load_times.push_back((float)t); + m_state.filament_load_times.push_back((float)t); } void GCodeTimeEstimator::set_filament_unload_times(const std::vector<double> &filament_unload_times) { - _state.filament_unload_times.clear(); + m_state.filament_unload_times.clear(); for (double t : filament_unload_times) - _state.filament_unload_times.push_back((float)t); + m_state.filament_unload_times.push_back((float)t); } float GCodeTimeEstimator::get_filament_load_time(unsigned int id_extruder) { return - (_state.filament_load_times.empty() || id_extruder == _state.extruder_id_unloaded) ? + (m_state.filament_load_times.empty() || id_extruder == m_state.extruder_id_unloaded) ? 0 : - (_state.filament_load_times.size() <= id_extruder) ? - _state.filament_load_times.front() : - _state.filament_load_times[id_extruder]; + (m_state.filament_load_times.size() <= id_extruder) ? + m_state.filament_load_times.front() : + m_state.filament_load_times[id_extruder]; } float GCodeTimeEstimator::get_filament_unload_time(unsigned int id_extruder) { return - (_state.filament_unload_times.empty() || id_extruder == _state.extruder_id_unloaded) ? + (m_state.filament_unload_times.empty() || id_extruder == m_state.extruder_id_unloaded) ? 0 : - (_state.filament_unload_times.size() <= id_extruder) ? - _state.filament_unload_times.front() : - _state.filament_unload_times[id_extruder]; + (m_state.filament_unload_times.size() <= id_extruder) ? + m_state.filament_unload_times.front() : + m_state.filament_unload_times[id_extruder]; } void GCodeTimeEstimator::set_extrude_factor_override_percentage(float percentage) { - _state.extrude_factor_override_percentage = percentage; + m_state.extrude_factor_override_percentage = percentage; } float GCodeTimeEstimator::get_extrude_factor_override_percentage() const { - return _state.extrude_factor_override_percentage; + return m_state.extrude_factor_override_percentage; } void GCodeTimeEstimator::set_dialect(GCodeFlavor dialect) { - _state.dialect = dialect; + m_state.dialect = dialect; } GCodeFlavor GCodeTimeEstimator::get_dialect() const { PROFILE_FUNC(); - return _state.dialect; + return m_state.dialect; } void GCodeTimeEstimator::set_units(GCodeTimeEstimator::EUnits units) { - _state.units = units; + m_state.units = units; } GCodeTimeEstimator::EUnits GCodeTimeEstimator::get_units() const { - return _state.units; + return m_state.units; } void GCodeTimeEstimator::set_global_positioning_type(GCodeTimeEstimator::EPositioningType type) { - _state.global_positioning_type = type; + m_state.global_positioning_type = type; } GCodeTimeEstimator::EPositioningType GCodeTimeEstimator::get_global_positioning_type() const { - return _state.global_positioning_type; + return m_state.global_positioning_type; } void GCodeTimeEstimator::set_e_local_positioning_type(GCodeTimeEstimator::EPositioningType type) { - _state.e_local_positioning_type = type; + m_state.e_local_positioning_type = type; } GCodeTimeEstimator::EPositioningType GCodeTimeEstimator::get_e_local_positioning_type() const { - return _state.e_local_positioning_type; + return m_state.e_local_positioning_type; } int GCodeTimeEstimator::get_g1_line_id() const { - return _state.g1_line_id; + return m_state.g1_line_id; } void GCodeTimeEstimator::increment_g1_line_id() { - ++_state.g1_line_id; + ++m_state.g1_line_id; } void GCodeTimeEstimator::reset_g1_line_id() { - _state.g1_line_id = 0; + m_state.g1_line_id = 0; } void GCodeTimeEstimator::set_extruder_id(unsigned int id) { - _state.extruder_id = id; + m_state.extruder_id = id; } unsigned int GCodeTimeEstimator::get_extruder_id() const { - return _state.extruder_id; + return m_state.extruder_id; } void GCodeTimeEstimator::reset_extruder_id() { // Set the initial extruder ID to unknown. For the multi-material setup it means // that all the filaments are parked in the MMU and no filament is loaded yet. - _state.extruder_id = _state.extruder_id_unloaded; + m_state.extruder_id = m_state.extruder_id_unloaded; } void GCodeTimeEstimator::add_additional_time(float timeSec) { PROFILE_FUNC(); - _state.additional_time += timeSec; + m_state.additional_time += timeSec; } void GCodeTimeEstimator::set_additional_time(float timeSec) { - _state.additional_time = timeSec; + m_state.additional_time = timeSec; } float GCodeTimeEstimator::get_additional_time() const { - return _state.additional_time; + return m_state.additional_time; } void GCodeTimeEstimator::set_default() @@ -648,8 +660,8 @@ namespace Slic3r { set_axis_max_jerk(axis, DEFAULT_AXIS_MAX_JERK[a]); } - _state.filament_load_times.clear(); - _state.filament_unload_times.clear(); + m_state.filament_load_times.clear(); + m_state.filament_unload_times.clear(); } void GCodeTimeEstimator::reset() @@ -664,7 +676,7 @@ namespace Slic3r { float GCodeTimeEstimator::get_time() const { - return _time; + return m_time; } std::string GCodeTimeEstimator::get_time_dhms() const @@ -677,19 +689,44 @@ namespace Slic3r { return _get_time_minutes(get_time()); } + std::vector<float> GCodeTimeEstimator::get_color_times() const + { + return m_color_times; + } + + std::vector<std::string> GCodeTimeEstimator::get_color_times_dhms() const + { + std::vector<std::string> ret; + for (float t : m_color_times) + { + ret.push_back(_get_time_dhms(t)); + } + return ret; + } + + std::vector<std::string> GCodeTimeEstimator::get_color_times_minutes() const + { + std::vector<std::string> ret; + for (float t : m_color_times) + { + ret.push_back(_get_time_minutes(t)); + } + return ret; + } + // Return an estimate of the memory consumed by the time estimator. size_t GCodeTimeEstimator::memory_used() const { size_t out = sizeof(*this); - out += SLIC3R_STDVEC_MEMSIZE(this->_blocks, Block); - out += SLIC3R_STDVEC_MEMSIZE(this->_g1_line_ids, G1LineIdToBlockId); + out += SLIC3R_STDVEC_MEMSIZE(this->m_blocks, Block); + out += SLIC3R_STDVEC_MEMSIZE(this->m_g1_line_ids, G1LineIdToBlockId); return out; } void GCodeTimeEstimator::_reset() { - _curr.reset(); - _prev.reset(); + m_curr.reset(); + m_prev.reset(); set_axis_position(X, 0.0f); set_axis_position(Y, 0.0f); @@ -701,19 +738,23 @@ namespace Slic3r { reset_extruder_id(); reset_g1_line_id(); - _g1_line_ids.clear(); + m_g1_line_ids.clear(); - _last_st_synchronized_block_id = -1; + m_last_st_synchronized_block_id = -1; + + m_needs_color_times = false; + m_color_times.clear(); + m_color_time_cache = 0.0f; } void GCodeTimeEstimator::_reset_time() { - _time = 0.0f; + m_time = 0.0f; } void GCodeTimeEstimator::_reset_blocks() { - _blocks.clear(); + m_blocks.clear(); } void GCodeTimeEstimator::_calculate_time() @@ -723,35 +764,32 @@ namespace Slic3r { _reverse_pass(); _recalculate_trapezoids(); - _time += get_additional_time(); + m_time += get_additional_time(); + m_color_time_cache += get_additional_time(); - for (int i = _last_st_synchronized_block_id + 1; i < (int)_blocks.size(); ++i) + for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size(); ++i) { - Block& block = _blocks[i]; - -#if ENABLE_MOVE_STATS + Block& block = m_blocks[i]; float block_time = 0.0f; block_time += block.acceleration_time(); block_time += block.cruise_time(); block_time += block.deceleration_time(); - _time += block_time; - block.elapsed_time = _time; + m_time += block_time; + block.elapsed_time = m_time; +#if ENABLE_MOVE_STATS MovesStatsMap::iterator it = _moves_stats.find(block.move_type); if (it == _moves_stats.end()) it = _moves_stats.insert(MovesStatsMap::value_type(block.move_type, MoveStats())).first; it->second.count += 1; it->second.time += block_time; -#else - _time += block.acceleration_time(); - _time += block.cruise_time(); - _time += block.deceleration_time(); - block.elapsed_time = _time; #endif // ENABLE_MOVE_STATS + + m_color_time_cache += block_time; } - _last_st_synchronized_block_id = (int)_blocks.size() - 1; + 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.); } @@ -866,6 +904,11 @@ namespace Slic3r { _processM566(line); break; } + case 600: // Set color change + { + _processM600(line); + break; + } case 702: // MK3 MMU2: Process the final filament unload. { _processM702(line); @@ -934,7 +977,7 @@ namespace Slic3r { return; // calculates block feedrate - _curr.feedrate = std::max(get_feedrate(), block.is_travel_move() ? get_minimum_travel_feedrate() : get_minimum_feedrate()); + m_curr.feedrate = std::max(get_feedrate(), block.is_travel_move() ? get_minimum_travel_feedrate() : get_minimum_feedrate()); float distance = block.move_length(); float invDistance = 1.0f / distance; @@ -942,23 +985,23 @@ namespace Slic3r { float min_feedrate_factor = 1.0f; for (unsigned char a = X; a < Num_Axis; ++a) { - _curr.axis_feedrate[a] = _curr.feedrate * block.delta_pos[a] * invDistance; + m_curr.axis_feedrate[a] = m_curr.feedrate * block.delta_pos[a] * invDistance; if (a == E) - _curr.axis_feedrate[a] *= get_extrude_factor_override_percentage(); + m_curr.axis_feedrate[a] *= get_extrude_factor_override_percentage(); - _curr.abs_axis_feedrate[a] = std::abs(_curr.axis_feedrate[a]); - if (_curr.abs_axis_feedrate[a] > 0.0f) - min_feedrate_factor = std::min(min_feedrate_factor, get_axis_max_feedrate((EAxis)a) / _curr.abs_axis_feedrate[a]); + m_curr.abs_axis_feedrate[a] = std::abs(m_curr.axis_feedrate[a]); + if (m_curr.abs_axis_feedrate[a] > 0.0f) + min_feedrate_factor = std::min(min_feedrate_factor, get_axis_max_feedrate((EAxis)a) / m_curr.abs_axis_feedrate[a]); } - block.feedrate.cruise = min_feedrate_factor * _curr.feedrate; + block.feedrate.cruise = min_feedrate_factor * m_curr.feedrate; if (min_feedrate_factor < 1.0f) { for (unsigned char a = X; a < Num_Axis; ++a) { - _curr.axis_feedrate[a] *= min_feedrate_factor; - _curr.abs_axis_feedrate[a] *= min_feedrate_factor; + m_curr.axis_feedrate[a] *= min_feedrate_factor; + m_curr.abs_axis_feedrate[a] *= min_feedrate_factor; } } @@ -975,25 +1018,25 @@ namespace Slic3r { block.acceleration = acceleration; // calculates block exit feedrate - _curr.safe_feedrate = block.feedrate.cruise; + m_curr.safe_feedrate = block.feedrate.cruise; for (unsigned char a = X; a < Num_Axis; ++a) { float axis_max_jerk = get_axis_max_jerk((EAxis)a); - if (_curr.abs_axis_feedrate[a] > axis_max_jerk) - _curr.safe_feedrate = std::min(_curr.safe_feedrate, axis_max_jerk); + if (m_curr.abs_axis_feedrate[a] > axis_max_jerk) + m_curr.safe_feedrate = std::min(m_curr.safe_feedrate, axis_max_jerk); } - block.feedrate.exit = _curr.safe_feedrate; + block.feedrate.exit = m_curr.safe_feedrate; // calculates block entry feedrate - float vmax_junction = _curr.safe_feedrate; - if (!_blocks.empty() && (_prev.feedrate > PREVIOUS_FEEDRATE_THRESHOLD)) + float vmax_junction = m_curr.safe_feedrate; + if (!m_blocks.empty() && (m_prev.feedrate > PREVIOUS_FEEDRATE_THRESHOLD)) { - bool prev_speed_larger = _prev.feedrate > block.feedrate.cruise; - float smaller_speed_factor = prev_speed_larger ? (block.feedrate.cruise / _prev.feedrate) : (_prev.feedrate / block.feedrate.cruise); + bool prev_speed_larger = m_prev.feedrate > block.feedrate.cruise; + float smaller_speed_factor = prev_speed_larger ? (block.feedrate.cruise / m_prev.feedrate) : (m_prev.feedrate / block.feedrate.cruise); // Pick the smaller of the nominal speeds. Higher speed shall not be achieved at the junction during coasting. - vmax_junction = prev_speed_larger ? block.feedrate.cruise : _prev.feedrate; + vmax_junction = prev_speed_larger ? block.feedrate.cruise : m_prev.feedrate; float v_factor = 1.0f; bool limited = false; @@ -1001,8 +1044,8 @@ namespace Slic3r { for (unsigned char a = X; a < Num_Axis; ++a) { // Limit an axis. We have to differentiate coasting from the reversal of an axis movement, or a full stop. - float v_exit = _prev.axis_feedrate[a]; - float v_entry = _curr.axis_feedrate[a]; + float v_exit = m_prev.axis_feedrate[a]; + float v_entry = m_curr.axis_feedrate[a]; if (prev_speed_larger) v_exit *= smaller_speed_factor; @@ -1044,23 +1087,23 @@ namespace Slic3r { float vmax_junction_threshold = vmax_junction * 0.99f; // Not coasting. The machine will stop and start the movements anyway, better to start the segment from start. - if ((_prev.safe_feedrate > vmax_junction_threshold) && (_curr.safe_feedrate > vmax_junction_threshold)) - vmax_junction = _curr.safe_feedrate; + if ((m_prev.safe_feedrate > vmax_junction_threshold) && (m_curr.safe_feedrate > vmax_junction_threshold)) + vmax_junction = m_curr.safe_feedrate; } - float v_allowable = Block::max_allowable_speed(-acceleration, _curr.safe_feedrate, distance); + float v_allowable = Block::max_allowable_speed(-acceleration, m_curr.safe_feedrate, distance); block.feedrate.entry = std::min(vmax_junction, v_allowable); block.max_entry_speed = vmax_junction; block.flags.nominal_length = (block.feedrate.cruise <= v_allowable); block.flags.recalculate = true; - block.safe_feedrate = _curr.safe_feedrate; + block.safe_feedrate = m_curr.safe_feedrate; // calculates block trapezoid block.calculate_trapezoid(); // updates previous - _prev = _curr; + m_prev = m_curr; // updates axis positions for (unsigned char a = X; a < Num_Axis; ++a) @@ -1091,8 +1134,8 @@ namespace Slic3r { #endif // ENABLE_MOVE_STATS // adds block to blocks list - _blocks.emplace_back(block); - _g1_line_ids.emplace_back(G1LineIdToBlockIdMap::value_type(get_g1_line_id(), (unsigned int)_blocks.size() - 1)); + m_blocks.emplace_back(block); + m_g1_line_ids.emplace_back(G1LineIdToBlockIdMap::value_type(get_g1_line_id(), (unsigned int)m_blocks.size() - 1)); } void GCodeTimeEstimator::_processG4(const GCodeReader::GCodeLine& line) @@ -1336,6 +1379,18 @@ namespace Slic3r { set_axis_max_jerk(E, line.e() * MMMIN_TO_MMSEC); } + void GCodeTimeEstimator::_processM600(const GCodeReader::GCodeLine& line) + { + PROFILE_FUNC(); + m_needs_color_times = true; + _calculate_time(); + if (m_color_time_cache != 0.0f) + { + m_color_times.push_back(m_color_time_cache); + m_color_time_cache = 0.0f; + } + } + void GCodeTimeEstimator::_processM702(const GCodeReader::GCodeLine& line) { PROFILE_FUNC(); @@ -1376,11 +1431,11 @@ namespace Slic3r { void GCodeTimeEstimator::_forward_pass() { PROFILE_FUNC(); - if (_blocks.size() > 1) + if (m_blocks.size() > 1) { - for (int i = _last_st_synchronized_block_id + 1; i < (int)_blocks.size() - 1; ++i) + for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size() - 1; ++i) { - _planner_forward_pass_kernel(_blocks[i], _blocks[i + 1]); + _planner_forward_pass_kernel(m_blocks[i], m_blocks[i + 1]); } } } @@ -1388,11 +1443,11 @@ namespace Slic3r { void GCodeTimeEstimator::_reverse_pass() { PROFILE_FUNC(); - if (_blocks.size() > 1) + if (m_blocks.size() > 1) { - for (int i = (int)_blocks.size() - 1; i >= _last_st_synchronized_block_id + 2; --i) + for (int i = (int)m_blocks.size() - 1; i >= m_last_st_synchronized_block_id + 2; --i) { - _planner_reverse_pass_kernel(_blocks[i - 1], _blocks[i]); + _planner_reverse_pass_kernel(m_blocks[i - 1], m_blocks[i]); } } } @@ -1444,9 +1499,9 @@ namespace Slic3r { Block* curr = nullptr; Block* next = nullptr; - for (int i = _last_st_synchronized_block_id + 1; i < (int)_blocks.size(); ++i) + for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size(); ++i) { - Block& b = _blocks[i]; + Block& b = m_blocks[i]; curr = next; next = &b; @@ -1517,7 +1572,7 @@ namespace Slic3r { { std::cout << MOVE_TYPE_STR[move.first]; std::cout << ": count " << move.second.count << " (" << 100.0f * (float)move.second.count / moves_count << "%)"; - std::cout << " - time: " << move.second.time << "s (" << 100.0f * move.second.time / _time << "%)"; + std::cout << " - time: " << move.second.time << "s (" << 100.0f * move.second.time / m_time << "%)"; std::cout << std::endl; } std::cout << std::endl; diff --git a/src/libslic3r/GCodeTimeEstimator.hpp b/src/libslic3r/GCodeTimeEstimator.hpp index 1fbc1c14b..840d58778 100644 --- a/src/libslic3r/GCodeTimeEstimator.hpp +++ b/src/libslic3r/GCodeTimeEstimator.hpp @@ -215,17 +215,22 @@ namespace Slic3r { typedef std::vector<G1LineIdToBlockId> G1LineIdToBlockIdMap; private: - EMode _mode; - GCodeReader _parser; - State _state; - Feedrates _curr; - Feedrates _prev; - BlocksList _blocks; + EMode m_mode; + GCodeReader m_parser; + State m_state; + 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 _g1_line_ids; + G1LineIdToBlockIdMap m_g1_line_ids; // Index of the last block already st_synchronized - int _last_st_synchronized_block_id; - float _time; // s + int m_last_st_synchronized_block_id; + float m_time; // s + + // data to calculate color print times + bool m_needs_color_times; + std::vector<float> m_color_times; + float m_color_time_cache; #if ENABLE_MOVE_STATS MovesStatsMap _moves_stats; @@ -341,6 +346,15 @@ namespace Slic3r { // Returns the estimated time, in minutes (integer) std::string get_time_minutes() const; + // Returns the estimated time, in seconds, for each color + std::vector<float> get_color_times() const; + + // Returns the estimated time, in format DDd HHh MMm SSs, for each color + std::vector<std::string> get_color_times_dhms() const; + + // Returns the estimated time, in minutes (integer), for each color + std::vector<std::string> get_color_times_minutes() const; + // Return an estimate of the memory consumed by the time estimator. size_t memory_used() const; @@ -409,6 +423,9 @@ namespace Slic3r { // Set allowable instantaneous speed change void _processM566(const GCodeReader::GCodeLine& line); + // Set color change + void _processM600(const GCodeReader::GCodeLine& line); + // Unload the current filament into the MK3 MMU2 unit at the end of print. void _processM702(const GCodeReader::GCodeLine& line); diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 53d6d692d..7fe0eb7a3 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -238,6 +238,8 @@ struct PrintStatistics PrintStatistics() { clear(); } std::string estimated_normal_print_time; std::string estimated_silent_print_time; + std::vector<std::string> estimated_normal_color_print_times; + std::vector<std::string> estimated_silent_color_print_times; double total_used_filament; double total_extruded_volume; double total_cost; @@ -256,6 +258,8 @@ struct PrintStatistics void clear() { estimated_normal_print_time.clear(); estimated_silent_print_time.clear(); + estimated_normal_color_print_times.clear(); + estimated_silent_color_print_times.clear(); total_used_filament = 0.; total_extruded_volume = 0.; total_cost = 0.; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 09ab91ef1..217937123 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1116,10 +1116,20 @@ void Sidebar::show_sliced_info_sizer(const bool show) if (ps.estimated_normal_print_time != "N/A") { new_label += wxString::Format("\n - %s", _(L("normal mode"))); info_text += wxString::Format("\n%s", ps.estimated_normal_print_time); + for (unsigned int i = 0; i < (unsigned int)ps.estimated_normal_color_print_times.size(); ++i) + { + new_label += wxString::Format("\n - %s%d", _(L("Color ")), i + 1); + info_text += wxString::Format("\n%s", ps.estimated_normal_color_print_times[i]); + } } if (ps.estimated_silent_print_time != "N/A") { new_label += wxString::Format("\n - %s", _(L("stealth mode"))); info_text += wxString::Format("\n%s", ps.estimated_silent_print_time); + for (unsigned int i = 0; i < (unsigned int)ps.estimated_normal_color_print_times.size(); ++i) + { + new_label += wxString::Format("\n - %s%d", _(L("Color ")), i + 1); + info_text += wxString::Format("\n%s", ps.estimated_normal_color_print_times[i]); + } } p->sliced_info->SetTextAndShow(siEstimatedTime, info_text, new_label); }