diff --git a/resources/ui_layout/extruder.ui b/resources/ui_layout/extruder.ui index d9231e34a..8dcec3661 100644 --- a/resources/ui_layout/extruder.ui +++ b/resources/ui_layout/extruder.ui @@ -1,6 +1,7 @@ page:idx:Extruder:funnel -group:Size +group:Name and Size + setting:idx:tool_name setting:idx:nozzle_diameter update_nozzle_diameter group:Layer height limits diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index d911a3f30..a420d4404 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -491,7 +491,8 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) const std::vector> GCodeProcessor::Producers = { { EProducer::PrusaSlicer, "PrusaSlicer" }, - { EProducer::SuperSlicer, "SuperSlicer" }, { EProducer::Slic3rPE, "Slic3r Prusa Edition" }, + { EProducer::SuperSlicer, "SuperSlicer" }, + { EProducer::Slic3rPE, "Slic3r Prusa Edition" }, { EProducer::Slic3r, "Slic3r" }, { EProducer::Cura, "Cura_SteamEngine" }, { EProducer::Simplify3D, "Simplify3D" }, @@ -522,6 +523,11 @@ void GCodeProcessor::apply_config(const PrintConfig& config) m_extruder_offsets[i] = { offset(0), offset(1), 0.0f }; } + m_extruder_names.resize(extruders_count); + for (size_t i = 0; i < extruders_count; ++i) { + m_extruder_names[i] = config.tool_name.values[i]; + } + m_extruder_colors.resize(extruders_count); for (size_t i = 0; i < extruders_count; ++i) { m_extruder_colors[i] = static_cast(i); @@ -555,7 +561,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config) m_time_processor.export_remaining_time_enabled = config.remaining_times.value; - if (config.option>("gcode_flavor")->value != gcfMarlin) { + if (m_flavor != gcfMarlin) { double time_estimation_compensation = config.get_abs_value("time_estimation_compensation"); for (auto& machine : this->m_time_processor.machines) { machine.time_acceleration = time_estimation_compensation; @@ -936,6 +942,45 @@ std::vector GCodeProcessor::get_layers_time(PrintEstimatedTimeStatistics: std::vector(); } +std::string get_klipper_param(std::string key, std::string line) { + size_t key_pos = line.find(key); + if (key_pos == std::string::npos) { + boost::to_lower(key); + key_pos = line.find(key); + } + if (key_pos != std::string::npos) { + size_t data_pos = key_pos + key.size(); + while (data_pos < line.size() && (line[data_pos] == ' ' || line[data_pos] == '=')) + data_pos++; + if (data_pos < line.size()) { + size_t end_pos = line.find(" ", data_pos); + if (end_pos == std::string::npos) + end_pos = line.size(); + return line.substr(data_pos, end_pos - data_pos); + } + } + return ""; +} + +void GCodeProcessor::process_klipper_ACTIVATE_EXTRUDER(const GCodeReader::GCodeLine& line) { + uint8_t extruder_id = 0; + //check the config + std::string raw_value = get_klipper_param(" EXTRUDER", line.raw()); + auto it = std::find(m_extruder_names.begin(), m_extruder_names.end(), raw_value); + if ( it != m_extruder_names.end()) { + process_T(uint8_t(it - m_extruder_names.begin())); + return; + } + std::string trsf; + while (raw_value.back() >= '0' && raw_value.back() <= '9') { + trsf = raw_value.back() + trsf; + raw_value.resize(raw_value.size() - 1); + } + if (trsf.empty()) + trsf = "0"; + process_T(uint8_t(std::stoi(trsf))); +} + void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line) { /* std::cout << line.raw() << std::endl; */ @@ -944,7 +989,19 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line) m_start_position = m_end_position; const std::string_view cmd = line.cmd(); - if (cmd.length() > 1) { + if (cmd.length() > 10 && m_flavor == GCodeFlavor::gcfKlipper) { + try { + std::string cmd_up = boost::to_upper_copy(std::string(cmd)); + //klipper extendt comands + if (cmd_up == "TURN_OFF_HEATERS") + m_temperature = 0; + else if (cmd_up == "ACTIVATE_EXTRUDER") + process_klipper_ACTIVATE_EXTRUDER(line); + } + catch (...) { + BOOST_LOG_TRIVIAL(error) << "GCodeProcessor failed to parse the klipper command '" << line.raw() << "'."; + } + } else if (cmd.length() > 1) { // process command lines switch (::toupper(cmd[0])) { @@ -1001,21 +1058,7 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line) } default: { break; } } - if (this->m_flavor == GCodeFlavor::gcfKlipper) { - if (cmd == "ACTIVATE_EXTRUDER") { - std::string rawline = line.raw(); - std::string trsf; - while (rawline.back() >= '0' && rawline.back() <= '9') { - trsf = rawline.back() + trsf; - rawline.resize(rawline.size() - 1); - } - if (trsf.empty()) - trsf = "0"; - process_T("T" + trsf); - } - } - } - else { + } else { const std::string &comment = line.raw(); if (comment.length() > 2 && comment.front() == ';') // Process tags embedded into comments. Tag comments always start at the start of a line @@ -2121,33 +2164,38 @@ void GCodeProcessor::process_T(const std::string_view command) { if (command.length() > 1) { int eid; - if (! parse_number(command.substr(1), eid) || eid < 0 || eid > 255) { + if (!parse_number(command.substr(1), eid) || eid < 0 || eid > 255) { BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid toolchange (" << command << ")."; } else { unsigned char id = static_cast(eid); - if (m_extruder_id != id) { - unsigned char extruders_count = static_cast(m_extruder_offsets.size()); - if (id >= extruders_count) - BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid toolchange, maybe from a custom gcode."; - else { - unsigned char old_extruder_id = m_extruder_id; - m_extruder_id = id; - m_cp_color.current = m_extruder_colors[id]; - // 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(old_extruder_id)); - m_time_processor.extruder_unloaded = false; - extra_time += get_filament_load_time(static_cast(m_extruder_id)); - simulate_st_synchronize(extra_time); - } - - // store tool change move - store_move_vertex(EMoveType::Tool_change); - } - } + process_T(id); } } +} + +void GCodeProcessor::process_T(uint8_t new_id) +{ + if (m_extruder_id != new_id) { + unsigned char extruders_count = static_cast(m_extruder_offsets.size()); + if (new_id >= extruders_count) + BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid toolchange, maybe from a custom gcode."; + else { + unsigned char old_extruder_id = m_extruder_id; + m_extruder_id = new_id; + m_cp_color.current = m_extruder_colors[new_id]; + // 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(old_extruder_id)); + m_time_processor.extruder_unloaded = false; + extra_time += get_filament_load_time(static_cast(m_extruder_id)); + simulate_st_synchronize(extra_time); + } + + // store tool change move + store_move_vertex(EMoveType::Tool_change); + } +} void GCodeProcessor::store_move_vertex(EMoveType type) { diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index 4ad4de79e..f7b4e9018 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -371,6 +371,7 @@ namespace Slic3r { EPositioningType m_global_positioning_type; EPositioningType m_e_local_positioning_type; std::vector m_extruder_offsets; + std::vector m_extruder_names; GCodeFlavor m_flavor; AxisCoords m_start_position; // mm @@ -550,6 +551,8 @@ namespace Slic3r { // Processes T line (Select Tool) void process_T(const GCodeReader::GCodeLine& line); void process_T(const std::string_view command); + void process_T(uint8_t command); + void process_klipper_ACTIVATE_EXTRUDER(const GCodeReader::GCodeLine& line); void store_move_vertex(EMoveType type); diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index 3fc5ee9e7..3db11d1ee 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -377,9 +377,15 @@ std::string GCodeWriter::toolchange(unsigned int tool_id) std::ostringstream gcode; if (this->multiple_extruders) { if (FLAVOR_IS(gcfKlipper)) { - gcode << this->toolchange_prefix() << "extruder"; - if (tool_id > 0) - gcode << tool_id; + //check if we can use the tool_name field or not + if (tool_id > 0 && tool_id < this->config.tool_name.values.size() && !this->config.tool_name.values[tool_id].empty() + && this->config.tool_name.values[tool_id][0] != ('0' + tool_id)) { + gcode << this->toolchange_prefix() << this->config.tool_name.values[tool_id]; + } else { + gcode << this->toolchange_prefix() << "extruder"; + if (tool_id > 0) + gcode << tool_id; + } } else { gcode << this->toolchange_prefix() << tool_id; } diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 20c37ff74..1c8bddbe5 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -160,6 +160,7 @@ bool Print::invalidate_state_by_config_options(const std::vectormode = comExpert; def->set_default_value(new ConfigOptionString("")); + def = this->add("tool_name", coStrings); + def->label = L("Tool name"); + def->category = OptionCategory::extruders; + def->tooltip = L("Only used for klipper, where you can name the extruder. If not set, will be 'extruderX' with 'X' replaced by the extruder number."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionStrings("")); + def = this->add("top_infill_extrusion_width", coFloatOrPercent); def->label = L("Top solid infill"); def->category = OptionCategory::width; @@ -4014,6 +4021,7 @@ void PrintConfigDef::init_extruder_option_keys() "extruder_offset", "extruder_fan_offset", "extruder_temperature_offset", + "tool_name", "retract_length", "retract_lift", "retract_lift_above", diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 9c3028ed3..781973b71 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1050,6 +1050,7 @@ public: ConfigOptionBool single_extruder_multi_material; ConfigOptionBool single_extruder_multi_material_priming; ConfigOptionBool wipe_tower_no_sparse_layers; + ConfigOptionStrings tool_name; ConfigOptionString toolchange_gcode; ConfigOptionFloat travel_speed; ConfigOptionBool use_firmware_retraction; @@ -1156,6 +1157,7 @@ protected: OPT_PTR(wipe_tower_no_sparse_layers); OPT_PTR(start_gcode); OPT_PTR(start_filament_gcode); + OPT_PTR(tool_name); OPT_PTR(toolchange_gcode); OPT_PTR(travel_speed); OPT_PTR(use_firmware_retraction); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 75f6c83cb..ec860c093 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1120,8 +1120,9 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) if (opt_key == "wipe_tower" || opt_key == "single_extruder_multi_material" || opt_key == "extruders_count" ) update_wiping_button_visibility(); - if (opt_key == "extruders_count") + if (opt_key == "extruders_count") { wxGetApp().plater()->on_extruders_change(boost::any_cast(value)); + } update(); } @@ -2342,7 +2343,14 @@ void TabPrinter::extruders_count_changed(size_t extruders_count) build_unregular_pages(); if (is_count_changed) { + //propagate change on_value_change("extruders_count", (int)extruders_count); + //update default tool_name => not used, no need to do that + //ConfigOptionStrings* names = this->m_config->option("tool_name"); + //for (size_t ss = 0; ss < names->values.size(); ss++) + // if (names->values[ss] == "") + // names->values[ss] = std::to_string(ss); + //update gui wxGetApp().sidebar().update_objects_list_extruder_column(extruders_count); } }