diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index bb670905b..a0d072722 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -374,6 +374,7 @@ void GCodeProcessor::TimeProcessor::reset() machine_limits = MachineEnvelopeConfig(); filament_load_times = 0.0f; filament_unload_times = 0.0f; + extruder_change_times = 0.0f; for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { @@ -775,7 +776,7 @@ void GCodeProcessor::UsedFilaments::reset() volumes_per_color_change = std::vector(); model_extrude_cache = 0.0f; - model_volumes_per_extruder.clear(); + model_volumes_per_filament.clear(); flush_per_filament.clear(); @@ -783,13 +784,13 @@ void GCodeProcessor::UsedFilaments::reset() filaments_per_role.clear(); wipe_tower_cache = 0.0f; - wipe_tower_volumes_per_extruder.clear(); + wipe_tower_volumes_per_filament.clear(); support_volume_cache = 0.0f; - support_volumes_per_extruder.clear(); + support_volumes_per_filament.clear(); total_volume_cache = 0.0f; - total_volumes_per_extruder.clear(); + total_volumes_per_filament.clear(); } void GCodeProcessor::UsedFilaments::increase_support_caches(double extruded_volume) @@ -825,65 +826,64 @@ void GCodeProcessor::UsedFilaments::process_color_change_cache() void GCodeProcessor::UsedFilaments::process_total_volume_cache(GCodeProcessor* processor) { - size_t active_extruder_id = processor->m_extruder_id; + size_t active_filament_id = processor->get_filament_id(); if (total_volume_cache!= 0.0f) { - if (total_volumes_per_extruder.find(active_extruder_id) != total_volumes_per_extruder.end()) - total_volumes_per_extruder[active_extruder_id] += total_volume_cache; + if (total_volumes_per_filament.find(active_filament_id) != total_volumes_per_filament.end()) + total_volumes_per_filament[active_filament_id] += total_volume_cache; else - total_volumes_per_extruder[active_extruder_id] = total_volume_cache; + total_volumes_per_filament[active_filament_id] = total_volume_cache; total_volume_cache = 0.0f; } } void GCodeProcessor::UsedFilaments::process_model_cache(GCodeProcessor* processor) { - size_t active_extruder_id = processor->m_extruder_id; + size_t active_filament_id = processor->get_filament_id(); if (model_extrude_cache != 0.0f) { - if (model_volumes_per_extruder.find(active_extruder_id) != model_volumes_per_extruder.end()) - model_volumes_per_extruder[active_extruder_id] += model_extrude_cache; + if (model_volumes_per_filament.find(active_filament_id) != model_volumes_per_filament.end()) + model_volumes_per_filament[active_filament_id] += model_extrude_cache; else - model_volumes_per_extruder[active_extruder_id] = model_extrude_cache; + model_volumes_per_filament[active_filament_id] = model_extrude_cache; model_extrude_cache = 0.0f; } } void GCodeProcessor::UsedFilaments::process_wipe_tower_cache(GCodeProcessor* processor) { - size_t active_extruder_id = processor->m_extruder_id; + size_t active_filament_id = processor->get_filament_id(); if (wipe_tower_cache != 0.0f) { - if (wipe_tower_volumes_per_extruder.find(active_extruder_id) != wipe_tower_volumes_per_extruder.end()) - wipe_tower_volumes_per_extruder[active_extruder_id] += wipe_tower_cache; + if (wipe_tower_volumes_per_filament.find(active_filament_id) != wipe_tower_volumes_per_filament.end()) + wipe_tower_volumes_per_filament[active_filament_id] += wipe_tower_cache; else - wipe_tower_volumes_per_extruder[active_extruder_id] = wipe_tower_cache; + wipe_tower_volumes_per_filament[active_filament_id] = wipe_tower_cache; wipe_tower_cache = 0.0f; } } void GCodeProcessor::UsedFilaments::process_support_cache(GCodeProcessor* processor) { - size_t active_extruder_id = processor->m_extruder_id; + size_t active_filament_id = processor->get_filament_id(); if (support_volume_cache != 0.0f){ - if (support_volumes_per_extruder.find(active_extruder_id) != support_volumes_per_extruder.end()) - support_volumes_per_extruder[active_extruder_id] += support_volume_cache; + if (support_volumes_per_filament.find(active_filament_id) != support_volumes_per_filament.end()) + support_volumes_per_filament[active_filament_id] += support_volume_cache; else - support_volumes_per_extruder[active_extruder_id] = support_volume_cache; + support_volumes_per_filament[active_filament_id] = support_volume_cache; support_volume_cache = 0.0f; } } -void GCodeProcessor::UsedFilaments::update_flush_per_filament(size_t extrude_id, float flush_volume) +void GCodeProcessor::UsedFilaments::update_flush_per_filament(size_t filament_id, float flush_volume) { if (flush_volume != 0.f) { - role_cache += flush_volume; - if (flush_per_filament.find(extrude_id) != flush_per_filament.end()) - flush_per_filament[extrude_id] += flush_volume; + if (flush_per_filament.find(filament_id) != flush_per_filament.end()) + flush_per_filament[filament_id] += flush_volume; else - flush_per_filament[extrude_id] = flush_volume; + flush_per_filament[filament_id] = flush_volume; - if (total_volumes_per_extruder.find(extrude_id) != total_volumes_per_extruder.end()) - total_volumes_per_extruder[extrude_id] += flush_volume; + if (total_volumes_per_filament.find(filament_id) != total_volumes_per_filament.end()) + total_volumes_per_filament[filament_id] += flush_volume; else - total_volumes_per_extruder[extrude_id] = flush_volume; + total_volumes_per_filament[filament_id] = flush_volume; } } @@ -892,9 +892,9 @@ void GCodeProcessor::UsedFilaments::process_role_cache(GCodeProcessor* processor if (role_cache != 0.0f) { std::pair filament = { 0.0f, 0.0f }; - double s = PI * sqr(0.5 * processor->m_result.filament_diameters[processor->m_extruder_id]); + double s = PI * sqr(0.5 * processor->m_result.filament_diameters[processor->get_filament_id()]); filament.first = role_cache / s * 0.001; - filament.second = role_cache * processor->m_result.filament_densities[processor->m_extruder_id] * 0.001; + filament.second = role_cache * processor->m_result.filament_densities[processor->get_filament_id()] * 0.001; ExtrusionRole active_role = processor->m_extrusion_role; if (filaments_per_role.find(active_role) != filaments_per_role.end()) { @@ -962,7 +962,7 @@ void GCodeProcessorResult::reset() { timelapse_warning_code = 0; printable_height = 0.0f; settings_ids.reset(); - extruders_count = 0; + filaments_count = 0; extruder_colors = std::vector(); filament_diameters = std::vector(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER); required_nozzle_HRC = std::vector(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_HRC); @@ -1066,7 +1066,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config) // BBS size_t extruders_count = config.filament_diameter.values.size(); - m_result.extruders_count = extruders_count; + m_result.filaments_count = extruders_count; m_extruder_offsets.resize(extruders_count); m_extruder_colors.resize(extruders_count); @@ -1100,6 +1100,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config) // are considered to be active for the single extruder multi-material printers only. m_time_processor.filament_load_times = static_cast(config.machine_load_filament_time.value); m_time_processor.filament_unload_times = static_cast(config.machine_unload_filament_time.value); + m_time_processor.extruder_change_times = static_cast(config.machine_switch_extruder_time.value); for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { float max_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_extruding, i); @@ -1119,6 +1120,12 @@ void GCodeProcessor::apply_config(const PrintConfig& config) m_result.printable_height = config.printable_height; + auto filament_maps = config.option("filament_map"); + if (filament_maps != nullptr) { + m_filament_maps = filament_maps->values; + std::transform(m_filament_maps.begin(), m_filament_maps.end(), m_filament_maps.begin(), [](int value) {return value - 1; }); + } + const ConfigOptionBool* spiral_vase = config.option("spiral_mode"); if (spiral_vase != nullptr) m_detect_layer_based_on_tag = spiral_vase->value; @@ -1168,7 +1175,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) m_result.settings_ids.printer = printer_settings_id->value; // BBS - m_result.extruders_count = config.option("filament_diameter")->values.size(); + m_result.filaments_count = config.option("filament_diameter")->values.size(); const ConfigOptionFloats* filament_diameters = config.option("filament_diameter"); if (filament_diameters != nullptr) { @@ -1179,8 +1186,8 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) } } - if (m_result.filament_diameters.size() < m_result.extruders_count) { - for (size_t i = m_result.filament_diameters.size(); i < m_result.extruders_count; ++i) { + if (m_result.filament_diameters.size() < m_result.filaments_count) { + for (size_t i = m_result.filament_diameters.size(); i < m_result.filaments_count; ++i) { m_result.filament_diameters.emplace_back(DEFAULT_FILAMENT_DIAMETER); } } @@ -1192,8 +1199,8 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) for (size_t i = 0; i < filament_HRC->values.size(); ++i) { m_result.required_nozzle_HRC[i] = static_cast(filament_HRC->values[i]); } } - if (m_result.required_nozzle_HRC.size() < m_result.extruders_count) { - for (size_t i = m_result.required_nozzle_HRC.size(); i < m_result.extruders_count; ++i) { m_result.required_nozzle_HRC.emplace_back(DEFAULT_FILAMENT_HRC); + if (m_result.required_nozzle_HRC.size() < m_result.filaments_count) { + for (size_t i = m_result.required_nozzle_HRC.size(); i < m_result.filaments_count; ++i) { m_result.required_nozzle_HRC.emplace_back(DEFAULT_FILAMENT_HRC); } } @@ -1206,12 +1213,18 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) } } - if (m_result.filament_densities.size() < m_result.extruders_count) { - for (size_t i = m_result.filament_densities.size(); i < m_result.extruders_count; ++i) { + if (m_result.filament_densities.size() < m_result.filaments_count) { + for (size_t i = m_result.filament_densities.size(); i < m_result.filaments_count; ++i) { m_result.filament_densities.emplace_back(DEFAULT_FILAMENT_DENSITY); } } + auto filament_maps = config.option("filament_map"); + if (filament_maps != nullptr) { + m_filament_maps = filament_maps->values; + std::transform(m_filament_maps.begin(), m_filament_maps.end(), m_filament_maps.begin(), [](int value) {return value - 1; }); + } + //BBS const ConfigOptionFloats* filament_costs = config.option("filament_cost"); if (filament_costs != nullptr) { @@ -1220,7 +1233,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) for (size_t i = 0; i < filament_costs->values.size(); ++i) m_result.filament_costs[i]=static_cast(filament_costs->values[i]); } - for (size_t i = m_result.filament_costs.size(); i < m_result.extruders_count; ++i) { + for (size_t i = m_result.filament_costs.size(); i < m_result.filaments_count; ++i) { m_result.filament_costs.emplace_back(DEFAULT_FILAMENT_COST); } @@ -1233,8 +1246,8 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) m_result.filament_vitrification_temperature[i] = static_cast(filament_vitrification_temperature->values[i]); } } - if (m_result.filament_vitrification_temperature.size() < m_result.extruders_count) { - for (size_t i = m_result.filament_vitrification_temperature.size(); i < m_result.extruders_count; ++i) { + if (m_result.filament_vitrification_temperature.size() < m_result.filaments_count) { + for (size_t i = m_result.filament_vitrification_temperature.size(); i < m_result.filaments_count; ++i) { m_result.filament_vitrification_temperature.emplace_back(DEFAULT_FILAMENT_VITRIFICATION_TEMPERATURE); } } @@ -1245,8 +1258,8 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) //BBS: for single extruder multi material, only use the offset of first extruder if (single_extruder_multi_material != nullptr && single_extruder_multi_material->getBool()) { Vec2f offset = extruder_offset->values[0].cast(); - m_extruder_offsets.resize(m_result.extruders_count); - for (size_t i = 0; i < m_result.extruders_count; ++i) { + m_extruder_offsets.resize(m_result.filaments_count); + for (size_t i = 0; i < m_result.filaments_count; ++i) { m_extruder_offsets[i] = { offset(0), offset(1), 0.0f }; } } @@ -1259,8 +1272,8 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) } } - if (m_extruder_offsets.size() < m_result.extruders_count) { - for (size_t i = m_extruder_offsets.size(); i < m_result.extruders_count; ++i) { + if (m_extruder_offsets.size() < m_result.filaments_count) { + for (size_t i = m_extruder_offsets.size(); i < m_result.filaments_count; ++i) { m_extruder_offsets.emplace_back(DEFAULT_EXTRUDER_OFFSET); } } @@ -1274,8 +1287,8 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) } } - if (m_result.extruder_colors.size() < m_result.extruders_count) { - for (size_t i = m_result.extruder_colors.size(); i < m_result.extruders_count; ++i) { + if (m_result.extruder_colors.size() < m_result.filaments_count) { + for (size_t i = m_result.extruder_colors.size(); i < m_result.filaments_count; ++i) { m_result.extruder_colors.emplace_back(std::string()); } } @@ -1291,7 +1304,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) m_extruder_colors[i] = static_cast(i); } - m_extruder_temps.resize(m_result.extruders_count); + m_extruder_temps.resize(m_result.filaments_count); const ConfigOptionFloat* machine_load_filament_time = config.option("machine_load_filament_time"); if (machine_load_filament_time != nullptr) @@ -1301,6 +1314,10 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) if (machine_unload_filament_time != nullptr) m_time_processor.filament_unload_times = static_cast(machine_unload_filament_time->value); + const ConfigOptionFloat* machine_switch_extruder_time = config.option("machine_switch_extruder_time"); + if (machine_switch_extruder_time != nullptr) + m_time_processor.extruder_change_times = static_cast(machine_switch_extruder_time->value); + if (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfKlipper) { const ConfigOptionFloats* machine_max_acceleration_x = config.option("machine_max_acceleration_x"); if (machine_max_acceleration_x != nullptr) @@ -1455,8 +1472,10 @@ void GCodeProcessor::reset() m_fan_speed = 0.0f; m_extrusion_role = erNone; - m_extruder_id = 0; - m_last_extruder_id = 0; + + m_filament_id = {static_cast(-1),static_cast(-1)}; + m_last_filament_id = {static_cast(-1),static_cast(-1) }; + m_extruder_id = static_cast(-1); m_extruder_colors.resize(MIN_EXTRUDERS_COUNT); for (size_t i = 0; i < MIN_EXTRUDERS_COUNT; ++i) { m_extruder_colors[i] = static_cast(i); @@ -1816,7 +1835,7 @@ void GCodeProcessor::apply_config_simplify3d(const std::string& filename) } else if (comment.find("extruderDiameter") != comment.npos) { std::vector extruder_diameters; extract_floats(comment, "extruderDiameter", extruder_diameters); - m_result.extruders_count = extruder_diameters.size(); + m_result.filaments_count = extruder_diameters.size(); } } else if (boost::starts_with(comment, "G-Code generated by Simplify3D(R)")) producer_detected = true; @@ -1828,8 +1847,8 @@ void GCodeProcessor::apply_config_simplify3d(const std::string& filename) } }); - if (m_result.extruders_count == 0) - m_result.extruders_count = std::max(1, std::min(m_result.filament_diameters.size(), m_result.filament_densities.size())); + if (m_result.filaments_count == 0) + m_result.filaments_count = std::max(1, std::min(m_result.filament_diameters.size(), m_result.filament_densities.size())); if (bed_size.is_defined()) { m_result.printable_area = { @@ -2282,7 +2301,7 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers // color change tag if (boost::starts_with(comment, reserved_tag(ETags::Color_Change))) { - unsigned char extruder_id = 0; + unsigned char filament_id = 0; static std::vector Default_Colors = { "#0B2C7A", // { 0.043f, 0.173f, 0.478f }, // bluish "#1C8891", // { 0.110f, 0.533f, 0.569f }, @@ -2318,7 +2337,7 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Color_Change (" << comment << ")."; return; } - extruder_id = static_cast(eid); + filament_id = static_cast(eid); } } if (tokens.size() > 2) { @@ -2332,16 +2351,16 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers m_last_default_color_id = 0; } - if (extruder_id < m_extruder_colors.size()) - m_extruder_colors[extruder_id] = static_cast(m_extruder_offsets.size()) + m_cp_color.counter; // color_change position in list of color for preview + if (filament_id < m_extruder_colors.size()) + m_extruder_colors[filament_id] = static_cast(m_extruder_offsets.size()) + m_cp_color.counter; // color_change position in list of color for preview ++m_cp_color.counter; if (m_cp_color.counter == UCHAR_MAX) m_cp_color.counter = 0; - if (m_extruder_id == extruder_id) { - m_cp_color.current = m_extruder_colors[extruder_id]; + if (get_filament_id() == filament_id) { + m_cp_color.current = m_extruder_colors[filament_id]; store_move_vertex(EMoveType::Color_change); - CustomGCode::Item item = { static_cast(m_end_position[2]), CustomGCode::ColorChange, extruder_id + 1, color, "" }; + CustomGCode::Item item = { static_cast(m_end_position[2]), CustomGCode::ColorChange, filament_id + 1, color, "" }; m_result.custom_gcode_per_print_z.emplace_back(item); m_options_z_corrector.set(); process_custom_gcode_time(CustomGCode::ColorChange); @@ -2354,7 +2373,7 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers // pause print tag if (comment == reserved_tag(ETags::Pause_Print)) { store_move_vertex(EMoveType::Pause_Print); - CustomGCode::Item item = { static_cast(m_end_position[2]), CustomGCode::PausePrint, m_extruder_id + 1, "", "" }; + CustomGCode::Item item = { static_cast(m_end_position[2]), CustomGCode::PausePrint, get_filament_id() + 1, "", ""}; m_result.custom_gcode_per_print_z.emplace_back(item); m_options_z_corrector.set(); process_custom_gcode_time(CustomGCode::PausePrint); @@ -2364,7 +2383,7 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers // custom code tag if (comment == reserved_tag(ETags::Custom_Code)) { store_move_vertex(EMoveType::Custom_GCode); - CustomGCode::Item item = { static_cast(m_end_position[2]), CustomGCode::Custom, m_extruder_id + 1, "", "" }; + CustomGCode::Item item = { static_cast(m_end_position[2]), CustomGCode::Custom, get_filament_id() + 1, "", ""}; m_result.custom_gcode_per_print_z.emplace_back(item); m_options_z_corrector.set(); return; @@ -2875,7 +2894,9 @@ void GCodeProcessor::process_G0(const GCodeReader::GCodeLine& line) void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) { - float filament_diameter = (static_cast(m_extruder_id) < m_result.filament_diameters.size()) ? m_result.filament_diameters[m_extruder_id] : m_result.filament_diameters.back(); + int filament_id = get_filament_id(); + int last_filament_id = get_last_filament_id(); + float filament_diameter = (static_cast(filament_id) < m_result.filament_diameters.size()) ? m_result.filament_diameters[filament_id] : m_result.filament_diameters.back(); float filament_radius = 0.5f * filament_diameter; float area_filament_cross_section = static_cast(M_PI) * sqr(filament_radius); auto absolute_position = [this, area_filament_cross_section](Axis axis, const GCodeReader::GCodeLine& lineG1) { @@ -2985,7 +3006,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) m_width = delta_pos[E] * static_cast(M_PI * sqr(1.05f * filament_radius)) / (delta_xyz * m_height); else if (m_extrusion_role == erBridgeInfill || m_extrusion_role == erNone) // cross section: circle - m_width = static_cast(m_result.filament_diameters[m_extruder_id]) * std::sqrt(delta_pos[E] / delta_xyz); + m_width = static_cast(m_result.filament_diameters[filament_id]) * std::sqrt(delta_pos[E] / delta_xyz); else // cross section: rectangle + 2 semicircles m_width = delta_pos[E] * static_cast(M_PI * sqr(filament_radius)) / (delta_xyz * m_height) + static_cast(1.0 - 0.25 * M_PI) * m_height; @@ -3004,12 +3025,12 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) float volume_flushed_filament = area_filament_cross_section * delta_pos[E]; if (m_remaining_volume > volume_flushed_filament) { - m_used_filaments.update_flush_per_filament(m_last_extruder_id, volume_flushed_filament); + m_used_filaments.update_flush_per_filament(last_filament_id, volume_flushed_filament); m_remaining_volume -= volume_flushed_filament; } else { - m_used_filaments.update_flush_per_filament(m_last_extruder_id, m_remaining_volume); - m_used_filaments.update_flush_per_filament(m_extruder_id, volume_flushed_filament - m_remaining_volume); + m_used_filaments.update_flush_per_filament(last_filament_id, m_remaining_volume); + m_used_filaments.update_flush_per_filament(filament_id, volume_flushed_filament - m_remaining_volume); m_remaining_volume = 0.f; } } @@ -3027,7 +3048,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) float distance = move_length(delta_pos); assert(distance != 0.0f); float inv_distance = 1.0f / distance; - int matched_extruder_id = extruder_id(m_extruder_id); + for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { TimeMachine& machine = m_time_processor.machines[i]; if (!machine.enabled) @@ -3092,7 +3113,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), matched_extruder_id); + float axis_max_feedrate = get_axis_max_feedrate(static_cast(i), static_cast(a), m_extruder_id); if (axis_max_feedrate != 0.0f) min_feedrate_factor = std::min(min_feedrate_factor, axis_max_feedrate / curr.abs_axis_feedrate[a]); } } @@ -3116,7 +3137,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) //BBS for (unsigned char a = X; a <= E; ++a) { - float axis_max_acceleration = get_axis_max_acceleration(static_cast(i), static_cast(a), matched_extruder_id); + float axis_max_acceleration = get_axis_max_acceleration(static_cast(i), static_cast(a), m_extruder_id); if (acceleration * std::abs(delta_pos[a]) * inv_distance > axis_max_acceleration) acceleration = axis_max_acceleration / (std::abs(delta_pos[a]) * inv_distance); } @@ -3244,11 +3265,11 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter && !m_seams_detector.has_first_vertex()) { //BBS: m_result.moves.back().position has plate offset, must minus plate offset before calculate the real seam position const Vec3f real_first_pos = Vec3f(m_result.moves.back().position.x() - m_x_offset, m_result.moves.back().position.y() - m_y_offset, m_result.moves.back().position.z()); - m_seams_detector.set_first_vertex(real_first_pos - m_extruder_offsets[m_extruder_id]); + m_seams_detector.set_first_vertex(real_first_pos - m_extruder_offsets[filament_id]); } else if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter && m_detect_layer_based_on_tag) { const Vec3f real_last_pos = Vec3f(m_result.moves.back().position.x() - m_x_offset, m_result.moves.back().position.y() - m_y_offset, m_result.moves.back().position.z()); - const Vec3f new_pos = real_last_pos - m_extruder_offsets[m_extruder_id]; + const Vec3f new_pos = real_last_pos - m_extruder_offsets[filament_id]; // We may have sloped loop, drop any previous start pos if we have z increment const std::optional first_vertex = m_seams_detector.get_first_vertex(); if (new_pos.z() > first_vertex->z()) { @@ -3264,7 +3285,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) const Vec3f curr_pos(m_end_position[X], m_end_position[Y], m_end_position[Z]); //BBS: m_result.moves.back().position has plate offset, must minus plate offset before calculate the real seam position const Vec3f real_last_pos = Vec3f(m_result.moves.back().position.x() - m_x_offset, m_result.moves.back().position.y() - m_y_offset, m_result.moves.back().position.z()); - const Vec3f new_pos = real_last_pos - m_extruder_offsets[m_extruder_id]; + const Vec3f new_pos = real_last_pos - m_extruder_offsets[filament_id]; const std::optional first_vertex = m_seams_detector.get_first_vertex(); // the threshold value = 0.0625f == 0.25 * 0.25 is arbitrary, we may find some smarter condition later @@ -3280,7 +3301,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) else if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter) { m_seams_detector.activate(true); Vec3f plate_offset = {(float) m_x_offset, (float) m_y_offset, 0.0f}; - m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset); + m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[filament_id] - plate_offset); } if (m_detect_layer_based_on_tag && !m_result.spiral_vase_layers.empty()) { @@ -3304,7 +3325,8 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) // BBS: this function is absolutely new for G2 and G3 gcode void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line) { - float filament_diameter = (static_cast(m_extruder_id) < m_result.filament_diameters.size()) ? m_result.filament_diameters[m_extruder_id] : m_result.filament_diameters.back(); + int filament_id = get_filament_id(); + float filament_diameter = (static_cast(filament_id) < m_result.filament_diameters.size()) ? m_result.filament_diameters[filament_id] : m_result.filament_diameters.back(); float filament_radius = 0.5f * filament_diameter; float area_filament_cross_section = static_cast(M_PI) * sqr(filament_radius); auto absolute_position = [this, area_filament_cross_section](Axis axis, const GCodeReader::GCodeLine& lineG2_3) { @@ -3465,7 +3487,7 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line) m_width = delta_pos[E] * static_cast(M_PI * sqr(1.05f * filament_radius)) / (delta_xyz * m_height); else if (m_extrusion_role == erBridgeInfill || m_extrusion_role == erNone) //BBS: cross section: circle - m_width = static_cast(m_result.filament_diameters[m_extruder_id]) * std::sqrt(delta_pos[E] / delta_xyz); + m_width = static_cast(m_result.filament_diameters[filament_id]) * std::sqrt(delta_pos[E] / delta_xyz); else //BBS: cross section: rectangle + 2 semicircles m_width = delta_pos[E] * static_cast(M_PI * sqr(filament_radius)) / (delta_xyz * m_height) + static_cast(1.0 - 0.25 * M_PI) * m_height; @@ -3486,7 +3508,6 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line) float inv_distance = 1.0f / delta_xyz; float radius = ArcSegment::calc_arc_radius(start_point, m_arc_center); - int matched_extruder_id = extruder_id(m_extruder_id); for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { TimeMachine& machine = m_time_processor.machines[i]; if (!machine.enabled) @@ -3532,7 +3553,7 @@ void GCodeProcessor::process_G2_G3(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), matched_extruder_id); + float axis_max_feedrate = get_axis_max_feedrate(static_cast(i), static_cast(a), m_extruder_id); if (axis_max_feedrate != 0.0f) min_feedrate_factor = std::min(min_feedrate_factor, axis_max_feedrate / curr.abs_axis_feedrate[a]); } } @@ -3559,7 +3580,7 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line) axis_acc[a] = acceleration * std::abs(delta_pos[a]) * inv_distance; if (axis_acc[a] != 0.0f) { - float axis_max_acceleration = get_axis_max_acceleration(static_cast(i), static_cast(a), matched_extruder_id); + float axis_max_acceleration = get_axis_max_acceleration(static_cast(i), static_cast(a), m_extruder_id); if (axis_max_acceleration != 0.0f && axis_acc[a] > axis_max_acceleration) min_acc_factor = std::min(min_acc_factor, axis_max_acceleration / axis_acc[a]); } } @@ -3682,11 +3703,11 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line) if (m_seams_detector.is_active()) { //BBS: check for seam starting vertex if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter && !m_seams_detector.has_first_vertex()) { - m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset); + m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[get_filament_id()] - plate_offset); } else if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter && m_detect_layer_based_on_tag) { const Vec3f real_last_pos = Vec3f(m_result.moves.back().position.x() - m_x_offset, m_result.moves.back().position.y() - m_y_offset, m_result.moves.back().position.z()); - const Vec3f new_pos = real_last_pos - m_extruder_offsets[m_extruder_id]; + const Vec3f new_pos = real_last_pos - m_extruder_offsets[filament_id]; // We may have sloped loop, drop any previous start pos if we have z increment const std::optional first_vertex = m_seams_detector.get_first_vertex(); if (new_pos.z() > first_vertex->z()) { m_seams_detector.set_first_vertex(new_pos); } @@ -3697,7 +3718,7 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line) m_end_position[X] = pos.x(); m_end_position[Y] = pos.y(); m_end_position[Z] = pos.z(); }; const Vec3f curr_pos(m_end_position[X], m_end_position[Y], m_end_position[Z]); - const Vec3f new_pos = m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset; + const Vec3f new_pos = m_result.moves.back().position - m_extruder_offsets[filament_id] - plate_offset; const std::optional first_vertex = m_seams_detector.get_first_vertex(); //BBS: the threshold value = 0.0625f == 0.25 * 0.25 is arbitrary, we may find some smarter condition later @@ -3712,7 +3733,7 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line) } else if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter) { m_seams_detector.activate(true); - m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset); + m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[filament_id] - plate_offset); } //BBS: some layer may only has G3/G3, update right layer height @@ -3874,9 +3895,10 @@ void GCodeProcessor::process_M83(const GCodeReader::GCodeLine& line) void GCodeProcessor::process_M104(const GCodeReader::GCodeLine& line) { + int filament_id = get_filament_id(); float new_temp; if (line.has_value('S', new_temp)) - m_extruder_temps[m_extruder_id] = new_temp; + m_extruder_temps[filament_id] = new_temp; } void GCodeProcessor::process_M106(const GCodeReader::GCodeLine& line) @@ -3914,6 +3936,7 @@ void GCodeProcessor::process_M108(const GCodeReader::GCodeLine& line) void GCodeProcessor::process_M109(const GCodeReader::GCodeLine& line) { + int filament_id = get_filament_id(); float new_temp; if (line.has_value('R', new_temp)) { float val; @@ -3923,10 +3946,10 @@ void GCodeProcessor::process_M109(const GCodeReader::GCodeLine& line) m_extruder_temps[eid] = new_temp; } else - m_extruder_temps[m_extruder_id] = new_temp; + m_extruder_temps[filament_id] = new_temp; } else if (line.has_value('S', new_temp)) - m_extruder_temps[m_extruder_id] = new_temp; + m_extruder_temps[filament_id] = new_temp; } void GCodeProcessor::process_M132(const GCodeReader::GCodeLine& line) @@ -4227,12 +4250,13 @@ void GCodeProcessor::process_M566(const GCodeReader::GCodeLine& line) void GCodeProcessor::process_M702(const GCodeReader::GCodeLine& line) { + int filament_id = get_filament_id(); if (line.has('C')) { // MK3 MMU2 specific M code: // M702 C is expected to be sent by the custom end G-code when finalizing a print. // The MK3 unit shall unload and park the active filament into the MMU2 unit. m_time_processor.extruder_unloaded = true; - simulate_st_synchronize(get_filament_unload_time(m_extruder_id)); + simulate_st_synchronize(get_filament_unload_time(filament_id)); } } @@ -4243,42 +4267,33 @@ void GCodeProcessor::process_T(const GCodeReader::GCodeLine& line) void GCodeProcessor::process_M1020(const GCodeReader::GCodeLine &line) { + int curr_filament_id = get_filament_id(false); + int curr_extruder_id = get_extruder_id(false); if (line.raw().length() > 5) { - std::string filament_id = line.raw().substr(7); - if (filament_id.empty()) + std::string filament_id_str = line.raw().substr(7); + if (filament_id_str.empty()) return; int eid = 0; - eid = std::stoi(filament_id); + eid = std::stoi(filament_id_str); if (eid < 0 || eid > 254) { // M1020-1 is a valid gcode line for RepRap Firmwares (used to deselects all tools) if ((m_flavor != gcfRepRapFirmware && m_flavor != gcfRepRapSprinter) || eid != -1) BOOST_LOG_TRIVIAL(error) << "Invalid M1020 command (" << line.raw() << ")."; - } else { - unsigned char id = static_cast(eid); - if (m_extruder_id != id) { - if (id >= m_result.extruders_count) - BOOST_LOG_TRIVIAL(error) << "Invalid M1020 command (" << line.raw() << ")."; - else { - m_last_extruder_id = m_extruder_id; - process_filaments(CustomGCode::ToolChange); - m_extruder_id = id; - m_cp_color.current = m_extruder_colors[id]; - // BBS: increase filament change times - m_result.lock(); - m_result.print_statistics.total_filamentchanges++; - m_result.unlock(); - } - - // store tool change move - store_move_vertex(EMoveType::Tool_change); - } + } + else { + if (eid >= m_result.filaments_count) + BOOST_LOG_TRIVIAL(error) << "Invalid M1020 command (" << line.raw() << ")."; + process_filament_change(eid); } } } void GCodeProcessor::process_T(const std::string_view command) { + int curr_filament_id = get_filament_id(false); + int curr_extruder_id = get_extruder_id(false); + //TODO: multi switch if (command.length() > 1) { int eid = 0; if (! parse_number(command.substr(1), eid) || eid < 0 || eid > 254) { @@ -4290,57 +4305,87 @@ void GCodeProcessor::process_T(const std::string_view command) // T-1 is a valid gcode line for RepRap Firmwares (used to deselects all tools) if ((m_flavor != gcfRepRapFirmware && m_flavor != gcfRepRapSprinter) || eid != -1) BOOST_LOG_TRIVIAL(error) << "Invalid T command (" << command << ")."; - } else { - unsigned char id = static_cast(eid); - if (m_extruder_id != id) { - if (id >= m_result.extruders_count) - BOOST_LOG_TRIVIAL(error) << "Invalid T command (" << command << ")."; - else { - m_last_extruder_id = m_extruder_id; - process_filaments(CustomGCode::ToolChange); - m_extruder_id = id; - m_cp_color.current = m_extruder_colors[id]; - //BBS: increase filament change times - m_result.lock(); - m_result.print_statistics.total_filamentchanges++; - m_result.unlock(); - - // Specific to the MK3 MMU2: - // The initial value of extruder_unloaded is set to true indicating - // that the filament is parked in the MMU2 unit and there is nothing to be unloaded yet. - float extra_time = get_filament_unload_time(static_cast(m_last_extruder_id)); - m_time_processor.extruder_unloaded = false; - extra_time += get_filament_load_time(static_cast(m_extruder_id)); - // store tool change move - store_move_vertex(EMoveType::Tool_change); - // construct a new time block to handle filament change - for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { - TimeMachine& machine = m_time_processor.machines[i]; - if (!machine.enabled) - continue; - TimeBlock block; - block.role = erFlush; - block.move_type = EMoveType::Tool_change; - block.layer_id = std::max(1, m_layer_id); - block.g1_line_id = m_g1_line_id; - block.flags.prepare_stage = m_processing_start_custom_gcode; - block.distance = 0; - block.calculate_trapezoid(); - - // when do st_sync, we will clear all of the blocks without keeping last n blocks, so we can directly add the new block into the blocks - machine.blocks.push_back(block); - } - - simulate_st_synchronize(extra_time, erFlush); - - } - } + } + else { + if (eid >= m_result.filaments_count) + BOOST_LOG_TRIVIAL(error) << "Invalid T command (" << command << ")."; + process_filament_change(eid); } } } + +void GCodeProcessor::process_filament_change(int id) +{ + assert(id < m_result.filaments_count); + int prev_extruder_id = get_extruder_id(false); + int prev_filament_id = get_filament_id(false); + int next_extruder_id = m_filament_maps[id]; + int next_filament_id = id; + float extra_time = 0; + + if (prev_filament_id == next_filament_id) + return; + + if (prev_extruder_id != -1) + m_last_filament_id[prev_extruder_id] = prev_filament_id; + + if (prev_extruder_id == next_extruder_id) { + // don't need extruder change + assert(prev_extruder_id != -1); + process_filaments(CustomGCode::ToolChange); + m_filament_id[next_extruder_id] = next_filament_id; + m_result.lock(); + m_result.print_statistics.total_filament_changes += 1; + m_result.unlock(); + extra_time += get_filament_unload_time(static_cast(prev_filament_id)); + m_time_processor.extruder_unloaded = false; + extra_time += get_filament_load_time(static_cast(next_filament_id)); + } + else { + if (prev_extruder_id == -1) { + // initialize + m_extruder_id = next_extruder_id; + m_filament_id[next_extruder_id] = next_filament_id; + m_time_processor.extruder_unloaded = false; + extra_time += get_filament_load_time(static_cast(next_filament_id)); + } + else { + //first process cache generated by last extruder + process_filaments(CustomGCode::ToolChange); + //switch to current extruder + m_extruder_id = next_extruder_id; + if (m_last_filament_id[next_extruder_id] == (unsigned char)(-1)) { + //no filament in current extruder + m_filament_id[next_extruder_id] = next_filament_id; + m_time_processor.extruder_unloaded = false; + extra_time += get_filament_load_time(static_cast(next_filament_id)); + } + else if (m_last_filament_id[next_extruder_id] != next_filament_id) { + //need to change filament + m_filament_id[next_extruder_id] = next_filament_id; + m_result.lock(); + m_result.print_statistics.total_filament_changes += 1; + m_result.unlock(); + extra_time += get_filament_unload_time(static_cast(prev_filament_id)); + m_time_processor.extruder_unloaded = false; + extra_time += get_filament_load_time(static_cast(next_filament_id)); + } + m_result.lock(); + m_result.print_statistics.total_extruder_changes++; + m_result.unlock(); + extra_time += get_extruder_change_time(next_extruder_id); + } + } + m_cp_color.current = m_extruder_colors[next_filament_id]; + simulate_st_synchronize(extra_time); + // store tool change move + store_move_vertex(EMoveType::Tool_change); +} + void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type) { + int filament_id = get_filament_id(); m_last_line_id = (type == EMoveType::Color_change || type == EMoveType::Pause_Print || type == EMoveType::Custom_GCode) ? m_line_id + 1 : ((type == EMoveType::Seam) ? m_last_line_id : m_line_id); @@ -4353,29 +4398,29 @@ void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type) Vec3f(m_interpolation_points[i].x() + m_x_offset, m_interpolation_points[i].y() + m_y_offset, m_processing_start_custom_gcode ? m_first_layer_height : m_interpolation_points[i].z()) + - m_extruder_offsets[m_extruder_id]; + m_extruder_offsets[filament_id]; } m_result.moves.push_back({ m_last_line_id, type, m_extrusion_role, - m_extruder_id, + static_cast(filament_id), m_cp_color.current, //BBS: add plate's offset to the rendering vertices - Vec3f(m_end_position[X] + m_x_offset, m_end_position[Y] + m_y_offset, m_processing_start_custom_gcode ? m_first_layer_height : m_end_position[Z]) + m_extruder_offsets[m_extruder_id], + Vec3f(m_end_position[X] + m_x_offset, m_end_position[Y] + m_y_offset, m_processing_start_custom_gcode ? m_first_layer_height : m_end_position[Z]) + m_extruder_offsets[filament_id], static_cast(m_end_position[E] - m_start_position[E]), m_feedrate, m_width, m_height, m_mm3_per_mm, m_fan_speed, - m_extruder_temps[m_extruder_id], + m_extruder_temps[filament_id], static_cast(m_result.moves.size()), static_cast(m_layer_id), //layer_duration: set later //BBS: add arc move related data path_type, - Vec3f(m_arc_center(0, 0) + m_x_offset, m_arc_center(1, 0) + m_y_offset, m_arc_center(2, 0)) + m_extruder_offsets[m_extruder_id], + Vec3f(m_arc_center(0, 0) + m_x_offset, m_arc_center(1, 0) + m_y_offset, m_arc_center(2, 0)) + m_extruder_offsets[filament_id], m_interpolation_points, }); @@ -4522,6 +4567,12 @@ float GCodeProcessor::get_filament_unload_time(size_t extruder_id) return m_time_processor.extruder_unloaded ? 0.0f : m_time_processor.filament_unload_times; } +float GCodeProcessor::get_extruder_change_time(size_t extruder_id) +{ + //TODO: all extruder has the same value ? + return m_time_processor.extruder_change_times; +} + //BBS int GCodeProcessor::get_filament_vitrification_temperature(size_t extrude_id) { @@ -4594,12 +4645,12 @@ void GCodeProcessor::update_estimated_times_stats() m_result.print_statistics.modes[static_cast(PrintEstimatedStatistics::ETimeMode::Stealth)].reset(); m_result.print_statistics.volumes_per_color_change = m_used_filaments.volumes_per_color_change; - m_result.print_statistics.model_volumes_per_extruder = m_used_filaments.model_volumes_per_extruder; - m_result.print_statistics.wipe_tower_volumes_per_extruder = m_used_filaments.wipe_tower_volumes_per_extruder; - m_result.print_statistics.support_volumes_per_extruder = m_used_filaments.support_volumes_per_extruder; + m_result.print_statistics.model_volumes_per_extruder = m_used_filaments.model_volumes_per_filament; + m_result.print_statistics.wipe_tower_volumes_per_extruder = m_used_filaments.wipe_tower_volumes_per_filament; + m_result.print_statistics.support_volumes_per_extruder = m_used_filaments.support_volumes_per_filament; m_result.print_statistics.flush_per_filament = m_used_filaments.flush_per_filament; m_result.print_statistics.used_filaments_per_role = m_used_filaments.filaments_per_role; - m_result.print_statistics.total_volumes_per_extruder = m_used_filaments.total_volumes_per_extruder; + m_result.print_statistics.total_volumes_per_extruder = m_used_filaments.total_volumes_per_filament; } //BBS: ugly code... @@ -4609,8 +4660,8 @@ void GCodeProcessor::update_slice_warnings() auto get_used_extruders = [this]() { std::vector used_extruders; - used_extruders.reserve(m_used_filaments.total_volumes_per_extruder.size()); - for (auto item : m_used_filaments.total_volumes_per_extruder) { + used_extruders.reserve(m_used_filaments.total_volumes_per_filament.size()); + for (auto item : m_used_filaments.total_volumes_per_filament) { used_extruders.push_back(item.first); } return used_extruders; @@ -4681,5 +4732,36 @@ void GCodeProcessor::update_slice_warnings() m_result.warnings.shrink_to_fit(); } +int GCodeProcessor::get_filament_id(bool force_initialize)const +{ + int extruder_id = get_extruder_id(force_initialize); + if (extruder_id == -1) + return force_initialize ? 0 : -1; + + if (m_filament_id[extruder_id] == (unsigned char)(-1)) + return force_initialize ? 0 : -1; + + return static_cast(m_filament_id[extruder_id]); +} + +int GCodeProcessor::get_last_filament_id(bool force_initialize)const +{ + int extruder_id = get_extruder_id(force_initialize); + if (extruder_id == -1) + return force_initialize ? 0 : -1; + + if (m_last_filament_id[extruder_id] == (unsigned char)(-1)) + return force_initialize ? 0 : -1; + + return static_cast(m_last_filament_id[extruder_id]); +} + +int GCodeProcessor::get_extruder_id(bool force_initialize)const +{ + if (m_extruder_id == (unsigned char)(-1)) + return force_initialize ? 0 : -1; + return static_cast(m_extruder_id); +} + } /* namespace Slic3r */ diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index b901b61c3..1313c8995 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -83,7 +83,8 @@ namespace Slic3r { std::map> used_filaments_per_role; std::array(ETimeMode::Count)> modes; - unsigned int total_filamentchanges; + unsigned int total_filament_changes; + unsigned int total_extruder_changes; PrintEstimatedStatistics() { reset(); } @@ -99,7 +100,8 @@ namespace Slic3r { total_volumes_per_extruder.clear(); flush_per_filament.clear(); used_filaments_per_role.clear(); - total_filamentchanges = 0; + total_filament_changes = 0; + total_extruder_changes = 0; } }; @@ -207,7 +209,7 @@ namespace Slic3r { bool support_traditional_timelapse{true}; float printable_height; SettingsIds settings_ids; - size_t extruders_count; + size_t filaments_count; std::vector extruder_colors; std::vector filament_diameters; std::vector required_nozzle_HRC; @@ -243,7 +245,7 @@ namespace Slic3r { timelapse_warning_code = other.timelapse_warning_code; printable_height = other.printable_height; settings_ids = other.settings_ids; - extruders_count = other.extruders_count; + filaments_count = other.filaments_count; extruder_colors = other.extruder_colors; filament_diameters = other.filament_diameters; filament_densities = other.filament_densities; @@ -482,25 +484,58 @@ namespace Slic3r { void calculate_time(size_t keep_last_n_blocks = 0, float additional_time = 0.0f, ExtrusionRole target_role = ExtrusionRole::erNone); }; + struct TimeProcessor + { + struct Planner + { + // Size of the firmware planner queue. The old 8-bit Marlins usually just managed 16 trapezoidal blocks. + // Let's be conservative and plan for newer boards with more memory. + static constexpr size_t queue_size = 64; + // The firmware recalculates last planner_queue_size trapezoidal blocks each time a new block is added. + // We are not simulating the firmware exactly, we calculate a sequence of blocks once a reasonable number of blocks accumulate. + static constexpr size_t refresh_threshold = queue_size * 4; + }; + + // extruder_id is currently used to correctly calculate filament load / unload times into the total print time. + // This is currently only really used by the MK3 MMU2: + // extruder_unloaded = true means no filament is loaded yet, all the filaments are parked in the MK3 MMU2 unit. + bool extruder_unloaded; + // allow to skip the lines M201/M203/M204/M205 generated by GCode::print_machine_envelope() for non-Normal time estimate mode + bool machine_envelope_processing_enabled; + MachineEnvelopeConfig machine_limits; + // Additional load / unload times for a filament exchange sequence. + float filament_load_times; + float filament_unload_times; + float extruder_change_times; + + std::array(PrintEstimatedStatistics::ETimeMode::Count)> machines; + + void reset(); + + // post process the file with the given filename to add remaining time lines M73 + // and updates moves' gcode ids accordingly + void post_process(const std::string& filename, std::vector& moves, std::vector& lines_ends, size_t total_layer_num); + }; + struct UsedFilaments // filaments per ColorChange { double color_change_cache; std::vector volumes_per_color_change; double model_extrude_cache; - std::map model_volumes_per_extruder; + std::map model_volumes_per_filament; double wipe_tower_cache; - std::mapwipe_tower_volumes_per_extruder; + std::mapwipe_tower_volumes_per_filament; double support_volume_cache; - std::mapsupport_volumes_per_extruder; + std::mapsupport_volumes_per_filament; //BBS: the flush amount of every filament std::map flush_per_filament; double total_volume_cache; - std::maptotal_volumes_per_extruder; + std::maptotal_volumes_per_filament; double role_cache; std::map> filaments_per_role; @@ -729,8 +764,10 @@ namespace Slic3r { float m_mm3_per_mm; float m_fan_speed; // percentage ExtrusionRole m_extrusion_role; + std::vector m_filament_maps; + std::vector m_last_filament_id; + std::vector m_filament_id; unsigned char m_extruder_id; - unsigned char m_last_extruder_id; ExtruderColors m_extruder_colors; ExtruderTemps m_extruder_temps; int m_highest_bed_temp; @@ -959,6 +996,8 @@ namespace Slic3r { void process_T(const std::string_view command); void process_M1020(const GCodeReader::GCodeLine &line); + void process_filament_change(int id); + //BBS: different path_type is only used for arc move void store_move_vertex(EMoveType type, EMovePathType path_type = EMovePathType::Noop_move); @@ -978,6 +1017,7 @@ namespace Slic3r { void set_travel_acceleration(PrintEstimatedStatistics::ETimeMode mode, float value); float get_filament_load_time(size_t extruder_id); float get_filament_unload_time(size_t extruder_id); + float get_extruder_change_time(size_t extruder_id); int get_filament_vitrification_temperature(size_t extrude_id); void process_custom_gcode_time(CustomGCode::Type code); void process_filaments(CustomGCode::Type code); @@ -989,11 +1029,12 @@ namespace Slic3r { //BBS: void update_slice_warnings(); - //TODO: get matched extruder id - int extruder_id(unsigned int filament_id) { - int extruder_id = 0; - return extruder_id; - } + // get current used filament + int get_filament_id(bool force_initialize = true) const; + // get last used filament in the same extruder with current filament + int get_last_filament_id(bool force_initialize = true) const; + //get current used extruder + int get_extruder_id(bool force_initialize = true)const; }; } /* namespace Slic3r */ diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 0f0ceacd2..b2e928b02 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -960,7 +960,7 @@ static std::vector s_Preset_printer_options { "printhost_cafile","printhost_port","printhost_authorization_type", "printhost_user", "printhost_password", "printhost_ssl_ignore_revoke", "use_relative_e_distances", "extruder_type","use_firmware_retraction", - "grab_length" + "grab_length","machine_switch_extruder_time" }; static std::vector s_Preset_sla_print_options { diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 0c3a31d2f..53861a144 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1653,6 +1653,14 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0.0)); + def = this->add("machine_switch_extruder_time", coFloat); + def->label = L("Extruder switch time"); + def->tooltip = L("Time to switch extruder. For statistics only"); + def->min = 0; + def->sidetext = L("s"); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(5)); + def = this->add("filament_diameter", coFloats); def->label = L("Diameter"); def->tooltip = L("Filament diameter is used to calculate extrusion in gcode, so it's important and should be accurate"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 367c8cd35..61a069d09 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -986,6 +986,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionStrings, filament_extruder_variant)) ((ConfigOptionFloat, machine_load_filament_time)) ((ConfigOptionFloat, machine_unload_filament_time)) + ((ConfigOptionFloat, machine_switch_extruder_time)) ((ConfigOptionFloats, filament_minimal_purge_on_wipe_tower)) // BBS ((ConfigOptionBool, scan_first_layer)) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 6768f708f..7076fe701 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -1186,7 +1186,7 @@ void GCodeViewer::refresh(const GCodeProcessorResult& gcode_result, const std::v m_tools.m_tool_colors[i] = adjust_color_for_rendering(m_tools.m_tool_colors[i]); } // ensure there are enough colors defined - while (m_tools.m_tool_colors.size() < std::max(size_t(1), gcode_result.extruders_count)) { + while (m_tools.m_tool_colors.size() < std::max(size_t(1), gcode_result.filaments_count)) { m_tools.m_tool_colors.push_back(decode_color("#FF8000")); m_tools.m_tool_visibles.push_back(true); } @@ -2410,7 +2410,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result, const if (m_moves_count == 0) return; - m_extruders_count = gcode_result.extruders_count; + m_extruders_count = gcode_result.filaments_count; unsigned int progress_count = 0; static const unsigned int progress_threshold = 1000; @@ -5508,7 +5508,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv ImGui::SameLine(); imgui.text(_u8L("Filament change times") + ":"); ImGui::SameLine(); - ::sprintf(buf, "%d", m_print_statistics.total_filamentchanges); + ::sprintf(buf, "%d", m_print_statistics.total_filament_changes); imgui.text(buf); //BBS display cost diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 5bf80b4a0..30c29908b 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3659,6 +3659,7 @@ void TabPrinter::build_fff() // optgroup->append_single_option_line("spaghetti_detector"); optgroup->append_single_option_line("machine_load_filament_time"); optgroup->append_single_option_line("machine_unload_filament_time"); + optgroup->append_single_option_line("machine_switch_extruder_time"); optgroup = page->new_optgroup(L("Extruder Clearance")); optgroup->append_single_option_line("extruder_clearance_max_radius");