mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	Merge branch 'et_color_print_times' of https://github.com/prusa3d/PrusaSlicer
This commit is contained in:
		
						commit
						29dfa786ff
					
				
					 5 changed files with 233 additions and 143 deletions
				
			
		|  | @ -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); | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -241,6 +241,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; | ||||
|  | @ -259,6 +261,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.; | ||||
|  |  | |||
|  | @ -1132,10 +1132,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); | ||||
|             } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Enrico Turri
						Enrico Turri