From f2d02faef4f73c9e71c4b06a438920937be7255b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 17 Aug 2020 10:06:41 +0200 Subject: [PATCH] GCodeProcessor -> Added debug code to check toolpaths data extracted from gcode, as mm3 per mm, height and width --- src/libslic3r/GCode.cpp | 11 ++ src/libslic3r/GCode.hpp | 6 + src/libslic3r/GCode/GCodeProcessor.cpp | 210 ++++++++++++++++--------- src/libslic3r/GCode/GCodeProcessor.hpp | 113 ++++++++++--- src/libslic3r/GCode/WipeTower.cpp | 16 ++ src/libslic3r/Technologies.hpp | 1 + src/slic3r/GUI/GCodeViewer.cpp | 4 +- 7 files changed, 263 insertions(+), 98 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 795aac898..24c758d50 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1186,6 +1186,9 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu m_last_width = 0.0f; m_last_height = 0.0f; m_last_layer_z = 0.0f; +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + m_last_mm3_per_mm = 0.0; +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING #else m_last_mm3_per_mm = GCodeAnalyzer::Default_mm3_per_mm; m_last_width = GCodeAnalyzer::Default_Width; @@ -3268,6 +3271,14 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, sprintf(buf, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(m_last_processor_extrusion_role).c_str()); gcode += buf; } + +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + if (last_was_wipe_tower || (m_last_mm3_per_mm != path.mm3_per_mm)) { + m_last_mm3_per_mm = path.mm3_per_mm; + sprintf(buf, ";%s%f\n", GCodeProcessor::Mm3_Per_Mm_Tag.c_str(), m_last_mm3_per_mm); + gcode += buf; + } +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING #else if (path.role() != m_last_analyzer_extrusion_role) { m_last_analyzer_extrusion_role = path.role(); diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 6f97d5dbd..76f897c63 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -172,6 +172,9 @@ public: m_volumetric_speed(0), m_last_pos_defined(false), m_last_extrusion_role(erNone), +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + m_last_mm3_per_mm(0.0), +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING #if !ENABLE_GCODE_VIEWER m_last_mm3_per_mm(GCodeAnalyzer::Default_mm3_per_mm), m_last_width(GCodeAnalyzer::Default_Width), @@ -381,6 +384,9 @@ private: float m_last_width{ 0.0f }; float m_last_height{ 0.0f }; float m_last_layer_z{ 0.0f }; +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + double m_last_mm3_per_mm; +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING #else // Support for G-Code Analyzer double m_last_mm3_per_mm; diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 18878cd5a..2e6736d1e 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -33,6 +33,10 @@ const std::string GCodeProcessor::First_Line_M73_Placeholder_Tag = "; _ const std::string GCodeProcessor::Last_Line_M73_Placeholder_Tag = "; _GP_LAST_LINE_M73_PLACEHOLDER"; const std::string GCodeProcessor::Estimated_Printing_Time_Placeholder_Tag = "; _GP_ESTIMATED_PRINTING_TIME_PLACEHOLDER"; +#if ENABLE_GCODE_VIEWER_DATA_CHECKING +const std::string GCodeProcessor::Mm3_Per_Mm_Tag = "Mm3_Per_Mm:"; +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING + static bool is_valid_extrusion_role(int value) { return (static_cast(erNone) <= value) && (value <= static_cast(erMixed)); @@ -308,10 +312,10 @@ void GCodeProcessor::TimeProcessor::reset() machine_limits = MachineEnvelopeConfig(); filament_load_times = std::vector(); filament_unload_times = std::vector(); - for (size_t i = 0; i < static_cast(ETimeMode::Count); ++i) { + for (size_t i = 0; i < static_cast(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) { machines[i].reset(); } - machines[static_cast(ETimeMode::Normal)].enabled = true; + machines[static_cast(PrintEstimatedTimeStatistics::ETimeMode::Normal)].enabled = true; } void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) @@ -342,8 +346,8 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) std::string gcode_line; size_t g1_lines_counter = 0; // keeps track of last exported pair - std::array, static_cast(ETimeMode::Count)> last_exported; - for (size_t i = 0; i < static_cast(ETimeMode::Count); ++i) { + std::array, static_cast(PrintEstimatedTimeStatistics::ETimeMode::Count)> last_exported; + for (size_t i = 0; i < static_cast(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) { last_exported[i] = { 0, time_in_minutes(machines[i].time) }; } @@ -357,7 +361,7 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) std::string ret; if (line == First_Line_M73_Placeholder_Tag || line == Last_Line_M73_Placeholder_Tag) { - for (size_t i = 0; i < static_cast(ETimeMode::Count); ++i) { + for (size_t i = 0; i < static_cast(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) { const TimeMachine& machine = machines[i]; if (machine.enabled) { ret += format_line_M73(machine.line_m73_mask.c_str(), @@ -367,12 +371,12 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) } } else if (line == Estimated_Printing_Time_Placeholder_Tag) { - for (size_t i = 0; i < static_cast(ETimeMode::Count); ++i) { + for (size_t i = 0; i < static_cast(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) { const TimeMachine& machine = machines[i]; if (machine.enabled) { char buf[128]; sprintf(buf, "; estimated printing time (%s mode) = %s\n", - (static_cast(i) == ETimeMode::Normal) ? "normal" : "silent", + (static_cast(i) == PrintEstimatedTimeStatistics::ETimeMode::Normal) ? "normal" : "silent", get_time_dhms(machine.time).c_str()); ret += buf; } @@ -383,7 +387,7 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) // add lines M73 to exported gcode auto process_line_G1 = [&]() { - for (size_t i = 0; i < static_cast(ETimeMode::Count); ++i) { + for (size_t i = 0; i < static_cast(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) { const TimeMachine& machine = machines[i]; if (machine.enabled && g1_lines_counter < machine.g1_times_cache.size()) { float elapsed_time = machine.g1_times_cache[g1_lines_counter]; @@ -458,8 +462,8 @@ unsigned int GCodeProcessor::s_result_id = 0; GCodeProcessor::GCodeProcessor() { reset(); - m_time_processor.machines[static_cast(ETimeMode::Normal)].line_m73_mask = "M73 P%s R%s\n"; - m_time_processor.machines[static_cast(ETimeMode::Stealth)].line_m73_mask = "M73 Q%s S%s\n"; + m_time_processor.machines[static_cast(PrintEstimatedTimeStatistics::ETimeMode::Normal)].line_m73_mask = "M73 P%s R%s\n"; + m_time_processor.machines[static_cast(PrintEstimatedTimeStatistics::ETimeMode::Stealth)].line_m73_mask = "M73 Q%s S%s\n"; } void GCodeProcessor::apply_config(const PrintConfig& config) @@ -478,7 +482,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config) m_extruder_colors.resize(extruders_count); for (size_t i = 0; i < extruders_count; ++i) { - m_extruder_colors[i] = static_cast(i); + m_extruder_colors[i] = static_cast(i); } m_filament_diameters.resize(config.filament_diameter.values.size()); @@ -499,7 +503,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config) m_time_processor.filament_unload_times[i] = static_cast(config.filament_unload_time.values[i]); } - for (size_t i = 0; i < static_cast(ETimeMode::Count); ++i) { + for (size_t i = 0; i < static_cast(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) { float max_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_extruding, i); m_time_processor.machines[i].max_acceleration = max_acceleration; m_time_processor.machines[i].acceleration = (max_acceleration > 0.0f) ? max_acceleration : DEFAULT_ACCELERATION; @@ -561,7 +565,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) m_extruder_colors.resize(m_result.extruder_colors.size()); for (size_t i = 0; i < m_result.extruder_colors.size(); ++i) { - m_extruder_colors[i] = static_cast(i); + m_extruder_colors[i] = static_cast(i); } const ConfigOptionFloats* filament_load_time = config.option("filament_load_time"); @@ -644,7 +648,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) if (machine_min_travel_rate != nullptr) m_time_processor.machine_limits.machine_min_travel_rate.values = machine_min_travel_rate->values; - for (size_t i = 0; i < static_cast(ETimeMode::Count); ++i) { + for (size_t i = 0; i < static_cast(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) { float max_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_extruding, i); m_time_processor.machines[i].max_acceleration = max_acceleration; m_time_processor.machines[i].acceleration = (max_acceleration > 0.0f) ? max_acceleration : DEFAULT_ACCELERATION; @@ -653,15 +657,17 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) void GCodeProcessor::enable_stealth_time_estimator(bool enabled) { - m_time_processor.machines[static_cast(ETimeMode::Stealth)].enabled = enabled; + m_time_processor.machines[static_cast(PrintEstimatedTimeStatistics::ETimeMode::Stealth)].enabled = enabled; } void GCodeProcessor::reset() { + static const size_t Min_Extruder_Count = 5; + m_units = EUnits::Millimeters; m_global_positioning_type = EPositioningType::Absolute; m_e_local_positioning_type = EPositioningType::Absolute; - m_extruder_offsets = std::vector(1, Vec3f::Zero()); + m_extruder_offsets = std::vector(Min_Extruder_Count, Vec3f::Zero()); m_flavor = gcfRepRap; m_start_position = { 0.0f, 0.0f, 0.0f, 0.0f }; @@ -677,8 +683,12 @@ void GCodeProcessor::reset() m_extrusion_role = erNone; m_extruder_id = 0; - m_extruder_colors = ExtruderColors(); - m_filament_diameters = std::vector(); + m_extruder_colors.resize(Min_Extruder_Count); + for (size_t i = 0; i < Min_Extruder_Count; ++i) { + m_extruder_colors[i] = static_cast(i); + } + + m_filament_diameters = std::vector(Min_Extruder_Count, 1.75f); m_extruded_last_z = 0.0f; m_cp_color.reset(); @@ -689,6 +699,12 @@ void GCodeProcessor::reset() m_result.reset(); m_result.id = ++s_result_id; + +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + m_mm3_per_mm_compare.reset(); + m_height_compare.reset(); + m_width_compare.reset(); +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING } void GCodeProcessor::process_file(const std::string& filename) @@ -724,7 +740,7 @@ void GCodeProcessor::process_file(const std::string& filename) m_parser.parse_file(filename, [this](GCodeReader& reader, const GCodeReader::GCodeLine& line) { process_gcode_line(line); }); // process the remaining time blocks - for (size_t i = 0; i < static_cast(ETimeMode::Count); ++i) { + for (size_t i = 0; i < static_cast(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) { TimeMachine& machine = m_time_processor.machines[i]; TimeMachine::CustomGCodeTime& gcode_time = machine.gcode_time; machine.calculate_time(); @@ -738,25 +754,31 @@ void GCodeProcessor::process_file(const std::string& filename) if (m_time_processor.export_remaining_time_enabled) m_time_processor.post_process(filename); +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + m_mm3_per_mm_compare.output(); + m_height_compare.output(); + m_width_compare.output(); +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING + #if ENABLE_GCODE_VIEWER_STATISTICS m_result.time = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start_time).count(); #endif // ENABLE_GCODE_VIEWER_STATISTICS } -float GCodeProcessor::get_time(ETimeMode mode) const +float GCodeProcessor::get_time(PrintEstimatedTimeStatistics::ETimeMode mode) const { - return (mode < ETimeMode::Count) ? m_time_processor.machines[static_cast(mode)].time : 0.0f; + return (mode < PrintEstimatedTimeStatistics::ETimeMode::Count) ? m_time_processor.machines[static_cast(mode)].time : 0.0f; } -std::string GCodeProcessor::get_time_dhm(ETimeMode mode) const +std::string GCodeProcessor::get_time_dhm(PrintEstimatedTimeStatistics::ETimeMode mode) const { - return (mode < ETimeMode::Count) ? short_time(get_time_dhms(m_time_processor.machines[static_cast(mode)].time)) : std::string("N/A"); + return (mode < PrintEstimatedTimeStatistics::ETimeMode::Count) ? short_time(get_time_dhms(m_time_processor.machines[static_cast(mode)].time)) : std::string("N/A"); } -std::vector>> GCodeProcessor::get_custom_gcode_times(ETimeMode mode, bool include_remaining) const +std::vector>> GCodeProcessor::get_custom_gcode_times(PrintEstimatedTimeStatistics::ETimeMode mode, bool include_remaining) const { std::vector>> ret; - if (mode < ETimeMode::Count) { + if (mode < PrintEstimatedTimeStatistics::ETimeMode::Count) { const TimeMachine& machine = m_time_processor.machines[static_cast(mode)]; float total_time = 0.0f; for (const auto& [type, time] : machine.gcode_time.times) { @@ -768,10 +790,10 @@ std::vector>> GCodeProcesso return ret; } -std::vector> GCodeProcessor::get_moves_time(ETimeMode mode) const +std::vector> GCodeProcessor::get_moves_time(PrintEstimatedTimeStatistics::ETimeMode mode) const { std::vector> ret; - if (mode < ETimeMode::Count) { + if (mode < PrintEstimatedTimeStatistics::ETimeMode::Count) { for (size_t i = 0; i < m_time_processor.machines[static_cast(mode)].moves_time.size(); ++i) { float time = m_time_processor.machines[static_cast(mode)].moves_time[i]; if (time > 0.0f) @@ -781,10 +803,10 @@ std::vector> GCodeProcessor::get_moves_time(ETimeMod return ret; } -std::vector> GCodeProcessor::get_roles_time(ETimeMode mode) const +std::vector> GCodeProcessor::get_roles_time(PrintEstimatedTimeStatistics::ETimeMode mode) const { std::vector> ret; - if (mode < ETimeMode::Count) { + if (mode < PrintEstimatedTimeStatistics::ETimeMode::Count) { for (size_t i = 0; i < m_time_processor.machines[static_cast(mode)].roles_time.size(); ++i) { float time = m_time_processor.machines[static_cast(mode)].roles_time[i]; if (time > 0.0f) @@ -888,6 +910,9 @@ void GCodeProcessor::process_tags(const std::string& comment) if (pos != comment.npos) { try { m_width = std::stof(comment.substr(pos + Width_Tag.length())); +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + m_width_compare.last_tag_value = m_width; +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING } catch (...) { BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Width (" << comment << ")."; @@ -900,6 +925,9 @@ void GCodeProcessor::process_tags(const std::string& comment) if (pos != comment.npos) { try { m_height = std::stof(comment.substr(pos + Height_Tag.length())); +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + m_height_compare.last_tag_value = m_height; +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING } catch (...) { BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Height (" << comment << ")."; @@ -947,6 +975,20 @@ void GCodeProcessor::process_tags(const std::string& comment) store_move_vertex(EMoveType::Custom_GCode); return; } + +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + // mm3_per_mm print tag + pos = comment.find(Mm3_Per_Mm_Tag); + if (pos != comment.npos) { + try { + m_mm3_per_mm_compare.last_tag_value = std::stof(comment.substr(pos + Mm3_Per_Mm_Tag.length())); + } + catch (...) { + BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Mm3_Per_Mm (" << comment << ")."; + } + return; + } +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING } bool GCodeProcessor::process_producers_tags(const std::string& comment) @@ -1126,8 +1168,10 @@ bool GCodeProcessor::process_simplify3d_tags(const std::string& comment) size_t w_end = data.find_first_of(' ', w_start); if (h_start != data.npos) { try { - std::string test = data.substr(h_start + 1, (h_end != data.npos) ? h_end - h_start - 1 : h_end); m_height = std::stof(data.substr(h_start + 1, (h_end != data.npos) ? h_end - h_start - 1 : h_end)); +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + m_height_compare.last_tag_value = m_height; +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING } catch (...) { BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Height (" << comment << ")."; @@ -1135,8 +1179,10 @@ bool GCodeProcessor::process_simplify3d_tags(const std::string& comment) } if (w_start != data.npos) { try { - std::string test = data.substr(w_start + 1, (w_end != data.npos) ? w_end - w_start - 1 : w_end); m_width = std::stof(data.substr(w_start + 1, (w_end != data.npos) ? w_end - w_start - 1 : w_end)); +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + m_width_compare.last_tag_value = m_width; +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING } catch (...) { BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Width (" << comment << ")."; @@ -1146,7 +1192,7 @@ bool GCodeProcessor::process_simplify3d_tags(const std::string& comment) return true; } - std::cout << comment << "\n"; +// std::cout << comment << "\n"; return false; } @@ -1226,6 +1272,9 @@ bool GCodeProcessor::process_ideamaker_tags(const std::string& comment) if (pos != comment.npos) { try { m_width = std::stof(comment.substr(pos + tag.length())); +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + m_width_compare.last_tag_value = m_width; +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING } catch (...) { BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Width (" << comment << ")."; @@ -1239,6 +1288,9 @@ bool GCodeProcessor::process_ideamaker_tags(const std::string& comment) if (pos != comment.npos) { try { m_height = std::stof(comment.substr(pos + tag.length())); +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + m_height_compare.last_tag_value = m_height; +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING } catch (...) { BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Height (" << comment << ")."; @@ -1327,19 +1379,29 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) return; EMoveType type = move_type(delta_pos); + if (type == EMoveType::Extrude && m_end_position[Z] == 0.0f) + type = EMoveType::Travel; if (type == EMoveType::Extrude) { - if (delta_pos[E] > 0.0f) { - float ds = std::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z])); - if (ds > 0.0f && static_cast(m_extruder_id) < m_filament_diameters.size()) { - // extruded filament volume / tool displacement - m_mm3_per_mm = round_to_nearest(static_cast(M_PI * sqr(m_filament_diameters[m_extruder_id]) * 0.25) * delta_pos[E] / ds, 4); - } + float d_xyz = std::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z])); + float filament_diameter = (static_cast(m_extruder_id) < m_filament_diameters.size()) ? m_filament_diameters[m_extruder_id] : m_filament_diameters.back(); + float filament_radius = 0.5f * filament_diameter; + float area_filament_cross_section = static_cast(M_PI) * sqr(filament_radius); + float volume_extruded_filament = area_filament_cross_section * delta_pos[E]; + float area_toolpath_cross_section = volume_extruded_filament / d_xyz; - if (m_end_position[Z] > m_extruded_last_z + EPSILON) { - m_height = round_to_nearest(m_end_position[Z] - m_extruded_last_z, 4); - m_extruded_last_z = m_end_position[Z]; - } + // volume extruded filament / tool displacement = area toolpath cross section + m_mm3_per_mm = round_to_nearest(area_toolpath_cross_section, 3); +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + m_mm3_per_mm_compare.update(area_toolpath_cross_section, m_extrusion_role); +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING + + if (m_end_position[Z] > m_extruded_last_z + EPSILON) { + m_height = round_to_nearest(m_end_position[Z] - m_extruded_last_z, 4); +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + m_height_compare.update(m_height, m_extrusion_role); +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING + m_extruded_last_z = m_end_position[Z]; } } @@ -1368,7 +1430,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) assert(distance != 0.0f); float inv_distance = 1.0f / distance; - for (size_t i = 0; i < static_cast(ETimeMode::Count); ++i) { + for (size_t i = 0; i < static_cast(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) { TimeMachine& machine = m_time_processor.machines[i]; if (!machine.enabled) continue; @@ -1378,8 +1440,8 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) std::vector& blocks = machine.blocks; curr.feedrate = (delta_pos[E] == 0.0f) ? - minimum_travel_feedrate(static_cast(i), m_feedrate) : - minimum_feedrate(static_cast(i), m_feedrate); + minimum_travel_feedrate(static_cast(i), m_feedrate) : + minimum_feedrate(static_cast(i), m_feedrate); TimeBlock block; block.move_type = type; @@ -1395,7 +1457,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) curr.abs_axis_feedrate[a] = std::abs(curr.axis_feedrate[a]); if (curr.abs_axis_feedrate[a] != 0.0f) { - float axis_max_feedrate = get_axis_max_feedrate(static_cast(i), static_cast(a)); + float axis_max_feedrate = get_axis_max_feedrate(static_cast(i), static_cast(a)); if (axis_max_feedrate != 0.0f) min_feedrate_factor = std::min(min_feedrate_factor, axis_max_feedrate / curr.abs_axis_feedrate[a]); } @@ -1412,11 +1474,11 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) // calculates block acceleration float acceleration = is_extrusion_only_move(delta_pos) ? - get_retract_acceleration(static_cast(i)) : - get_acceleration(static_cast(i)); + get_retract_acceleration(static_cast(i)) : + get_acceleration(static_cast(i)); for (unsigned char a = X; a <= E; ++a) { - float axis_max_acceleration = get_axis_max_acceleration(static_cast(i), static_cast(a)); + float axis_max_acceleration = get_axis_max_acceleration(static_cast(i), static_cast(a)); if (acceleration * std::abs(delta_pos[a]) * inv_distance > axis_max_acceleration) acceleration = axis_max_acceleration; } @@ -1427,7 +1489,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) curr.safe_feedrate = block.feedrate_profile.cruise; for (unsigned char a = X; a <= E; ++a) { - float axis_max_jerk = get_axis_max_jerk(static_cast(i), static_cast(a)); + float axis_max_jerk = get_axis_max_jerk(static_cast(i), static_cast(a)); if (curr.abs_axis_feedrate[a] > axis_max_jerk) curr.safe_feedrate = std::min(curr.safe_feedrate, axis_max_jerk); } @@ -1475,7 +1537,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) // axis reversal std::max(-v_exit, v_entry)); - float axis_max_jerk = get_axis_max_jerk(static_cast(i), static_cast(a)); + float axis_max_jerk = get_axis_max_jerk(static_cast(i), static_cast(a)); if (jerk > axis_max_jerk) { v_factor *= axis_max_jerk / jerk; limited = true; @@ -1689,7 +1751,7 @@ void GCodeProcessor::process_M201(const GCodeReader::GCodeLine& line) // see http://reprap.org/wiki/G-code#M201:_Set_max_printing_acceleration float factor = (m_flavor != gcfRepRap && m_units == EUnits::Inches) ? INCHES_TO_MM : 1.0f; - for (size_t i = 0; i < static_cast(ETimeMode::Count); ++i) { + for (size_t i = 0; i < static_cast(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) { if (line.has_x()) set_option_value(m_time_processor.machine_limits.machine_max_acceleration_x, i, line.x() * factor); @@ -1717,7 +1779,7 @@ void GCodeProcessor::process_M203(const GCodeReader::GCodeLine& line) // http://smoothieware.org/supported-g-codes float factor = (m_flavor == gcfMarlin || m_flavor == gcfSmoothie) ? 1.0f : MMMIN_TO_MMSEC; - for (size_t i = 0; i < static_cast(ETimeMode::Count); ++i) { + for (size_t i = 0; i < static_cast(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) { if (line.has_x()) set_option_value(m_time_processor.machine_limits.machine_max_feedrate_x, i, line.x() * factor); @@ -1738,19 +1800,19 @@ void GCodeProcessor::process_M204(const GCodeReader::GCodeLine& line) return; float value; - for (size_t i = 0; i < static_cast(ETimeMode::Count); ++i) { + for (size_t i = 0; i < static_cast(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) { if (line.has_value('S', value)) { // Legacy acceleration format. This format is used by the legacy Marlin, MK2 or MK3 firmware, // and it is also generated by Slic3r to control acceleration per extrusion type // (there is a separate acceleration settings in Slicer for perimeter, first layer etc). - set_acceleration(static_cast(i), value); + set_acceleration(static_cast(i), value); if (line.has_value('T', value)) set_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, i, value); } else { // New acceleration format, compatible with the upstream Marlin. if (line.has_value('P', value)) - set_acceleration(static_cast(i), value); + set_acceleration(static_cast(i), value); if (line.has_value('R', value)) set_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, i, value); if (line.has_value('T', value)) { @@ -1767,7 +1829,7 @@ void GCodeProcessor::process_M205(const GCodeReader::GCodeLine& line) if (!m_time_processor.machine_envelope_processing_enabled) return; - for (size_t i = 0; i < static_cast(ETimeMode::Count); ++i) { + for (size_t i = 0; i < static_cast(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) { if (line.has_x()) { float max_jerk = line.x(); set_option_value(m_time_processor.machine_limits.machine_max_jerk_x, i, max_jerk); @@ -1798,7 +1860,7 @@ void GCodeProcessor::process_M221(const GCodeReader::GCodeLine& line) float value_t; if (line.has_value('S', value_s) && !line.has_value('T', value_t)) { value_s *= 0.01f; - for (size_t i = 0; i < static_cast(ETimeMode::Count); ++i) { + for (size_t i = 0; i < static_cast(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) { m_time_processor.machines[i].extrude_factor_override_percentage = value_s; } } @@ -1849,7 +1911,7 @@ void GCodeProcessor::process_M402(const GCodeReader::GCodeLine& line) void GCodeProcessor::process_M566(const GCodeReader::GCodeLine& line) { - for (size_t i = 0; i < static_cast(ETimeMode::Count); ++i) { + for (size_t i = 0; i < static_cast(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) { if (line.has_x()) set_option_value(m_time_processor.machine_limits.machine_max_jerk_x, i, line.x() * MMMIN_TO_MMSEC); @@ -1930,7 +1992,7 @@ void GCodeProcessor::store_move_vertex(EMoveType type) m_result.moves.emplace_back(vertex); } -float GCodeProcessor::minimum_feedrate(ETimeMode mode, float feedrate) const +float GCodeProcessor::minimum_feedrate(PrintEstimatedTimeStatistics::ETimeMode mode, float feedrate) const { if (m_time_processor.machine_limits.machine_min_extruding_rate.empty()) return feedrate; @@ -1938,7 +2000,7 @@ float GCodeProcessor::minimum_feedrate(ETimeMode mode, float feedrate) const return std::max(feedrate, get_option_value(m_time_processor.machine_limits.machine_min_extruding_rate, static_cast(mode))); } -float GCodeProcessor::minimum_travel_feedrate(ETimeMode mode, float feedrate) const +float GCodeProcessor::minimum_travel_feedrate(PrintEstimatedTimeStatistics::ETimeMode mode, float feedrate) const { if (m_time_processor.machine_limits.machine_min_travel_rate.empty()) return feedrate; @@ -1946,7 +2008,7 @@ float GCodeProcessor::minimum_travel_feedrate(ETimeMode mode, float feedrate) co return std::max(feedrate, get_option_value(m_time_processor.machine_limits.machine_min_travel_rate, static_cast(mode))); } -float GCodeProcessor::get_axis_max_feedrate(ETimeMode mode, Axis axis) const +float GCodeProcessor::get_axis_max_feedrate(PrintEstimatedTimeStatistics::ETimeMode mode, Axis axis) const { switch (axis) { @@ -1958,7 +2020,7 @@ float GCodeProcessor::get_axis_max_feedrate(ETimeMode mode, Axis axis) const } } -float GCodeProcessor::get_axis_max_acceleration(ETimeMode mode, Axis axis) const +float GCodeProcessor::get_axis_max_acceleration(PrintEstimatedTimeStatistics::ETimeMode mode, Axis axis) const { switch (axis) { @@ -1970,7 +2032,7 @@ float GCodeProcessor::get_axis_max_acceleration(ETimeMode mode, Axis axis) const } } -float GCodeProcessor::get_axis_max_jerk(ETimeMode mode, Axis axis) const +float GCodeProcessor::get_axis_max_jerk(PrintEstimatedTimeStatistics::ETimeMode mode, Axis axis) const { switch (axis) { @@ -1982,18 +2044,18 @@ float GCodeProcessor::get_axis_max_jerk(ETimeMode mode, Axis axis) const } } -float GCodeProcessor::get_retract_acceleration(ETimeMode mode) const +float GCodeProcessor::get_retract_acceleration(PrintEstimatedTimeStatistics::ETimeMode mode) const { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, static_cast(mode)); } -float GCodeProcessor::get_acceleration(ETimeMode mode) const +float GCodeProcessor::get_acceleration(PrintEstimatedTimeStatistics::ETimeMode mode) const { size_t id = static_cast(mode); return (id < m_time_processor.machines.size()) ? m_time_processor.machines[id].acceleration : DEFAULT_ACCELERATION; } -void GCodeProcessor::set_acceleration(ETimeMode mode, float value) +void GCodeProcessor::set_acceleration(PrintEstimatedTimeStatistics::ETimeMode mode, float value) { size_t id = static_cast(mode); if (id < m_time_processor.machines.size()) { @@ -2021,7 +2083,7 @@ float GCodeProcessor::get_filament_unload_time(size_t extruder_id) void GCodeProcessor::process_custom_gcode_time(CustomGCode::Type code) { - for (size_t i = 0; i < static_cast(ETimeMode::Count); ++i) { + for (size_t i = 0; i < static_cast(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) { TimeMachine& machine = m_time_processor.machines[i]; if (!machine.enabled) continue; @@ -2040,14 +2102,14 @@ void GCodeProcessor::process_custom_gcode_time(CustomGCode::Type code) void GCodeProcessor::simulate_st_synchronize(float additional_time) { - for (size_t i = 0; i < static_cast(ETimeMode::Count); ++i) { + for (size_t i = 0; i < static_cast(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) { m_time_processor.machines[i].simulate_st_synchronize(additional_time); } } void GCodeProcessor::update_estimated_times_stats() { - auto update_mode = [this](GCodeProcessor::ETimeMode mode) { + auto update_mode = [this](PrintEstimatedTimeStatistics::ETimeMode mode) { PrintEstimatedTimeStatistics::Mode& data = m_result.time_statistics.modes[static_cast(mode)]; data.time = get_time(mode); data.custom_gcode_times = get_custom_gcode_times(mode, true); @@ -2055,11 +2117,11 @@ void GCodeProcessor::update_estimated_times_stats() data.roles_times = get_roles_time(mode); }; - update_mode(GCodeProcessor::ETimeMode::Normal); - if (m_time_processor.machines[static_cast(GCodeProcessor::ETimeMode::Stealth)].enabled) - update_mode(GCodeProcessor::ETimeMode::Stealth); + update_mode(PrintEstimatedTimeStatistics::ETimeMode::Normal); + if (m_time_processor.machines[static_cast(PrintEstimatedTimeStatistics::ETimeMode::Stealth)].enabled) + update_mode(PrintEstimatedTimeStatistics::ETimeMode::Stealth); else - m_result.time_statistics.modes[static_cast(GCodeProcessor::ETimeMode::Stealth)].reset(); + m_result.time_statistics.modes[static_cast(PrintEstimatedTimeStatistics::ETimeMode::Stealth)].reset(); } } /* namespace Slic3r */ diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index f103bab96..166e1b8cc 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -76,6 +76,10 @@ namespace Slic3r { static const std::string Last_Line_M73_Placeholder_Tag; static const std::string Estimated_Printing_Time_Placeholder_Tag; +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + static const std::string Mm3_Per_Mm_Tag; +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING + private: using AxisCoords = std::array; using ExtruderColors = std::vector; @@ -152,13 +156,6 @@ namespace Slic3r { float time() const; }; - enum class ETimeMode : unsigned char - { - Normal, - Stealth, - Count - }; - private: struct TimeMachine { @@ -227,7 +224,7 @@ namespace Slic3r { // Additional load / unload times for a filament exchange sequence. std::vector filament_load_times; std::vector filament_unload_times; - std::array(ETimeMode::Count)> machines; + std::array(PrintEstimatedTimeStatistics::ETimeMode::Count)> machines; void reset(); @@ -281,6 +278,72 @@ namespace Slic3r { #endif // ENABLE_GCODE_VIEWER_STATISTICS }; +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + struct DataChecker + { + struct Error + { + float value; + float tag_value; + ExtrusionRole role; + }; + + std::string type; + float threshold{ 0.01f }; + float last_tag_value{ 0.0f }; + unsigned int count{ 0 }; + std::vector errors; + + DataChecker(const std::string& type, float threshold) + : type(type), threshold(threshold) + {} + + void update(float value, ExtrusionRole role) { + ++count; + if (last_tag_value != 0.0f) { + if (std::abs(value - last_tag_value) / last_tag_value > threshold) + errors.push_back({ value, last_tag_value, role }); + } + } + + void reset() { last_tag_value = 0.0f; errors.clear(); count = 0; } + + std::pair get_min() const { + float delta_min = FLT_MAX; + float perc_min = 0.0f; + for (const Error& e : errors) { + if (delta_min > e.value - e.tag_value) { + delta_min = e.value - e.tag_value; + perc_min = 100.0f * delta_min / e.tag_value; + } + } + return { delta_min, perc_min }; + } + + std::pair get_max() const { + float delta_max = -FLT_MAX; + float perc_max = 0.0f; + for (const Error& e : errors) { + if (delta_max < e.value - e.tag_value) { + delta_max = e.value - e.tag_value; + perc_max = 100.0f * delta_max / e.tag_value; + } + } + return { delta_max, perc_max }; + } + + void output() const { + if (!errors.empty()) { + std::cout << type << ":\n"; + std::cout << "Errors: " << errors.size() << " (" << 100.0f * float(errors.size()) / float(count) << "%)\n"; + auto [min, perc_min] = get_min(); + auto [max, perc_max] = get_max(); + std::cout << "min: " << min << "(" << perc_min << "%) - max: " << max << "(" << perc_max << "%)\n"; + } + } + }; +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING + private: GCodeReader m_parser; @@ -326,6 +389,12 @@ namespace Slic3r { Result m_result; static unsigned int s_result_id; +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + DataChecker m_mm3_per_mm_compare{ "mm3_per_mm", 0.01f }; + DataChecker m_height_compare{ "height", 0.01f }; + DataChecker m_width_compare{ "width", 0.01f }; +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING + public: GCodeProcessor(); @@ -333,7 +402,7 @@ namespace Slic3r { void apply_config(const DynamicPrintConfig& config); void enable_stealth_time_estimator(bool enabled); bool is_stealth_time_estimator_enabled() const { - return m_time_processor.machines[static_cast(ETimeMode::Stealth)].enabled; + return m_time_processor.machines[static_cast(PrintEstimatedTimeStatistics::ETimeMode::Stealth)].enabled; } void enable_machine_envelope_processing(bool enabled) { m_time_processor.machine_envelope_processing_enabled = enabled; } void enable_producers(bool enabled) { m_producers_enabled = enabled; } @@ -345,12 +414,12 @@ namespace Slic3r { // Process the gcode contained in the file with the given filename void process_file(const std::string& filename); - float get_time(ETimeMode mode) const; - std::string get_time_dhm(ETimeMode mode) const; - std::vector>> get_custom_gcode_times(ETimeMode mode, bool include_remaining) const; + float get_time(PrintEstimatedTimeStatistics::ETimeMode mode) const; + std::string get_time_dhm(PrintEstimatedTimeStatistics::ETimeMode mode) const; + std::vector>> get_custom_gcode_times(PrintEstimatedTimeStatistics::ETimeMode mode, bool include_remaining) const; - std::vector> get_moves_time(ETimeMode mode) const; - std::vector> get_roles_time(ETimeMode mode) const; + std::vector> get_moves_time(PrintEstimatedTimeStatistics::ETimeMode mode) const; + std::vector> get_roles_time(PrintEstimatedTimeStatistics::ETimeMode mode) const; private: void process_gcode_line(const GCodeReader::GCodeLine& line); @@ -454,14 +523,14 @@ namespace Slic3r { void store_move_vertex(EMoveType type); - float minimum_feedrate(ETimeMode mode, float feedrate) const; - float minimum_travel_feedrate(ETimeMode mode, float feedrate) const; - float get_axis_max_feedrate(ETimeMode mode, Axis axis) const; - float get_axis_max_acceleration(ETimeMode mode, Axis axis) const; - float get_axis_max_jerk(ETimeMode mode, Axis axis) const; - float get_retract_acceleration(ETimeMode mode) const; - float get_acceleration(ETimeMode mode) const; - void set_acceleration(ETimeMode mode, float value); + float minimum_feedrate(PrintEstimatedTimeStatistics::ETimeMode mode, float feedrate) const; + float minimum_travel_feedrate(PrintEstimatedTimeStatistics::ETimeMode mode, float feedrate) const; + float get_axis_max_feedrate(PrintEstimatedTimeStatistics::ETimeMode mode, Axis axis) const; + float get_axis_max_acceleration(PrintEstimatedTimeStatistics::ETimeMode mode, Axis axis) const; + float get_axis_max_jerk(PrintEstimatedTimeStatistics::ETimeMode mode, Axis axis) const; + float get_retract_acceleration(PrintEstimatedTimeStatistics::ETimeMode mode) const; + float get_acceleration(PrintEstimatedTimeStatistics::ETimeMode mode) const; + void set_acceleration(PrintEstimatedTimeStatistics::ETimeMode mode, float value); float get_filament_load_time(size_t extruder_id); float get_filament_unload_time(size_t extruder_id); diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index c20009a48..e6e60b618 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -84,6 +84,17 @@ public: return *this; } +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + WipeTowerWriter& change_analyzer_mm3_per_mm(float len, float e) { + static const float area = float(M_PI) * 1.75f * 1.75f / 4.f; + float mm3_per_mm = (len == 0.f ? 0.f : area * e / len); + // adds tag for processor: + char buf[64]; + sprintf(buf, ";%s%f\n", GCodeProcessor::Mm3_Per_Mm_Tag.c_str(), mm3_per_mm); + m_gcode += buf; + return *this; + } +#else #if !ENABLE_GCODE_VIEWER WipeTowerWriter& change_analyzer_mm3_per_mm(float len, float e) { static const float area = float(M_PI) * 1.75f * 1.75f / 4.f; @@ -95,6 +106,7 @@ public: return *this; } #endif // !ENABLE_GCODE_VIEWER +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING WipeTowerWriter& set_initial_position(const Vec2f &pos, float width = 0.f, float depth = 0.f, float internal_angle = 0.f) { m_wipe_tower_width = width; @@ -167,9 +179,13 @@ public: Vec2f rot(this->rotate(Vec2f(x,y))); // this is where we want to go if (! m_preview_suppressed && e > 0.f && len > 0.f) { +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + change_analyzer_mm3_per_mm(len, e); +#else #if !ENABLE_GCODE_VIEWER change_analyzer_mm3_per_mm(len, e); #endif // !ENABLE_GCODE_VIEWER +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING // Width of a squished extrusion, corrected for the roundings of the squished extrusions. // This is left zero if it is a travel move. float width = e * m_filpar[0].filament_area / (len * m_layer_height); diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 609aecf63..e10cabc6c 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -58,6 +58,7 @@ #define ENABLE_GCODE_VIEWER (1 && ENABLE_2_3_0_ALPHA1) #define ENABLE_GCODE_VIEWER_STATISTICS (0 && ENABLE_GCODE_VIEWER) #define ENABLE_GCODE_VIEWER_SHADERS_EDITOR (0 && ENABLE_GCODE_VIEWER) +#define ENABLE_GCODE_VIEWER_DATA_CHECKING (0 && ENABLE_GCODE_VIEWER) #define TIME_ESTIMATE_NONE 0 #define TIME_ESTIMATE_DEFAULT 1 diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index b7bd81a0f..17651fef3 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -975,8 +975,8 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) for (const TBuffer& buffer : m_buffers) { m_statistics.paths_size += SLIC3R_STDVEC_MEMSIZE(buffer.paths, Path); } - m_statistics.travel_segments_count = indices[buffer_id(GCodeProcessor::EMoveType::Travel)].size() / 2; - m_statistics.extrude_segments_count = indices[buffer_id(GCodeProcessor::EMoveType::Extrude)].size() / 2; + m_statistics.travel_segments_count = indices[buffer_id(EMoveType::Travel)].size() / 2; + m_statistics.extrude_segments_count = indices[buffer_id(EMoveType::Extrude)].size() / 2; #endif // ENABLE_GCODE_VIEWER_STATISTICS // layers zs / roles / extruder ids / cp color ids -> extract from result