ENH: save multi extruder state in gcode processor

1.Save multi extruder state in gcode processor
2.Add machine exturder change time
3.Fix some naming issues

jira:NONE

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: I9785331290515eeb908ff0ff01aad5aac44212d9
This commit is contained in:
xun.zhang 2024-07-26 16:46:24 +08:00 committed by lane.wei
parent 5f30ee389e
commit b49d4ca153
7 changed files with 317 additions and 184 deletions

View File

@ -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<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
@ -775,7 +776,7 @@ void GCodeProcessor::UsedFilaments::reset()
volumes_per_color_change = std::vector<double>();
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<double, double> 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<std::string>();
filament_diameters = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER);
required_nozzle_HRC = std::vector<int>(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<float>(config.machine_load_filament_time.value);
m_time_processor.filament_unload_times = static_cast<float>(config.machine_unload_filament_time.value);
m_time_processor.extruder_change_times = static_cast<float>(config.machine_switch_extruder_time.value);
for (size_t i = 0; i < static_cast<size_t>(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<ConfigOptionInts>("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<ConfigOptionBool>("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<ConfigOptionFloats>("filament_diameter")->values.size();
m_result.filaments_count = config.option<ConfigOptionFloats>("filament_diameter")->values.size();
const ConfigOptionFloats* filament_diameters = config.option<ConfigOptionFloats>("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<float>(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<ConfigOptionInts>("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<ConfigOptionFloats>("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<float>(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<int>(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<float>();
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<unsigned char>(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<ConfigOptionFloat>("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<float>(machine_unload_filament_time->value);
const ConfigOptionFloat* machine_switch_extruder_time = config.option<ConfigOptionFloat>("machine_switch_extruder_time");
if (machine_switch_extruder_time != nullptr)
m_time_processor.extruder_change_times = static_cast<float>(machine_switch_extruder_time->value);
if (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfKlipper) {
const ConfigOptionFloats* machine_max_acceleration_x = config.option<ConfigOptionFloats>("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<unsigned char>(-1),static_cast<unsigned char>(-1)};
m_last_filament_id = {static_cast<unsigned char>(-1),static_cast<unsigned char>(-1) };
m_extruder_id = static_cast<unsigned char>(-1);
m_extruder_colors.resize(MIN_EXTRUDERS_COUNT);
for (size_t i = 0; i < MIN_EXTRUDERS_COUNT; ++i) {
m_extruder_colors[i] = static_cast<unsigned char>(i);
@ -1816,7 +1835,7 @@ void GCodeProcessor::apply_config_simplify3d(const std::string& filename)
} else if (comment.find("extruderDiameter") != comment.npos) {
std::vector<float> 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<size_t>(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<size_t>(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<std::string> 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<unsigned char>(eid);
filament_id = static_cast<unsigned char>(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<unsigned char>(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<unsigned char>(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<double>(m_end_position[2]), CustomGCode::ColorChange, extruder_id + 1, color, "" };
CustomGCode::Item item = { static_cast<double>(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<double>(m_end_position[2]), CustomGCode::PausePrint, m_extruder_id + 1, "", "" };
CustomGCode::Item item = { static_cast<double>(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<double>(m_end_position[2]), CustomGCode::Custom, m_extruder_id + 1, "", "" };
CustomGCode::Item item = { static_cast<double>(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<size_t>(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<size_t>(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<float>(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<float>(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<float>(m_result.filament_diameters[m_extruder_id]) * std::sqrt(delta_pos[E] / delta_xyz);
m_width = static_cast<float>(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<float>(M_PI * sqr(filament_radius)) / (delta_xyz * m_height) + static_cast<float>(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<size_t>(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<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a), matched_extruder_id);
float axis_max_feedrate = get_axis_max_feedrate(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a), m_extruder_id);
if (axis_max_feedrate != 0.0f) min_feedrate_factor = std::min<float>(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<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a), matched_extruder_id);
float axis_max_acceleration = get_axis_max_acceleration(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(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<Vec3f> 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<Vec3f> 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<size_t>(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<size_t>(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<float>(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<float>(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<float>(m_result.filament_diameters[m_extruder_id]) * std::sqrt(delta_pos[E] / delta_xyz);
m_width = static_cast<float>(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<float>(M_PI * sqr(filament_radius)) / (delta_xyz * m_height) + static_cast<float>(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<size_t>(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<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a), matched_extruder_id);
float axis_max_feedrate = get_axis_max_feedrate(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a), m_extruder_id);
if (axis_max_feedrate != 0.0f) min_feedrate_factor = std::min<float>(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<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a), matched_extruder_id);
float axis_max_acceleration = get_axis_max_acceleration(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a), m_extruder_id);
if (axis_max_acceleration != 0.0f && axis_acc[a] > axis_max_acceleration) min_acc_factor = std::min<float>(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<Vec3f> 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<Vec3f> 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<unsigned char>(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);
}
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<unsigned char>(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();
if (eid >= m_result.filaments_count)
BOOST_LOG_TRIVIAL(error) << "Invalid T command (" << command << ").";
process_filament_change(eid);
}
}
}
// 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<size_t>(m_last_extruder_id));
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<size_t>(prev_filament_id));
m_time_processor.extruder_unloaded = false;
extra_time += get_filament_load_time(static_cast<size_t>(m_extruder_id));
extra_time += get_filament_load_time(static_cast<size_t>(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<size_t>(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<size_t>(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<size_t>(prev_filament_id));
m_time_processor.extruder_unloaded = false;
extra_time += get_filament_load_time(static_cast<size_t>(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);
// construct a new time block to handle filament change
for (size_t i = 0; i < static_cast<size_t>(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<unsigned int>(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);
}
}
}
}
}
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<unsigned char>(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<float>(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<float>(m_result.moves.size()),
static_cast<float>(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<size_t>(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<size_t> 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<int>(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<int>(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<int>(m_extruder_id);
}
} /* namespace Slic3r */

View File

@ -83,7 +83,8 @@ namespace Slic3r {
std::map<ExtrusionRole, std::pair<double, double>> used_filaments_per_role;
std::array<Mode, static_cast<size_t>(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<std::string> extruder_colors;
std::vector<float> filament_diameters;
std::vector<int> 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<TimeMachine, static_cast<size_t>(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<GCodeProcessorResult::MoveVertex>& moves, std::vector<size_t>& lines_ends, size_t total_layer_num);
};
struct UsedFilaments // filaments per ColorChange
{
double color_change_cache;
std::vector<double> volumes_per_color_change;
double model_extrude_cache;
std::map<size_t, double> model_volumes_per_extruder;
std::map<size_t, double> model_volumes_per_filament;
double wipe_tower_cache;
std::map<size_t, double>wipe_tower_volumes_per_extruder;
std::map<size_t, double>wipe_tower_volumes_per_filament;
double support_volume_cache;
std::map<size_t, double>support_volumes_per_extruder;
std::map<size_t, double>support_volumes_per_filament;
//BBS: the flush amount of every filament
std::map<size_t, double> flush_per_filament;
double total_volume_cache;
std::map<size_t, double>total_volumes_per_extruder;
std::map<size_t, double>total_volumes_per_filament;
double role_cache;
std::map<ExtrusionRole, std::pair<double, double>> 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<int> m_filament_maps;
std::vector<unsigned char> m_last_filament_id;
std::vector<unsigned char> 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 */

View File

@ -960,7 +960,7 @@ static std::vector<std::string> 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<std::string> s_Preset_sla_print_options {

View File

@ -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");

View File

@ -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))

View File

@ -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

View File

@ -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");