From c2320e03a59c013b9a91fbfa93eb1ef6b5d916de Mon Sep 17 00:00:00 2001 From: SoftFever Date: Fri, 5 Jul 2024 00:00:54 +0800 Subject: [PATCH 01/32] tool changer support - init work --- src/libslic3r/GCode.cpp | 64 +++- src/libslic3r/Preset.cpp | 4 +- src/libslic3r/Print.cpp | 13 +- src/libslic3r/PrintConfig.cpp | 52 ++-- src/libslic3r/PrintConfig.hpp | 6 +- src/libslic3r/PrintObject.cpp | 2 +- src/slic3r/GUI/ConfigManipulation.cpp | 2 +- src/slic3r/GUI/GUI_App.cpp | 20 +- src/slic3r/GUI/Plater.cpp | 14 +- src/slic3r/GUI/Plater.hpp | 2 + src/slic3r/GUI/Tab.cpp | 411 +++++++++++++++----------- 11 files changed, 370 insertions(+), 220 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index cdeaa1f159..c46de72179 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -272,11 +272,22 @@ static std::vector get_path_of_change_filament(const Print& print) gcode += gcodegen.writer().travel_to_xy(unscale(standby_point), "move to standby position"); } + unsigned int extruder_id = gcodegen.writer().extruder()->id(); + const ConfigOptionInts& filament_idle_temp = gcodegen.config().idle_temperature; - if (gcodegen.config().standby_temperature_delta.value != 0) { - // we assume that heating is always slower than cooling, so no need to block - gcode += gcodegen.writer().set_temperature - (this->_get_temp(gcodegen) + gcodegen.config().standby_temperature_delta.value, false, gcodegen.writer().extruder()->id()); + if (filament_idle_temp.get_at(extruder_id) == 0) { + if (gcodegen.config().standby_temperature_delta.value != 0) { + // we assume that heating is always slower than cooling, so no need to block + gcode += gcodegen.writer().set_temperature(this->_get_temp(gcodegen) + gcodegen.config().standby_temperature_delta.value, + false, gcodegen.writer().extruder()->id()); + gcode.pop_back(); + gcode += " ;cooldown\n"; // this is a marker for GCodeProcessor, so it can supress the commands when needed + } + } else { + // Use the value from filament settings. That one is absolute, not delta. + gcode += gcodegen.writer().set_temperature(filament_idle_temp.get_at(extruder_id), false, extruder_id); + gcode.pop_back(); + gcode += " ;cooldown\n"; // this is a marker for GCodeProcessor, so it can supress the commands when needed } return gcode; @@ -2261,6 +2272,8 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato this->placeholder_parser().set("has_wipe_tower", has_wipe_tower); //this->placeholder_parser().set("has_single_extruder_multi_material_priming", has_wipe_tower && print.config().single_extruder_multi_material_priming); this->placeholder_parser().set("total_toolchanges", std::max(0, print.wipe_tower_data().number_of_toolchanges)); // Check for negative toolchanges (single extruder mode) and set to 0 (no tool change). + this->placeholder_parser().set("num_extruders", int(print.config().nozzle_diameter.values.size())); + this->placeholder_parser().set("retract_length", new ConfigOptionFloats(print.config().retraction_length)); // PlaceholderParser currently substitues non-existent vector values with the zero'th value, which is harmful in the // case of "is_extruder_used[]" as Slicer may lie about availability of such non-existent extruder. We rather @@ -3255,8 +3268,12 @@ void GCode::_print_first_layer_extruder_temperatures(GCodeOutputStream &file, Pr // Set temperatures of all the printing extruders. for (unsigned int tool_id : print.extruders()) { int temp = print.config().nozzle_temperature_initial_layer.get_at(tool_id); - if (print.config().ooze_prevention.value) - temp += print.config().standby_temperature_delta.value; + if (print.config().ooze_prevention.value) { + if (print.config().idle_temperature.get_at(tool_id) == 0) + temp += print.config().standby_temperature_delta.value; + else + temp = print.config().idle_temperature.get_at(tool_id); + } if (temp > 0) file.write(m_writer.set_temperature(temp, wait, tool_id)); } @@ -6016,15 +6033,22 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z, bool b // if we are running a single-extruder setup, just set the extruder and return nothing if (!m_writer.multiple_extruders) { this->placeholder_parser().set("current_extruder", extruder_id); - this->placeholder_parser().set("retraction_distance_when_cut", m_config.retraction_distances_when_cut.get_at(extruder_id)); - this->placeholder_parser().set("long_retraction_when_cut", m_config.long_retractions_when_cut.get_at(extruder_id)); std::string gcode; // Append the filament start G-code. const std::string &filament_start_gcode = m_config.filament_start_gcode.get_at(extruder_id); if (! filament_start_gcode.empty()) { // Process the filament_start_gcode for the filament. - gcode += this->placeholder_parser_process("filament_start_gcode", filament_start_gcode, extruder_id); + DynamicConfig config; + config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index)); + config.set_key_value("layer_z", new ConfigOptionFloat(this->writer().get_position().z() - m_config.z_offset.value)); + config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z)); + config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(extruder_id))); + config.set_key_value("retraction_distance_when_cut", + new ConfigOptionFloat(m_config.retraction_distances_when_cut.get_at(extruder_id))); + config.set_key_value("long_retraction_when_cut", new ConfigOptionBool(m_config.long_retractions_when_cut.get_at(extruder_id))); + + gcode += this->placeholder_parser_process("filament_start_gcode", filament_start_gcode, extruder_id, &config); check_add_eol(gcode); } if (m_config.enable_pressure_advance.get_at(extruder_id)) { @@ -6054,7 +6078,12 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z, bool b unsigned int old_extruder_id = m_writer.extruder()->id(); const std::string &filament_end_gcode = m_config.filament_end_gcode.get_at(old_extruder_id); if (! filament_end_gcode.empty()) { - gcode += placeholder_parser_process("filament_end_gcode", filament_end_gcode, old_extruder_id); + DynamicConfig config; + config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index)); + config.set_key_value("layer_z", new ConfigOptionFloat(m_writer.get_position().z() - m_config.z_offset.value)); + config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z)); + config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(old_extruder_id))); + gcode += placeholder_parser_process("filament_end_gcode", filament_end_gcode, old_extruder_id, &config); check_add_eol(gcode); } } @@ -6166,6 +6195,14 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z, bool b std::string toolchange_gcode_parsed; //Orca: Ignore change_filament_gcode if is the first call for a tool change and manual_filament_change is enabled if (!change_filament_gcode.empty() && !(m_config.manual_filament_change.value && m_toolchange_count == 1)) { + dyn_config.set_key_value("previous_extruder", + new ConfigOptionInt((int) (m_writer.extruder() != nullptr ? m_writer.extruder()->id() : -1))); + dyn_config.set_key_value("next_extruder", new ConfigOptionInt((int) extruder_id)); + dyn_config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index)); + dyn_config.set_key_value("layer_z", new ConfigOptionFloat(print_z)); + dyn_config.set_key_value("toolchange_z", new ConfigOptionFloat(print_z)); + dyn_config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z)); + toolchange_gcode_parsed = placeholder_parser_process("change_filament_gcode", change_filament_gcode, extruder_id, &dyn_config); check_add_eol(toolchange_gcode_parsed); gcode += toolchange_gcode_parsed; @@ -6216,7 +6253,12 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z, bool b const std::string &filament_start_gcode = m_config.filament_start_gcode.get_at(extruder_id); if (! filament_start_gcode.empty()) { // Process the filament_start_gcode for the new filament. - gcode += this->placeholder_parser_process("filament_start_gcode", filament_start_gcode, extruder_id); + DynamicConfig config; + config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index)); + config.set_key_value("layer_z", new ConfigOptionFloat(this->writer().get_position().z() - m_config.z_offset.value)); + config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z)); + config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(extruder_id))); + gcode += this->placeholder_parser_process("filament_start_gcode", filament_start_gcode, extruder_id, &config); check_add_eol(gcode); } // Set the new extruder to the operating temperature. diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 05c34446b6..724bdc148e 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -809,7 +809,7 @@ static std::vector s_Preset_print_options { "tree_support_brim_width", "gcode_comments", "gcode_label_objects", "initial_layer_travel_speed", "exclude_object", "slow_down_layers", "infill_anchor", "infill_anchor_max","initial_layer_min_bead_width", "make_overhang_printable", "make_overhang_printable_angle", "make_overhang_printable_hole_size" ,"notes", - "wipe_tower_cone_angle", "wipe_tower_extra_spacing","wipe_tower_max_purge_speed", "wipe_tower_extruder", "wiping_volumes_extruders","wipe_tower_bridging", "single_extruder_multi_material_priming", + "wipe_tower_cone_angle", "wipe_tower_extra_spacing","wipe_tower_max_purge_speed", "wipe_tower_filament", "wiping_volumes_extruders","wipe_tower_bridging", "single_extruder_multi_material_priming", "wipe_tower_rotation_angle", "tree_support_branch_distance_organic", "tree_support_branch_diameter_organic", "tree_support_branch_angle_organic", "hole_to_polyhole", "hole_to_polyhole_threshold", "hole_to_polyhole_twisted", "mmu_segmented_region_max_width", "mmu_segmented_region_interlocking_depth", "small_area_infill_flow_compensation", "small_area_infill_flow_compensation_model", @@ -845,7 +845,7 @@ static std::vector s_Preset_filament_options { "filament_unloading_speed", "filament_unloading_speed_start", "filament_unload_time", "filament_toolchange_delay", "filament_cooling_moves", "filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", "filament_multitool_ramming", "filament_multitool_ramming_volume", "filament_multitool_ramming_flow", "activate_chamber_temp_control", - "filament_long_retractions_when_cut","filament_retraction_distances_when_cut" + "filament_long_retractions_when_cut","filament_retraction_distances_when_cut", "idle_temperature" }; static std::vector s_Preset_machine_limits_options { diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 43755c8ade..5e5f4bf284 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -284,10 +284,11 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n || opt_key == "initial_layer_speed" || opt_key == "initial_layer_travel_speed" || opt_key == "slow_down_layers" + || opt_key == "idle_temperature" || opt_key == "wipe_tower_cone_angle" || opt_key == "wipe_tower_extra_spacing" || opt_key == "wipe_tower_max_purge_speed" - || opt_key == "wipe_tower_extruder" + || opt_key == "wipe_tower_filament" || opt_key == "wiping_volumes_extruders" || opt_key == "enable_filament_ramming" || opt_key == "purge_in_prime_tower" @@ -1148,9 +1149,12 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons* double nozzle_diam = m_config.nozzle_diameter.get_at(extruder_idx); double filament_diam = m_config.filament_diameter.get_at(extruder_idx); if (nozzle_diam - EPSILON > first_nozzle_diam || nozzle_diam + EPSILON < first_nozzle_diam - || std::abs((filament_diam - first_filament_diam) / first_filament_diam) > 0.1) - // BBS: remove L() - return { L("Different nozzle diameters and different filament diameters is not allowed when prime tower is enabled.") }; + || std::abs((filament_diam - first_filament_diam) / first_filament_diam) > 0.1) { + // return { L("Different nozzle diameters and different filament diameters may not work well when prime tower is enabled. It's very experimental, please proceed with caucious.") }; + warning->string = L("Different nozzle diameters and different filament diameters may not work well when the prime tower is enabled. It's very experimental, so please proceed with caution."); + warning->opt_key = "nozzle_diameter"; + break; + } } if (! m_config.use_relative_e_distances) @@ -2820,6 +2824,7 @@ std::string Print::output_filename(const std::string &filename_base) const // These values will be just propagated into the output file name. DynamicConfig config = this->finished() ? this->print_statistics().config() : this->print_statistics().placeholders(); config.set_key_value("num_filaments", new ConfigOptionInt((int)m_config.nozzle_diameter.size())); + config.set_key_value("num_extruders", new ConfigOptionInt((int) m_config.nozzle_diameter.size())); config.set_key_value("plate_name", new ConfigOptionString(get_plate_name())); config.set_key_value("plate_number", new ConfigOptionString(get_plate_number_formatted())); config.set_key_value("model_name", new ConfigOptionString(get_model_name())); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 1dc18c1711..2c3798dd08 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2800,11 +2800,10 @@ void PrintConfigDef::init_fff_params() def = this->add("mmu_segmented_region_interlocking_depth", coFloat); def->label = L("Interlocking depth of a segmented region"); - //def->tooltip = L("Interlocking depth of a segmented region. It will be ignored if " - // "\"mmu_segmented_region_max_width\" is zero or if \"mmu_segmented_region_interlocking_depth\"" - // "is bigger then \"mmu_segmented_region_max_width\". Zero disables this feature."); - def->tooltip = L("Interlocking depth of a segmented region. Zero disables this feature."); - def->sidetext = L("mm"); //(zero to disable) + def->tooltip = L("Interlocking depth of a segmented region. It will be ignored if " + "\"mmu_segmented_region_max_width\" is zero or if \"mmu_segmented_region_interlocking_depth\"" + "is bigger then \"mmu_segmented_region_max_width\". Zero disables this feature."); + def->sidetext = L("mm"); def->min = 0; def->category = L("Advanced"); def->mode = comAdvanced; @@ -3398,7 +3397,7 @@ void PrintConfigDef::init_fff_params() def->category = "Extruders"; def->tooltip = "Filament to print walls"; def->min = 1; - def->mode = comDevelop; + def->mode = comAdvanced; def->set_default_value(new ConfigOptionInt(1)); def = this->add("inner_wall_line_width", coFloatOrPercent); @@ -4061,12 +4060,13 @@ void PrintConfigDef::init_fff_params() def = this->add("standby_temperature_delta", coInt); def->label = L("Temperature variation"); - //def->tooltip = L("Temperature difference to be applied when an extruder is not active. " - // "Enables a full-height \"sacrificial\" skirt on which the nozzles are periodically wiped."); + // TRN PrintSettings : "Ooze prevention" > "Temperature variation" + def->tooltip = L("Temperature difference to be applied when an extruder is not active. " + "The value is not used when 'idle_temperature' in filament settings " + "is defined."); def->sidetext = "∆°C"; def->min = -max_temp; def->max = max_temp; - //BBS def->mode = comDevelop; def->set_default_value(new ConfigOptionInt(-5)); @@ -4092,7 +4092,6 @@ void PrintConfigDef::init_fff_params() def->label = L("Single Extruder Multi Material"); def->tooltip = L("Use single nozzle to print multi filament"); def->mode = comAdvanced; - def->readonly = true; def->set_default_value(new ConfigOptionBool(true)); def = this->add("manual_filament_change", coBool); @@ -4913,8 +4912,8 @@ void PrintConfigDef::init_fff_params() def->min = 10; def->set_default_value(new ConfigOptionFloat(90.)); - def = this->add("wipe_tower_extruder", coInt); - def->label = L("Wipe tower extruder"); + def = this->add("wipe_tower_filament", coInt); + def->label = L("Wipe tower"); def->category = L("Extruders"); def->tooltip = L("The extruder to use when printing perimeter of the wipe tower. " "Set to 0 to use the one that is available (non-soluble would be preferred)."); @@ -4961,6 +4960,15 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(10.)); + def = this->add("idle_temperature", coInts); + def->label = L("Idle temperature"); + def->tooltip = L("Nozzle temperature when the tool is currently not used in multi-tool setups." + "This is only used when 'Ooze prevention' is active in Print Settings. Set to 0 to disable."); + def->sidetext = L("°C"); + def->min = 0; + def->max = max_temp; + def->set_default_value(new ConfigOptionInts{0}); + def = this->add("xy_hole_compensation", coFloat); def->label = L("X-Y hole compensation"); def->category = L("Quality"); @@ -5921,7 +5929,9 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va opt_key = "solid_infill_filament"; }else if (opt_key == "perimeter_extruder") { opt_key = "wall_filament"; - } else if (opt_key == "support_material_extruder") { + }else if(opt_key == "wipe_tower_extruder") { + opt_key = "wipe_tower_filament"; + }else if (opt_key == "support_material_extruder") { opt_key = "support_filament"; } else if (opt_key == "support_material_interface_extruder") { opt_key = "support_interface_filament"; @@ -5988,8 +5998,6 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va } else { opt_key = "wall_sequence"; } - } else if(opt_key == "single_extruder_multi_material") { - value = "1"; } else if(opt_key == "ensure_vertical_shell_thickness") { if(value == "1") { @@ -7243,10 +7251,9 @@ ReadWriteSlicingStatesConfigDef::ReadWriteSlicingStatesConfigDef() def->label = L("Extra deretraction"); def->tooltip = L("Currently planned extra extruder priming after deretraction."); - // Options from PS not used in Orca -// def = this->add("e_position", coFloats); -// def->label = L("Absolute E position"); -// def->tooltip = L("Current position of the extruder axis. Only used with absolute extruder addressing."); + def = this->add("e_position", coFloats); + def->label = L("Absolute E position"); + def->tooltip = L("Current position of the extruder axis. Only used with absolute extruder addressing."); } OtherSlicingStatesConfigDef::OtherSlicingStatesConfigDef() @@ -7488,10 +7495,9 @@ OtherPresetsConfigDef::OtherPresetsConfigDef() def->label = L("Physical printer name"); def->tooltip = L("Name of the physical printer used for slicing."); - // Options from PS not used in Orca - // def = this->add("num_extruders", coInt); - // def->label = L("Number of extruders"); - // def->tooltip = L("Total number of extruders, regardless of whether they are used in the current print."); + def = this->add("num_extruders", coInt); + def->label = L("Number of extruders"); + def->tooltip = L("Total number of extruders, regardless of whether they are used in the current print."); } diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 67cdfef999..3401423eb4 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1244,9 +1244,11 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( // Orca: mmu support ((ConfigOptionFloat, wipe_tower_cone_angle)) ((ConfigOptionPercent, wipe_tower_extra_spacing)) - ((ConfigOptionFloat, wipe_tower_max_purge_speed)) - ((ConfigOptionInt, wipe_tower_extruder)) + ((ConfigOptionFloat, wipe_tower_max_purge_speed)) + ((ConfigOptionInt, wipe_tower_filament)) ((ConfigOptionFloats, wiping_volumes_extruders)) + ((ConfigOptionInts, idle_temperature)) + // BBS: wipe tower is only used for priming ((ConfigOptionFloat, prime_volume)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 907cc9c248..6112159585 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -2888,7 +2888,7 @@ static void apply_to_print_region_config(PrintRegionConfig &out, const DynamicPr // 1) Copy the "extruder key to sparse_infill_filament and wall_filament. auto *opt_extruder = in.opt(key_extruder); if (opt_extruder) - if (int extruder = opt_extruder->value; extruder != 0) { + if (int extruder = opt_extruder->value; extruder != 1) { // Not a default extruder. out.sparse_infill_filament .value = extruder; out.solid_infill_filament.value = extruder; diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 52d1ea99a6..be5bb65a51 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -675,7 +675,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co bool purge_in_primetower = preset_bundle->printers.get_edited_preset().config.opt_bool("purge_in_prime_tower"); - for (auto el : {"wipe_tower_rotation_angle", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_max_purge_speed", "wipe_tower_bridging", "wipe_tower_no_sparse_layers"}) + for (auto el : {"wipe_tower_rotation_angle", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_max_purge_speed", "wipe_tower_bridging", "wipe_tower_no_sparse_layers", "single_extruder_multi_material_priming"}) toggle_line(el, have_prime_tower && purge_in_primetower); toggle_line("prime_volume",have_prime_tower && !purge_in_primetower); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 842909985b..19a4d42c4a 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -3982,16 +3982,18 @@ void GUI_App::on_http_error(wxCommandEvent &evt) wxString result; if (status >= 400 && status < 500) { try { - json j = json::parse(evt.GetString()); - if (j.contains("code")) { - if (!j["code"].is_null()) - code = j["code"].get(); + auto evt_str = evt.GetString(); + if (!evt_str.empty()) { + json j = json::parse(evt_str); + if (j.contains("code")) { + if (!j["code"].is_null()) + code = j["code"].get(); + } + if (j.contains("error")) + if (!j["error"].is_null()) + error = j["error"].get(); } - if (j.contains("error")) - if (!j["error"].is_null()) - error = j["error"].get(); - } - catch (...) {} + } catch (...) {} } // Version limit diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index b3bcfb2f7f..0b63afd342 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1224,6 +1224,8 @@ void Sidebar::update_all_preset_comboboxes() p->m_filament_icon->SetBitmap_("filament"); } + show_add_del_filament_button(cfg.opt_bool("single_extruder_multi_material")); + //p->m_staticText_filament_settings->Update(); @@ -1327,6 +1329,7 @@ void Sidebar::update_presets(Preset::Type preset_type) /* update bed shape */ Tab* printer_tab = wxGetApp().get_tab(Preset::TYPE_PRINTER); if (printer_tab) { + printer_tab->on_preset_loaded(); printer_tab->update(); } @@ -1786,6 +1789,15 @@ void Sidebar::sync_ams_list() Layout(); } +void Sidebar::show_add_del_filament_button(bool bshow) +{ + if(p->m_bpButton_add_filament) + p->m_bpButton_add_filament->Show(bshow); + if(p->m_bpButton_del_filament) + p->m_bpButton_del_filament->Show(bshow); + Layout(); +} + ObjectList* Sidebar::obj_list() { // BBS @@ -2703,7 +2715,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) "brim_width", "wall_loops", "wall_filament", "sparse_infill_density", "sparse_infill_filament", "top_shell_layers", "enable_support", "support_filament", "support_interface_filament", "support_top_z_distance", "support_bottom_z_distance", "raft_layers", - "wipe_tower_rotation_angle", "wipe_tower_cone_angle", "wipe_tower_extra_spacing","wipe_tower_max_purge_speed", "wipe_tower_extruder", + "wipe_tower_rotation_angle", "wipe_tower_cone_angle", "wipe_tower_extra_spacing","wipe_tower_max_purge_speed", "wipe_tower_filament", "best_object_pos" })) , sidebar(new Sidebar(q)) diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index bda2ab6110..95a08c1827 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -148,6 +148,8 @@ public: void load_ams_list(std::string const & device, MachineObject* obj); std::map build_filament_ams_list(MachineObject* obj); void sync_ams_list(); + // Orca + void show_add_del_filament_button(bool bshow); ObjectList* obj_list(); ObjectSettings* obj_settings(); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 6db2ff4c37..163b9b7d51 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -27,6 +27,7 @@ #include #include #include "libslic3r/libslic3r.h" +#include "slic3r/GUI/OptionsGroup.hpp" #include "wxExtensions.hpp" #include "PresetComboBoxes.hpp" #include @@ -1431,8 +1432,8 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) } - if (opt_key == "single_extruder_multi_material" || opt_key == "extruders_count" ) - update_wiping_button_visibility(); + if (opt_key == "single_extruder_multi_material" ) + wxGetApp().sidebar().show_add_del_filament_button(m_config->opt_bool("single_extruder_multi_material")); if (opt_key == "enable_prime_tower") { auto timelapse_type = m_config->option>("timelapse_type"); @@ -1645,11 +1646,16 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) } - // BBS -#if 0 - if (opt_key == "extruders_count") - wxGetApp().plater()->on_extruders_change(boost::any_cast(value)); -#endif + //Orca: sync filament num if it's a multi tool printer + if (opt_key == "extruders_count" && !m_config->opt_bool("single_extruder_multi_material")){ + auto num_extruder = boost::any_cast(value); + wxColour new_col = Plater::get_next_color_for_filament(); + std::string new_color = new_col.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(); + wxGetApp().preset_bundle->set_num_filaments(num_extruder, new_color); + wxGetApp().plater()->on_filaments_change(num_extruder); + wxGetApp().get_tab(Preset::TYPE_PRINT)->update(); + wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config); + } if (m_postpone_update_ui) { // It means that not all values are rolled to the system/last saved values jet. @@ -1658,7 +1664,8 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) } update(); - m_active_page->update_visibility(m_mode, true); + if(m_active_page) + m_active_page->update_visibility(m_mode, true); m_page_view->GetParent()->Layout(); } @@ -1677,14 +1684,16 @@ void Tab::show_timelapse_warning_dialog() { void Tab::update_wiping_button_visibility() { if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA) return; // ys_FIXME - bool wipe_tower_enabled = dynamic_cast( (m_preset_bundle->prints.get_edited_preset().config ).option("enable_prime_tower"))->value; - bool multiple_extruders = dynamic_cast((m_preset_bundle->printers.get_edited_preset().config).option("nozzle_diameter"))->values.size() > 1; + // Orca: it's not used + // + // bool wipe_tower_enabled = dynamic_cast( (m_preset_bundle->prints.get_edited_preset().config ).option("enable_prime_tower"))->value; + // bool multiple_extruders = dynamic_cast((m_preset_bundle->printers.get_edited_preset().config).option("nozzle_diameter"))->values.size() > 1; + // auto wiping_dialog_button = wxGetApp().sidebar().get_wiping_dialog_button(); + // if (wiping_dialog_button) { + // wiping_dialog_button->Show(wipe_tower_enabled && multiple_extruders); + // wiping_dialog_button->GetParent()->Layout(); + // } - auto wiping_dialog_button = wxGetApp().sidebar().get_wiping_dialog_button(); - if (wiping_dialog_button) { - wiping_dialog_button->Show(wipe_tower_enabled && multiple_extruders); - wiping_dialog_button->GetParent()->Layout(); - } } void Tab::activate_option(const std::string& opt_key, const wxString& category) @@ -2288,8 +2297,17 @@ void TabPrint::build() optgroup->append_single_option_line("wipe_tower_extra_spacing"); optgroup->append_single_option_line("wipe_tower_max_purge_speed"); optgroup->append_single_option_line("wipe_tower_no_sparse_layers"); - // optgroup->append_single_option_line("single_extruder_multi_material_priming"); + optgroup->append_single_option_line("single_extruder_multi_material_priming"); + optgroup = page->new_optgroup(L("Filament for Features")); + optgroup->append_single_option_line("wall_filament"); + optgroup->append_single_option_line("sparse_infill_filament"); + optgroup->append_single_option_line("solid_infill_filament"); + optgroup->append_single_option_line("wipe_tower_filament"); + + optgroup = page->new_optgroup(L("Ooze prevention")); + optgroup->append_single_option_line("ooze_prevention"); + optgroup->append_single_option_line("standby_temperature_delta"); optgroup = page->new_optgroup(L("Flush options"), L"param_flush"); optgroup->append_single_option_line("flush_into_infill", "reduce-wasting-during-filament-change#wipe-into-infill"); @@ -2312,7 +2330,7 @@ void TabPrint::build() optgroup = page->new_optgroup(L("Advanced"), L"advanced"); optgroup->append_single_option_line("interlocking_beam"); - // optgroup->append_single_option_line("mmu_segmented_region_max_width"); + optgroup->append_single_option_line("mmu_segmented_region_max_width"); optgroup->append_single_option_line("mmu_segmented_region_interlocking_depth"); optgroup->append_single_option_line("interlocking_beam_width"); optgroup->append_single_option_line("interlocking_orientation"); @@ -3234,6 +3252,7 @@ void TabFilament::build() optgroup->append_single_option_line("filament_cost"); //BBS optgroup->append_single_option_line("temperature_vitrification"); + optgroup->append_single_option_line("idle_temperature"); Line line = { L("Recommended nozzle temperature"), L("Recommended nozzle temperature range of this filament. 0 means no set") }; line.append_option(optgroup->get_option("nozzle_temperature_range_low")); line.append_option(optgroup->get_option("nozzle_temperature_range_high")); @@ -3438,6 +3457,7 @@ void TabFilament::build() }); // Orca: multi tool is not supported yet. +#define ORCA_MULTI_TOOL #ifdef ORCA_MULTI_TOOL optgroup = page->new_optgroup(L("Toolchange parameters with multi extruder MM printers")); optgroup->append_single_option_line("filament_multitool_ramming"); @@ -3660,18 +3680,6 @@ void TabPrinter::build_fff() optgroup->append_single_option_line("z_offset"); optgroup->append_single_option_line("preferred_orientation"); - // ConfigOptionDef def; - // def.type = coInt, - // def.set_default_value(new ConfigOptionInt(1)); - // def.label = L("Extruders"); - // def.tooltip = L("Number of extruders of the printer."); - // def.min = 1; - // def.max = 256; - // //BBS - // def.mode = comDevelop; - // Option option(def, "extruders_count"); - // optgroup->append_single_option_line(option); - optgroup = page->new_optgroup(L("Advanced"), L"param_advanced"); optgroup->append_single_option_line("printer_structure"); optgroup->append_single_option_line("gcode_flavor"); @@ -3947,12 +3955,10 @@ void TabPrinter::extruders_count_changed(size_t extruders_count) m_preset_bundle->update_multi_material_filament_presets(); is_count_changed = true; } - // BBS -#if 0 + // Orca: support multi tool else if (m_extruders_count == 1 && m_preset_bundle->project_config.option("flush_volumes_matrix")->values.size()>1) m_preset_bundle->update_multi_material_filament_presets(); -#endif /* This function should be call in any case because of correct updating/rebuilding * of unregular pages of a Printer Settings @@ -4086,14 +4092,86 @@ if (is_marlin_flavor) auto page = add_options_page(L("Multimaterial"), "custom-gcode_multi_material", true); // ORCA: icon only visible on placeholders auto optgroup = page->new_optgroup(L("Single extruder multimaterial setup"), "param_multi_material"); optgroup->append_single_option_line("single_extruder_multi_material", "semm"); - // Orca: we only support Single Extruder Multi Material, so it's always enabled - // optgroup->m_on_change = [this](const t_config_option_key &opt_key, const boost::any &value) { - // wxTheApp->CallAfter([this, opt_key, value]() { - // if (opt_key == "single_extruder_multi_material") { - // build_unregular_pages(); - // } - // }); - // }; + ConfigOptionDef def; + def.type = coInt, def.set_default_value(new ConfigOptionInt((int) m_extruders_count)); + def.label = L("Extruders"); + def.tooltip = L("Number of extruders of the printer."); + def.min = 1; + def.max = 256; + def.mode = comAdvanced; + Option option(def, "extruders_count"); + optgroup->append_single_option_line(option); + + // Orca: rebuild missed extruder pages + optgroup->m_on_change = [this, optgroup_wk = ConfigOptionsGroupWkp(optgroup)](t_config_option_key opt_key, boost::any value) { + auto optgroup_sh = optgroup_wk.lock(); + if (!optgroup_sh) + return; + + // optgroup->get_value() return int for def.type == coInt, + // Thus, there should be boost::any_cast ! + // Otherwise, boost::any_cast causes an "unhandled unknown exception" + size_t extruders_count = size_t(boost::any_cast(optgroup_sh->get_value("extruders_count"))); + wxTheApp->CallAfter([this, opt_key, value, extruders_count]() { + if (opt_key == "extruders_count" || opt_key == "single_extruder_multi_material") { + extruders_count_changed(extruders_count); + init_options_list(); // m_options_list should be updated before UI updating + update_dirty(); + if (opt_key == "single_extruder_multi_material") { // the single_extruder_multimaterial was added to force pages + on_value_change(opt_key, value); // rebuild - let's make sure the on_value_change is not skipped + + if (boost::any_cast(value) && m_extruders_count > 1) { + SuppressBackgroundProcessingUpdate sbpu; + +// Orca: we use a different logic here. If SEMM is enabled, we set extruder count to 1. +#if 1 + extruders_count_changed(1); +#else + + std::vector nozzle_diameters = + static_cast(m_config->option("nozzle_diameter"))->values; + const double frst_diam = nozzle_diameters[0]; + + for (auto cur_diam : nozzle_diameters) { + // if value is differs from first nozzle diameter value + if (fabs(cur_diam - frst_diam) > EPSILON) { + const wxString msg_text = _( + L("Single Extruder Multi Material is selected, \n" + "and all extruders must have the same diameter.\n" + "Do you want to change the diameter for all extruders to first extruder nozzle diameter value?")); + MessageDialog dialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO); + + DynamicPrintConfig new_conf = *m_config; + if (dialog.ShowModal() == wxID_YES) { + for (size_t i = 1; i < nozzle_diameters.size(); i++) + nozzle_diameters[i] = frst_diam; + + new_conf.set_key_value("nozzle_diameter", new ConfigOptionFloats(nozzle_diameters)); + } else + new_conf.set_key_value("single_extruder_multi_material", new ConfigOptionBool(false)); + + load_config(new_conf); + break; + } + } +#endif + } + + m_preset_bundle->update_compatible(PresetSelectCompatibleType::Never); + // Upadte related comboboxes on Sidebar and Tabs + Sidebar& sidebar = wxGetApp().plater()->sidebar(); + for (const Preset::Type& type : {Preset::TYPE_PRINT, Preset::TYPE_FILAMENT}) { + sidebar.update_presets(type); + wxGetApp().get_tab(type)->update_tab_ui(); + } + } + } + else { + update_dirty(); + on_value_change(opt_key, value); + } + }); + }; optgroup->append_single_option_line("manual_filament_change", "semm#manual-filament-change"); optgroup = page->new_optgroup(L("Wipe tower"), "param_tower"); @@ -4110,140 +4188,138 @@ if (is_marlin_flavor) m_pages.insert(m_pages.end() - n_after_single_extruder_MM, page); } - // BBS. Just create one extruder page because BBL machine has only on physical extruder. - // Build missed extruder pages - //for (auto extruder_idx = m_extruders_count_old; extruder_idx < m_extruders_count; ++extruder_idx) - auto extruder_idx = 0; - const wxString& page_name = (m_extruders_count > 1) ? wxString::Format("Extruder %d", int(extruder_idx + 1)) : wxString::Format("Extruder"); - bool page_exist = false; - for (auto page_temp : m_pages) { - if (page_temp->title() == page_name) { - page_exist = true; - break; + // Orca: build missed extruder pages + for (auto extruder_idx = m_extruders_count_old; extruder_idx < m_extruders_count; ++extruder_idx) { + // auto extruder_idx = 0; + const wxString& page_name = wxString::Format("Extruder %d", int(extruder_idx + 1)); + bool page_exist = false; + for (auto page_temp : m_pages) { + if (page_temp->title() == page_name) { + page_exist = true; + break; + } } - } - if (!page_exist) - { - //# build page - //const wxString& page_name = wxString::Format("Extruder %d", int(extruder_idx + 1)); - auto page = add_options_page(page_name, "custom-gcode_extruder", true); // ORCA: icon only visible on placeholders - m_pages.insert(m_pages.begin() + n_before_extruders + extruder_idx, page); + if (!page_exist) + { + //# build page + //const wxString& page_name = wxString::Format("Extruder %d", int(extruder_idx + 1)); + auto page = add_options_page(page_name, "custom-gcode_extruder", true); // ORCA: icon only visible on placeholders + m_pages.insert(m_pages.begin() + n_before_extruders + extruder_idx, page); - auto optgroup = page->new_optgroup(L("Size"), L"param_extruder_size", -1, true); - optgroup->append_single_option_line("nozzle_diameter", "", extruder_idx); + auto optgroup = page->new_optgroup(L("Size"), L"param_extruder_size"); + optgroup->append_single_option_line("nozzle_diameter", "", extruder_idx); - optgroup->m_on_change = [this, extruder_idx](const t_config_option_key& opt_key, boost::any value) - { - //if (m_config->opt_bool("single_extruder_multi_material") && m_extruders_count > 1 && opt_key.find_first_of("nozzle_diameter") != std::string::npos) - //{ - // SuppressBackgroundProcessingUpdate sbpu; - // const double new_nd = boost::any_cast(value); - // std::vector nozzle_diameters = static_cast(m_config->option("nozzle_diameter"))->values; + optgroup->m_on_change = [this, extruder_idx](const t_config_option_key& opt_key, boost::any value) + { + bool is_SEMM = m_config->opt_bool("single_extruder_multi_material"); + if (is_SEMM && m_extruders_count > 1 && opt_key.find_first_of("nozzle_diameter") != std::string::npos) + { + SuppressBackgroundProcessingUpdate sbpu; + const double new_nd = boost::any_cast(value); + std::vector nozzle_diameters = static_cast(m_config->option("nozzle_diameter"))->values; - // // if value was changed - // if (fabs(nozzle_diameters[extruder_idx == 0 ? 1 : 0] - new_nd) > EPSILON) + // if value was changed + if (fabs(nozzle_diameters[extruder_idx == 0 ? 1 : 0] - new_nd) > EPSILON) + { + const wxString msg_text = _(L("This is a single extruder multimaterial printer, diameters of all extruders " + "will be set to the new value. Do you want to proceed?")); + //wxMessageDialog dialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO); + MessageDialog dialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO); + + DynamicPrintConfig new_conf = *m_config; + if (dialog.ShowModal() == wxID_YES) { + for (size_t i = 0; i < nozzle_diameters.size(); i++) { + if (i == extruder_idx) + continue; + nozzle_diameters[i] = new_nd; + } + } + else + nozzle_diameters[extruder_idx] = nozzle_diameters[extruder_idx == 0 ? 1 : 0]; + + new_conf.set_key_value("nozzle_diameter", new ConfigOptionFloats(nozzle_diameters)); + load_config(new_conf); + } + } + + update_dirty(); + update(); + }; + + optgroup = page->new_optgroup(L("Layer height limits"), L"param_layer_height"); + optgroup->append_single_option_line("min_layer_height", "", extruder_idx); + optgroup->append_single_option_line("max_layer_height", "", extruder_idx); + + optgroup = page->new_optgroup(L("Position"), L"param_position"); + optgroup->append_single_option_line("extruder_offset", "", extruder_idx); + + //BBS: don't show retract related config menu in machine page + optgroup = page->new_optgroup(L("Retraction"), L"param_retraction"); + optgroup->append_single_option_line("retraction_length", "", extruder_idx); + optgroup->append_single_option_line("retract_restart_extra", "", extruder_idx); + optgroup->append_single_option_line("z_hop", "", extruder_idx); + optgroup->append_single_option_line("z_hop_types", "", extruder_idx); + optgroup->append_single_option_line("travel_slope", "", extruder_idx); + optgroup->append_single_option_line("retraction_speed", "", extruder_idx); + optgroup->append_single_option_line("deretraction_speed", "", extruder_idx); + optgroup->append_single_option_line("retraction_minimum_travel", "", extruder_idx); + optgroup->append_single_option_line("retract_when_changing_layer", "", extruder_idx); + optgroup->append_single_option_line("wipe", "", extruder_idx); + optgroup->append_single_option_line("wipe_distance", "", extruder_idx); + optgroup->append_single_option_line("retract_before_wipe", "", extruder_idx); + + optgroup = page->new_optgroup(L("Lift Z Enforcement"), L"param_extruder_lift_enforcement"); + optgroup->append_single_option_line("retract_lift_above", "", extruder_idx); + optgroup->append_single_option_line("retract_lift_below", "", extruder_idx); + optgroup->append_single_option_line("retract_lift_enforce", "", extruder_idx); + + optgroup = page->new_optgroup(L("Retraction when switching material"), L"param_retraction_material_change"); + optgroup->append_single_option_line("retract_length_toolchange", "", extruder_idx); + optgroup->append_single_option_line("retract_restart_extra_toolchange", "", extruder_idx); + // do not display this params now + optgroup->append_single_option_line("long_retractions_when_cut", "", extruder_idx); + optgroup->append_single_option_line("retraction_distances_when_cut", "", extruder_idx); + + #if 0 + //optgroup = page->new_optgroup(L("Preview"), -1, true); + + //auto reset_to_filament_color = [this, extruder_idx](wxWindow* parent) { + // m_reset_to_filament_color = new ScalableButton(parent, wxID_ANY, "undo", _L("Reset to Filament Color"), + // wxDefaultSize, wxDefaultPosition, wxBU_LEFT | wxBU_EXACTFIT, true); + // ScalableButton* btn = m_reset_to_filament_color; + // btn->SetFont(Slic3r::GUI::wxGetApp().normal_font()); + // btn->SetSize(btn->GetBestSize()); + // auto sizer = new wxBoxSizer(wxHORIZONTAL); + // sizer->Add(btn); + + // btn->Bind(wxEVT_BUTTON, [this, extruder_idx](wxCommandEvent& e) // { - // const wxString msg_text = _(L("This is a single extruder multimaterial printer, diameters of all extruders " - // "will be set to the new value. Do you want to proceed?")); - // //wxMessageDialog dialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO); - // MessageDialog dialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO); + // std::vector colors = static_cast(m_config->option("extruder_colour"))->values; + // colors[extruder_idx] = ""; // DynamicPrintConfig new_conf = *m_config; - // if (dialog.ShowModal() == wxID_YES) { - // for (size_t i = 0; i < nozzle_diameters.size(); i++) { - // if (i==extruder_idx) - // continue; - // nozzle_diameters[i] = new_nd; - // } - // } - // else - // nozzle_diameters[extruder_idx] = nozzle_diameters[extruder_idx == 0 ? 1 : 0]; - - // new_conf.set_key_value("nozzle_diameter", new ConfigOptionFloats(nozzle_diameters)); + // new_conf.set_key_value("extruder_colour", new ConfigOptionStrings(colors)); // load_config(new_conf); - // } - //} - update_dirty(); - update(); - }; - - optgroup = page->new_optgroup(L("Layer height limits"), L"param_layer_height", -1, true); - optgroup->append_single_option_line("min_layer_height", "", extruder_idx); - optgroup->append_single_option_line("max_layer_height", "", extruder_idx); - - optgroup = page->new_optgroup(L("Position"), L"param_position", -1, true); - optgroup->append_single_option_line("extruder_offset", "", extruder_idx); - - //BBS: don't show retract related config menu in machine page - optgroup = page->new_optgroup(L("Retraction"), L"param_retraction"); - optgroup->append_single_option_line("retraction_length", "", extruder_idx); - optgroup->append_single_option_line("retract_restart_extra", "", extruder_idx); - optgroup->append_single_option_line("z_hop", "", extruder_idx); - optgroup->append_single_option_line("z_hop_types", "", extruder_idx); - optgroup->append_single_option_line("travel_slope", "", extruder_idx); - optgroup->append_single_option_line("retraction_speed", "", extruder_idx); - optgroup->append_single_option_line("deretraction_speed", "", extruder_idx); - optgroup->append_single_option_line("retraction_minimum_travel", "", extruder_idx); - optgroup->append_single_option_line("retract_when_changing_layer", "", extruder_idx); - optgroup->append_single_option_line("wipe", "", extruder_idx); - optgroup->append_single_option_line("wipe_distance", "", extruder_idx); - optgroup->append_single_option_line("retract_before_wipe", "", extruder_idx); - - optgroup = page->new_optgroup(L("Lift Z Enforcement"), L"param_extruder_lift_enforcement", -1, true); - optgroup->append_single_option_line("retract_lift_above", "", extruder_idx); - optgroup->append_single_option_line("retract_lift_below", "", extruder_idx); - optgroup->append_single_option_line("retract_lift_enforce", "", extruder_idx); - - optgroup = page->new_optgroup(L("Retraction when switching material"), L"param_retraction_material_change", -1, true); - optgroup->append_single_option_line("retract_length_toolchange", "", extruder_idx); - optgroup->append_single_option_line("retract_restart_extra_toolchange", "", extruder_idx); - // do not display this params now - optgroup->append_single_option_line("long_retractions_when_cut", "", extruder_idx); - optgroup->append_single_option_line("retraction_distances_when_cut", "", extruder_idx); - -#if 0 - //optgroup = page->new_optgroup(L("Preview"), -1, true); - - //auto reset_to_filament_color = [this, extruder_idx](wxWindow* parent) { - // m_reset_to_filament_color = new ScalableButton(parent, wxID_ANY, "undo", _L("Reset to Filament Color"), - // wxDefaultSize, wxDefaultPosition, wxBU_LEFT | wxBU_EXACTFIT, true); - // ScalableButton* btn = m_reset_to_filament_color; - // btn->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - // btn->SetSize(btn->GetBestSize()); - // auto sizer = new wxBoxSizer(wxHORIZONTAL); - // sizer->Add(btn); - - // btn->Bind(wxEVT_BUTTON, [this, extruder_idx](wxCommandEvent& e) - // { - // std::vector colors = static_cast(m_config->option("extruder_colour"))->values; - // colors[extruder_idx] = ""; - - // DynamicPrintConfig new_conf = *m_config; - // new_conf.set_key_value("extruder_colour", new ConfigOptionStrings(colors)); - // load_config(new_conf); - - // update_dirty(); - // update(); - // }); - - // return sizer; - //}; - ////BBS - //Line line = optgroup->create_single_option_line("extruder_colour", "", extruder_idx); - //line.append_widget(reset_to_filament_color); - //optgroup->append_line(line); -#endif - } + // update_dirty(); + // update(); + // }); + // return sizer; + //}; + ////BBS + //Line line = optgroup->create_single_option_line("extruder_colour", "", extruder_idx); + //line.append_widget(reset_to_filament_color); + //optgroup->append_line(line); + #endif + } +} // BBS. No extra extruder page for single physical extruder machine // # remove extra pages -#if 0 if (m_extruders_count < m_extruders_count_old) m_pages.erase( m_pages.begin() + n_before_extruders + m_extruders_count, m_pages.begin() + n_before_extruders + m_extruders_count_old); -#endif Thaw(); @@ -4264,15 +4340,12 @@ if (is_marlin_flavor) // this gets executed after preset is loaded and before GUI fields are updated void TabPrinter::on_preset_loaded() { - // BBS -#if 0 + // Orca // update the extruders count field auto *nozzle_diameter = dynamic_cast(m_config->option("nozzle_diameter")); size_t extruders_count = nozzle_diameter->values.size(); // update the GUI field according to the number of nozzle diameters supplied extruders_count_changed(extruders_count); -#endif - build_unregular_pages(); } void TabPrinter::update_pages() @@ -4319,7 +4392,7 @@ void TabPrinter::reload_config() // "extruders_count" doesn't update from the update_config(), // so update it implicitly - if (m_active_page && m_active_page->title() == "General") + if (m_active_page && m_active_page->title() == "Multimaterial") m_active_page->set_value("extruders_count", int(m_extruders_count)); } @@ -4329,7 +4402,7 @@ void TabPrinter::activate_selected_page(std::function throw_if_canceled) // "extruders_count" doesn't update from the update_config(), // so update it implicitly - if (m_active_page && m_active_page->title() == "General") + if (m_active_page && m_active_page->title() == "Multimaterial") m_active_page->set_value("extruders_count", int(m_extruders_count)); } @@ -4368,13 +4441,19 @@ void TabPrinter::toggle_options() } if (m_active_page->title() == L("Multimaterial")) { - // toggle_option("single_extruder_multi_material", have_multiple_extruders); - // SoftFever: hide specific settings for BBL printer for (auto el : {"purge_in_prime_tower", "enable_filament_ramming", "cooling_tube_retraction", "cooling_tube_length", "parking_pos_retraction", "extra_loading_move", "high_current_on_filament_swap", }) toggle_option(el, !is_BBL_printer); + auto bSEMM = m_config->opt_bool("single_extruder_multi_material"); + if (!bSEMM && m_config->opt_bool("manual_filament_change")) { + DynamicPrintConfig new_conf = *m_config; + new_conf.set_key_value("manual_filament_change", new ConfigOptionBool(false)); + load_config(new_conf); + } + toggle_option("extruders_count", !bSEMM); + toggle_option("manual_filament_change", bSEMM); } wxString extruder_number; long val = 1; From 8ff7b0fac231b1c0be4bf74866c39f1d1574574d Mon Sep 17 00:00:00 2001 From: SoftFever Date: Sun, 7 Jul 2024 00:11:37 +0800 Subject: [PATCH 02/32] dynamic list --- src/libslic3r/PrintConfig.cpp | 10 +++--- src/slic3r/GUI/Plater.cpp | 60 +++++++++++++++++++++++++++++++++-- src/slic3r/GUI/Tab.cpp | 13 ++++++-- 3 files changed, 72 insertions(+), 11 deletions(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 2c3798dd08..a44fa6ebbb 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2715,6 +2715,7 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionBool(false)); def = this->add("sparse_infill_filament", coInt); + def->gui_type = ConfigOptionDef::GUIType::i_enum_open; def->label = L("Infill"); def->category = L("Extruders"); def->tooltip = L("Filament to print internal sparse infill."); @@ -3390,9 +3391,7 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionBool(true)); def = this->add("wall_filament", coInt); - //def->label = L("Walls"); - //def->category = L("Extruders"); - //def->tooltip = L("Filament to print walls"); + def->gui_type = ConfigOptionDef::GUIType::i_enum_open; def->label = "Walls"; def->category = "Extruders"; def->tooltip = "Filament to print walls"; @@ -3983,9 +3982,7 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionFloat(15)); def = this->add("solid_infill_filament", coInt); - //def->label = L("Solid infill"); - //def->category = L("Extruders"); - //def->tooltip = L("Filament to print solid infill"); + def->gui_type = ConfigOptionDef::GUIType::i_enum_open; def->label = "Solid infill"; def->category = "Extruders"; def->tooltip = "Filament to print solid infill"; @@ -4913,6 +4910,7 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionFloat(90.)); def = this->add("wipe_tower_filament", coInt); + def->gui_type = ConfigOptionDef::GUIType::i_enum_open; def->label = L("Wipe tower"); def->category = L("Extruders"); def->tooltip = L("The extruder to use when printing perimeter of the wipe tower. " diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 0b63afd342..5000424a2a 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -545,7 +545,7 @@ std::vector get_min_flush_volumes(const DynamicPrintConfig& full_config) // Sidebar / public -static struct DynamicFilamentList : DynamicList +struct DynamicFilamentList : DynamicList { std::vector> items; @@ -590,13 +590,69 @@ static struct DynamicFilamentList : DynamicList } DynamicList::update(); } -} dynamic_filament_list; +}; + +struct DynamicFilamentList1Based : DynamicFilamentList +{ + void apply_on(Choice *c) override + { + if (items.empty()) + update(true); + auto cb = dynamic_cast(c->window); + auto n = cb->GetSelection(); + cb->Clear(); + for (auto i : items) { + cb->Append(i.first, *i.second); + } + if (n < cb->GetCount()) + cb->SetSelection(n); + } + wxString get_value(int index) override + { + wxString str; + str << index+1; + return str; + } + int index_of(wxString value) override + { + long n = 0; + if(!value.ToLong(&n)) + return -1; + --n; + return (n >= 0 && n <= items.size()) ? int(n) : -1; + } + void update(bool force = false) + { + items.clear(); + if (!force && m_choices.empty()) + return; + auto icons = get_extruder_color_icons(true); + auto presets = wxGetApp().preset_bundle->filament_presets; + for (int i = 0; i < presets.size(); ++i) { + wxString str; + std::string type; + wxGetApp().preset_bundle->filaments.find_preset(presets[i])->get_filament_type(type); + str << type; + items.push_back({str, icons[i]}); + } + DynamicList::update(); + } + +}; + + +static DynamicFilamentList dynamic_filament_list; +static DynamicFilamentList1Based dynamic_filament_list_1_based; Sidebar::Sidebar(Plater *parent) : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(42 * wxGetApp().em_unit(), -1)), p(new priv(parent)) { Choice::register_dynamic_list("support_filament", &dynamic_filament_list); Choice::register_dynamic_list("support_interface_filament", &dynamic_filament_list); + Choice::register_dynamic_list("wall_filament", &dynamic_filament_list_1_based); + Choice::register_dynamic_list("sparse_infill_filament", &dynamic_filament_list_1_based); + Choice::register_dynamic_list("solid_infill_filament", &dynamic_filament_list_1_based); + Choice::register_dynamic_list("wipe_tower_filament", &dynamic_filament_list); p->scrolled = new wxPanel(this); // p->scrolled->SetScrollbars(0, 100, 1, 2); // ys_DELETE_after_testing. pixelsPerUnitY = 100 diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 163b9b7d51..c974c2f044 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1431,9 +1431,16 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) m_config->set_key_value("pellet_flow_coefficient", new ConfigOptionFloats{double_value}); } + auto bSEMM = m_config->opt_bool("single_extruder_multi_material"); + + if (opt_key == "single_extruder_multi_material" ){ + wxGetApp().sidebar().show_add_del_filament_button(bSEMM); + wxGetApp().get_tab(Preset::TYPE_PRINT)->update(); + } + + if(opt_key == "purge_in_prime_tower") + wxGetApp().get_tab(Preset::TYPE_PRINT)->update(); - if (opt_key == "single_extruder_multi_material" ) - wxGetApp().sidebar().show_add_del_filament_button(m_config->opt_bool("single_extruder_multi_material")); if (opt_key == "enable_prime_tower") { auto timelapse_type = m_config->option>("timelapse_type"); @@ -1647,7 +1654,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) //Orca: sync filament num if it's a multi tool printer - if (opt_key == "extruders_count" && !m_config->opt_bool("single_extruder_multi_material")){ + if (opt_key == "extruders_count" && !bSEMM){ auto num_extruder = boost::any_cast(value); wxColour new_col = Plater::get_next_color_for_filament(); std::string new_color = new_col.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(); From b6a1a06c25a1e13f8ec1f59d6de8753bb1c13a2a Mon Sep 17 00:00:00 2001 From: SoftFever Date: Sun, 7 Jul 2024 00:28:44 +0800 Subject: [PATCH 03/32] fix crash --- src/slic3r/GUI/Tab.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index c974c2f044..7f89e45104 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1431,9 +1431,9 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) m_config->set_key_value("pellet_flow_coefficient", new ConfigOptionFloats{double_value}); } - auto bSEMM = m_config->opt_bool("single_extruder_multi_material"); if (opt_key == "single_extruder_multi_material" ){ + const auto bSEMM = m_config->opt_bool("single_extruder_multi_material"); wxGetApp().sidebar().show_add_del_filament_button(bSEMM); wxGetApp().get_tab(Preset::TYPE_PRINT)->update(); } @@ -1654,7 +1654,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) //Orca: sync filament num if it's a multi tool printer - if (opt_key == "extruders_count" && !bSEMM){ + if (opt_key == "extruders_count" && !m_config->opt_bool("single_extruder_multi_material")){ auto num_extruder = boost::any_cast(value); wxColour new_col = Plater::get_next_color_for_filament(); std::string new_color = new_col.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(); From 1c68d5834311e7aa3f8966bc7d61a222efa2d655 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Mon, 8 Jul 2024 00:35:22 +0800 Subject: [PATCH 04/32] support has_single_extruder_multi_material_priming --- src/libslic3r/GCode.cpp | 35 ++++++++++++--------------- src/libslic3r/Print.cpp | 30 ++++++++++++----------- src/slic3r/GUI/ConfigManipulation.cpp | 3 ++- 3 files changed, 33 insertions(+), 35 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index c46de72179..c9c48fce7d 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2180,16 +2180,13 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato // No object to print was found, cancel the G-code export. throw Slic3r::SlicingError(_(L("No object can be printed. Maybe too small"))); has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower(); - // BBS: priming logic is removed, so 1st layer tool_ordering also respect the object tool sequence -#if 0 + // Orca: support all extruder priming initial_extruder_id = (has_wipe_tower && !print.config().single_extruder_multi_material_priming) ? // The priming towers will be skipped. tool_ordering.all_extruders().back() : // Don't skip the priming towers. tool_ordering.first_extruder(); -#else - initial_extruder_id = tool_ordering.first_extruder(); -#endif + //BBS: try to find the non-support filament extruder if is multi color and initial_extruder is support filament if (initial_extruder_id != static_cast(-1)) { initial_non_support_extruder_id = initial_extruder_id; @@ -2270,7 +2267,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato this->placeholder_parser().set("current_object_idx", 0); // For the start / end G-code to do the priming and final filament pull in case there is no wipe tower provided. this->placeholder_parser().set("has_wipe_tower", has_wipe_tower); - //this->placeholder_parser().set("has_single_extruder_multi_material_priming", has_wipe_tower && print.config().single_extruder_multi_material_priming); + this->placeholder_parser().set("has_single_extruder_multi_material_priming", has_wipe_tower && print.config().single_extruder_multi_material_priming); this->placeholder_parser().set("total_toolchanges", std::max(0, print.wipe_tower_data().number_of_toolchanges)); // Check for negative toolchanges (single extruder mode) and set to 0 (no tool change). this->placeholder_parser().set("num_extruders", int(print.config().nozzle_diameter.values.size())); this->placeholder_parser().set("retract_length", new ConfigOptionFloats(print.config().retraction_length)); @@ -2511,8 +2508,8 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato } } - // BBS: priming logic is removed, always set first extruer here. - //if (! (has_wipe_tower && print.config().single_extruder_multi_material_priming)) + // Orca: support extruder priming + if (! (has_wipe_tower && print.config().single_extruder_multi_material_priming)) { // Set initial extruder only after custom start G-code. // Ugly hack: Do not set the initial extruder if the extruder is primed using the MMU priming towers at the edge of the print bed. @@ -2642,7 +2639,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato m_wipe_tower.reset(new WipeTowerIntegration(print.config(), print.get_plate_index(), print.get_plate_origin(), * print.wipe_tower_data().priming.get(), print.wipe_tower_data().tool_changes, *print.wipe_tower_data().final_purge.get())); //BBS file.write(m_writer.travel_to_z(initial_layer_print_height + m_config.z_offset.value, "Move to the first layer height")); - #if 0 + if (print.config().single_extruder_multi_material_priming) { file.write(m_wipe_tower->prime(*this)); // Verify, whether the print overaps the priming extrusions. @@ -2667,19 +2664,17 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato file.write("M1 S10\n"); } } - //BBS: only support Marlin - //else { + else { // This is not Marlin, M1 command is probably not supported. - //if (overlap) { - // print.active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, - // _(L("Your print is very close to the priming regions. " - // "Make sure there is no collision."))); - //} else { - // // Just continue printing, no action necessary. - //} - //} + if (overlap) { + print.active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, + _(L("Your print is very close to the priming regions. " + "Make sure there is no collision."))); + } else { + // Just continue printing, no action necessary. + } + } } - #endif print.throw_if_canceled(); } // Process all layers of all objects (non-sequential mode) with a parallel pipeline: diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 5e5f4bf284..6bb1ff8508 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -2061,14 +2061,6 @@ void Print::process(long long *time_cost_with_cache, bool use_cache) tool_ordering = this->tool_ordering(); tool_ordering.assign_custom_gcodes(*this); has_wipe_tower = this->has_wipe_tower() && tool_ordering.has_wipe_tower(); - //BBS: have no single_extruder_multi_material_priming -#if 0 - initial_extruder_id = (has_wipe_tower && !this->config().single_extruder_multi_material_priming) ? - // The priming towers will be skipped. - tool_ordering.all_extruders().back() : - // Don't skip the priming towers. - tool_ordering.first_extruder(); -#endif initial_extruder_id = tool_ordering.first_extruder(); print_object_instances_ordering = chain_print_object_instances(*this); append(printExtruders, tool_ordering.tools_for_layer(layers_to_print.front().first).extruders); @@ -2581,9 +2573,19 @@ void Print::_make_wipe_tower() for (unsigned int i = 0; i(flush_matrix.begin()+i*number_of_extruders, flush_matrix.begin()+(i+1)*number_of_extruders)); + // Orca: itertate over wipe_volumes and change the non-zero values to the prime_volume + if (!m_config.purge_in_prime_tower && !is_BBL_printer()) { + for (unsigned int i = 0; i < number_of_extruders; ++i) { + for (unsigned int j = 0; j < number_of_extruders; ++j) { + if (wipe_volumes[i][j] > 0) { + wipe_volumes[i][j] = m_config.prime_volume; + } + } + } + } + // Let the ToolOrdering class know there will be initial priming extrusions at the start of the print. - // BBS: priming logic is removed, so don't consider it in tool ordering - m_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int)-1, false); + m_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int)-1, true); if (!m_wipe_tower_data.tool_ordering.has_wipe_tower()) // Don't generate any wipe tower. @@ -2734,13 +2736,13 @@ void Print::_make_wipe_tower() for (size_t i = 0; i < number_of_extruders; ++i) wipe_tower.set_extruder(i, m_config); - // m_wipe_tower_data.priming = Slic3r::make_unique>( - // wipe_tower.prime((float)this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false)); + m_wipe_tower_data.priming = Slic3r::make_unique>( + wipe_tower.prime((float)this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false)); // Lets go through the wipe tower layers and determine pairs of extruder changes for each // to pass to wipe_tower (so that it can use it for planning the layout of the tower) { - unsigned int current_extruder_id = m_wipe_tower_data.tool_ordering.first_extruder(); + unsigned int current_extruder_id = m_wipe_tower_data.tool_ordering.all_extruders().back(); for (auto &layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) { // for all layers if (!layer_tools.has_wipe_tower) continue; @@ -2748,7 +2750,7 @@ void Print::_make_wipe_tower() wipe_tower.plan_toolchange((float) layer_tools.print_z, (float) layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id, false); for (const auto extruder_id : layer_tools.extruders) { - if (/*(first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back()) || */ extruder_id != + if ((first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back()) || extruder_id != current_extruder_id) { float volume_to_wipe = m_config.prime_volume; if (m_config.purge_in_prime_tower) { diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index be5bb65a51..263f57e19b 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -675,8 +675,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co bool purge_in_primetower = preset_bundle->printers.get_edited_preset().config.opt_bool("purge_in_prime_tower"); + // Orca: do we really need to hide these options when not purge_in_primetower? for (auto el : {"wipe_tower_rotation_angle", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_max_purge_speed", "wipe_tower_bridging", "wipe_tower_no_sparse_layers", "single_extruder_multi_material_priming"}) - toggle_line(el, have_prime_tower && purge_in_primetower); + toggle_line(el, have_prime_tower); toggle_line("prime_volume",have_prime_tower && !purge_in_primetower); From 860a41baedf3149778090af20e949f524527a2a6 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Tue, 9 Jul 2024 22:20:36 +0800 Subject: [PATCH 05/32] update wipe tower according to latest PrusaSlicer --- src/libslic3r/GCode/WipeTower2.cpp | 294 +++++++++++++++++--------- src/libslic3r/GCode/WipeTower2.hpp | 37 ++-- src/libslic3r/Preset.cpp | 4 +- src/libslic3r/Print.cpp | 3 + src/libslic3r/PrintConfig.cpp | 24 +++ src/libslic3r/PrintConfig.hpp | 3 + src/slic3r/GUI/ConfigManipulation.cpp | 13 +- src/slic3r/GUI/Plater.cpp | 2 +- src/slic3r/GUI/Tab.cpp | 4 +- 9 files changed, 256 insertions(+), 128 deletions(-) diff --git a/src/libslic3r/GCode/WipeTower2.cpp b/src/libslic3r/GCode/WipeTower2.cpp index 6e96e21150..a22bec5dd8 100644 --- a/src/libslic3r/GCode/WipeTower2.cpp +++ b/src/libslic3r/GCode/WipeTower2.cpp @@ -1,6 +1,4 @@ -// Orca: This file is ported from latest PrusaSlicer - -// Original PrusaSlicer Copyright: +// Orca: WipeTower2 for all non bbl printers, support all MMU device and toolchanger. #include "WipeTower2.hpp" #include @@ -26,6 +24,20 @@ namespace Slic3r { +// Calculates length of extrusion line to extrude given volume +static float volume_to_length(float volume, float line_width, float layer_height) +{ + return std::max(0.f, volume / (layer_height * (line_width - layer_height * (1.f - float(M_PI) / 4.f)))); +} + +static float length_to_volume(float length, float line_width, float layer_height) +{ + return std::max(0.f, length * layer_height * (line_width - layer_height * (1.f - float(M_PI) / 4.f))); +} + + + + class WipeTowerWriter2 { public: @@ -37,12 +49,9 @@ public: m_extrusion_flow(0.f), m_preview_suppressed(false), m_elapsed_time(0.f), -#if ENABLE_GCODE_VIEWER_DATA_CHECKING - m_default_analyzer_line_width(line_width), -#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING - m_gcode_flavor(flavor), - m_filpar(filament_parameters) - { + m_gcode_flavor(flavor), + m_filpar(filament_parameters) + { // ORCA: This class is only used by non BBL printers, so set the parameter appropriately. // This fixes an issue where the wipe tower was using BBL tags resulting in statistics for purging in the purge tower not being displayed. GCodeProcessor::s_IsBBLPrinter = false; @@ -62,18 +71,6 @@ public: return *this; } -#if ENABLE_GCODE_VIEWER_DATA_CHECKING - WipeTowerWriter2& change_analyzer_mm3_per_mm(float len, float e) { - static const float area = float(M_PI) * 1.75f * 1.75f / 4.f; - float mm3_per_mm = (len == 0.f ? 0.f : area * e / len); - // adds tag for processor: - std::stringstream str; - str << ";" << GCodeProcessor::Mm3_Per_Mm_Tag << mm3_per_mm << "\n"; - m_gcode += str.str(); - return *this; - } -#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING - WipeTowerWriter2& set_initial_position(const Vec2f &pos, float width = 0.f, float depth = 0.f, float internal_angle = 0.f) { m_wipe_tower_width = width; m_wipe_tower_depth = depth; @@ -109,16 +106,16 @@ public: return *this; } + WipeTowerWriter2& switch_filament_monitoring(bool enable) { + m_gcode += std::string("G4 S0\n") + "M591 " + (enable ? "R" : "S0") + "\n"; + return *this; + } + // Suppress / resume G-code preview in Slic3r. Slic3r will have difficulty to differentiate the various // filament loading and cooling moves from normal extrusion moves. Therefore the writer // is asked to suppres output of some lines, which look like extrusions. -#if ENABLE_GCODE_VIEWER_DATA_CHECKING - WipeTowerWriter2& suppress_preview() { change_analyzer_line_width(0.f); m_preview_suppressed = true; return *this; } - WipeTowerWriter2& resume_preview() { change_analyzer_line_width(m_default_analyzer_line_width); m_preview_suppressed = false; return *this; } -#else WipeTowerWriter2& suppress_preview() { m_preview_suppressed = true; return *this; } - WipeTowerWriter2& resume_preview() { m_preview_suppressed = false; return *this; } -#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING + WipeTowerWriter2& resume_preview() { m_preview_suppressed = false; return *this; } WipeTowerWriter2& feedrate(float f) { @@ -140,8 +137,8 @@ public: float get_and_reset_used_filament_length() { float temp = m_used_filament_length; m_used_filament_length = 0.f; return temp; } // Extrude with an explicitely provided amount of extrusion. - WipeTowerWriter2& extrude_explicit(float x, float y, float e, float f = 0.f, bool record_length = false, bool limit_volumetric_flow = true) - { + WipeTowerWriter2& extrude_explicit(float x, float y, float e, float f = 0.f, bool record_length = false, bool limit_volumetric_flow = true) + { if (x == m_current_pos.x() && y == m_current_pos.y() && e == 0.f && (f == 0.f || f == m_current_feedrate)) // Neither extrusion nor a travel move. return *this; @@ -157,12 +154,9 @@ public: Vec2f rot(this->rotate(Vec2f(x,y))); // this is where we want to go if (! m_preview_suppressed && e > 0.f && len > 0.f) { -#if ENABLE_GCODE_VIEWER_DATA_CHECKING - change_analyzer_mm3_per_mm(len, e); -#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING - // Width of a squished extrusion, corrected for the roundings of the squished extrusions. + // Width of a squished extrusion, corrected for the roundings of the squished extrusions. // This is left zero if it is a travel move. - float width = e * m_filpar[0].filament_area / (len * m_layer_height); + float width = e * m_filpar[0].filament_area / (len * m_layer_height); // Correct for the roundings of a squished extrusion. width += m_layer_height * float(1. - M_PI / 4.); if (m_extrusions.empty() || m_extrusions.back().pos != rotated_current_pos) @@ -204,17 +198,17 @@ public: return *this; } - WipeTowerWriter2& extrude_explicit(const Vec2f &dest, float e, float f = 0.f, bool record_length = false, bool limit_volumetric_flow = true) - { return extrude_explicit(dest.x(), dest.y(), e, f, record_length); } + WipeTowerWriter2& extrude_explicit(const Vec2f &dest, float e, float f = 0.f, bool record_length = false, bool limit_volumetric_flow = true) + { return extrude_explicit(dest.x(), dest.y(), e, f, record_length); } - // Travel to a new XY position. f=0 means use the current value. + // Travel to a new XY position. f=0 means use the current value. WipeTowerWriter2& travel(float x, float y, float f = 0.f) - { return extrude_explicit(x, y, 0.f, f); } + { return extrude_explicit(x, y, 0.f, f); } - WipeTowerWriter2& travel(const Vec2f &dest, float f = 0.f) - { return extrude_explicit(dest.x(), dest.y(), 0.f, f); } + WipeTowerWriter2& travel(const Vec2f &dest, float f = 0.f) + { return extrude_explicit(dest.x(), dest.y(), 0.f, f); } - // Extrude a line from current position to x, y with the extrusion amount given by m_extrusion_flow. + // Extrude a line from current position to x, y with the extrusion amount given by m_extrusion_flow. WipeTowerWriter2& extrude(float x, float y, float f = 0.f) { float dx = x - m_current_pos.x(); @@ -222,8 +216,8 @@ public: return extrude_explicit(x, y, std::sqrt(dx*dx+dy*dy) * m_extrusion_flow, f, true); } - WipeTowerWriter2& extrude(const Vec2f &dest, const float f = 0.f) - { return extrude(dest.x(), dest.y(), f); } + WipeTowerWriter2& extrude(const Vec2f &dest, const float f = 0.f) + { return extrude(dest.x(), dest.y(), f); } WipeTowerWriter2& rectangle(const Vec2f& ld,float width,float height,const float f = 0.f) { @@ -291,6 +285,25 @@ public: return extrude_explicit(end_point, y(), loading_dist, x_speed * 60.f, false, false); } + // Loads filament while also moving towards given point in x-axis. Unlike the previous function, this one respects + // both the loading_speed and x_speed. Can shorten the move. + WipeTowerWriter2& load_move_x_advanced_there_and_back(float farthest_x, float e_dist, float e_speed, float x_speed) + { + float old_x = x(); + float time = std::abs(e_dist / e_speed); // time that the whole move must take + float x_max_dist = std::abs(farthest_x - x()); // max x-distance that we can travel + float x_dist = x_speed * time; // totel x-distance to travel during the move + int n = int(x_dist / (2*x_max_dist) + 1.f); // how many there and back moves should we do + float r = 2*n*x_max_dist / x_dist; // actual/required dist if the move is not shortened + + float end_point = x() + (farthest_x > x() ? 1.f : -1.f) * x_max_dist / r; + for (int i=0; i& m_filpar; @@ -533,7 +544,9 @@ WipeTower2::WipeTower2(const PrintConfig& config, const PrintRegionConfig& defau m_wipe_tower_rotation_angle(float(config.wipe_tower_rotation_angle)), m_wipe_tower_brim_width(float(config.prime_tower_brim_width)), m_wipe_tower_cone_angle(float(config.wipe_tower_cone_angle)), - m_extra_spacing(float(config.wipe_tower_extra_spacing/100.)), + m_extra_flow(float(config.wipe_tower_extra_flow/100.)), + m_extra_spacing_wipe(float(config.wipe_tower_extra_spacing/100. * config.wipe_tower_extra_flow/100.)), + m_extra_spacing_ramming(float(config.wipe_tower_extra_spacing/100.)), m_y_shift(0.f), m_z_pos(0.f), m_bridging(float(config.wipe_tower_bridging)), @@ -571,6 +584,8 @@ WipeTower2::WipeTower2(const PrintConfig& config, const PrintRegionConfig& defau m_set_extruder_trimpot = config.high_current_on_filament_swap; } + m_is_mk4mmu3 = boost::icontains(config.printer_notes.value, "PRINTER_MODEL_MK4") && boost::icontains(config.printer_notes.value, "MMU"); + // Calculate where the priming lines should be - very naive test not detecting parallelograms etc. const std::vector& bed_points = config.printable_area.values; BoundingBoxf bb(bed_points); @@ -605,6 +620,7 @@ void WipeTower2::set_extruder(size_t idx, const PrintConfig& config) m_filpar[idx].is_soluble = config.filament_soluble.get_at(idx); m_filpar[idx].temperature = config.nozzle_temperature.get_at(idx); m_filpar[idx].first_layer_temperature = config.nozzle_temperature_initial_layer.get_at(idx); + m_filpar[idx].filament_minimal_purge_on_wipe_tower = config.filament_minimal_purge_on_wipe_tower.get_at(idx); // If this is a single extruder MM printer, we will use all the SE-specific config values. // Otherwise, the defaults will be used to turn off the SE stuff. @@ -617,6 +633,8 @@ void WipeTower2::set_extruder(size_t idx, const PrintConfig& config) m_filpar[idx].cooling_moves = config.filament_cooling_moves.get_at(idx); m_filpar[idx].cooling_initial_speed = float(config.filament_cooling_initial_speed.get_at(idx)); m_filpar[idx].cooling_final_speed = float(config.filament_cooling_final_speed.get_at(idx)); + m_filpar[idx].filament_stamping_loading_speed = float(config.filament_stamping_loading_speed.get_at(idx)); + m_filpar[idx].filament_stamping_distance = float(config.filament_stamping_distance.get_at(idx)); } m_filpar[idx].filament_area = float((M_PI/4.f) * pow(config.filament_diameter.get_at(idx), 2)); // all extruders are assumed to have the same filament diameter at this point @@ -730,7 +748,7 @@ std::vector WipeTower2::prime( toolchange_Wipe(writer, cleaning_box , 20.f); WipeTower::box_coordinates box = cleaning_box; box.translate(0.f, writer.y() - cleaning_box.ld.y() + m_perimeter_width); - toolchange_Unload(writer, box , m_filpar[m_current_tool].material, m_filpar[tools[idx_tool + 1]].first_layer_temperature); + toolchange_Unload(writer, box , m_filpar[m_current_tool].material, m_filpar[m_current_tool].first_layer_temperature, m_filpar[tools[idx_tool + 1]].first_layer_temperature); cleaning_box.translate(prime_section_width, 0.f); writer.travel(cleaning_box.ld, 7200); } @@ -777,7 +795,7 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool) for (const auto &b : m_layer_info->tool_changes) if ( b.new_tool == tool ) { wipe_volume = b.wipe_volume; - wipe_area = b.required_depth * m_layer_info->extra_spacing; + wipe_area = b.required_depth; break; } } @@ -797,10 +815,10 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool) .set_initial_tool(m_current_tool) .set_y_shift(m_y_shift + (tool!=(unsigned int)(-1) && (m_current_shape == SHAPE_REVERSED) ? m_layer_info->depth - m_layer_info->toolchanges_depth(): 0.f)) .append(";--------------------\n" - "; CP TOOLCHANGE START\n") - .comment_with_value(" toolchange #", m_num_tool_changes + 1); // the number is zero-based + "; CP TOOLCHANGE START\n"); if (tool != (unsigned)(-1)){ + writer.comment_with_value(" toolchange #", m_num_tool_changes + 1); // the number is zero-based writer.append(std::string("; material : " + (m_current_tool < m_filpar.size() ? m_filpar[m_current_tool].material : "(NONE)") + " -> " + m_filpar[tool].material + "\n").c_str()) .append(";--------------------\n"); writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_Start) + "\n"); @@ -819,7 +837,8 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool) // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool. if (tool != (unsigned int)-1){ // This is not the last change. toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, - is_first_layer() ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature); + (is_first_layer() ? m_filpar[m_current_tool].first_layer_temperature : m_filpar[m_current_tool].temperature), + (is_first_layer() ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature)); toolchange_Change(writer, tool, m_filpar[tool].material); // Change the tool, set a speed override for soluble and flex materials. toolchange_Load(writer, cleaning_box); writer.travel(writer.x(), writer.y()-m_perimeter_width); // cooling and loading were done a bit down the road @@ -827,7 +846,7 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool) writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_End) + "\n"); ++ m_num_tool_changes; } else - toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, m_filpar[m_current_tool].temperature); + toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, m_filpar[m_current_tool].temperature, m_filpar[m_current_tool].temperature); m_depth_traversed += wipe_area; @@ -854,13 +873,14 @@ void WipeTower2::toolchange_Unload( WipeTowerWriter2 &writer, const WipeTower::box_coordinates &cleaning_box, const std::string& current_material, + const int old_temperature, const int new_temperature) { float xl = cleaning_box.ld.x() + 1.f * m_perimeter_width; float xr = cleaning_box.rd.x() - 1.f * m_perimeter_width; const float line_width = m_perimeter_width * m_filpar[m_current_tool].ramming_line_width_multiplicator; // desired ramming line thickness - const float y_step = line_width * m_filpar[m_current_tool].ramming_step_multiplicator * m_extra_spacing; // spacing between lines in mm + const float y_step = line_width * m_filpar[m_current_tool].ramming_step_multiplicator * m_extra_spacing_ramming; // spacing between lines in mm const Vec2f ramming_start_pos = Vec2f(xl, cleaning_box.ld.y() + m_depth_traversed + y_step/2.f); @@ -873,10 +893,14 @@ void WipeTower2::toolchange_Unload( float e_done = 0; // measures E move done from each segment const bool do_ramming = m_enable_filament_ramming && (m_semm || m_filpar[m_current_tool].multitool_ramming); + const bool cold_ramming = m_is_mk4mmu3; if (do_ramming) { writer.travel(ramming_start_pos); // move to starting position - writer.disable_linear_advance(); + if (! m_is_mk4mmu3) + writer.disable_linear_advance(); + if (cold_ramming) + writer.set_extruder_temp(old_temperature - 20); } else writer.set_position(ramming_start_pos); @@ -897,7 +921,7 @@ void WipeTower2::toolchange_Unload( if (tch.old_tool == m_current_tool) { sum_of_depths += tch.ramming_depth; float ramming_end_y = sum_of_depths; - ramming_end_y -= (y_step/m_extra_spacing-m_perimeter_width) / 2.f; // center of final ramming line + ramming_end_y -= (y_step/m_extra_spacing_ramming-m_perimeter_width) / 2.f; // center of final ramming line if ( (m_current_shape == SHAPE_REVERSED && ramming_end_y < sparse_beginning_y - 0.5f*m_perimeter_width ) || (m_current_shape == SHAPE_NORMAL && ramming_end_y > sparse_beginning_y + 0.5f*m_perimeter_width ) ) @@ -910,6 +934,11 @@ void WipeTower2::toolchange_Unload( sum_of_depths += tch.required_depth; } } + + if (m_is_mk4mmu3) { + writer.switch_filament_monitoring(false); + writer.wait(1.5f); + } // now the ramming itself: @@ -953,32 +982,70 @@ void WipeTower2::toolchange_Unload( .retract(0.10f * total_retraction_distance, 0.3f * m_filpar[m_current_tool].unloading_speed * 60.f) .resume_preview(); } + + const int& number_of_cooling_moves = m_filpar[m_current_tool].cooling_moves; + const bool cooling_will_happen = m_semm && number_of_cooling_moves > 0; + bool change_temp_later = false; + // Wipe tower should only change temperature with single extruder MM. Otherwise, all temperatures should // be already set and there is no need to change anything. Also, the temperature could be changed // for wrong extruder. if (m_semm) { - if (new_temperature != 0 && (new_temperature != m_old_temperature || is_first_layer()) ) { // Set the extruder temperature, but don't wait. + if (new_temperature != 0 && (new_temperature != m_old_temperature || is_first_layer() || cold_ramming) ) { // Set the extruder temperature, but don't wait. // If the required temperature is the same as last time, don't emit the M104 again (if user adjusted the value, it would be reset) // However, always change temperatures on the first layer (this is to avoid issues with priming lines turned off). - writer.set_extruder_temp(new_temperature, false); + if (cold_ramming && cooling_will_happen) + change_temp_later = true; + else + writer.set_extruder_temp(new_temperature, false); m_old_temperature = new_temperature; } } // Cooling: - const int& number_of_moves = m_filpar[m_current_tool].cooling_moves; - if (m_semm && number_of_moves > 0 && m_cooling_tube_length != 0) { + if (cooling_will_happen) { writer.append("; Cooling\n"); const float& initial_speed = m_filpar[m_current_tool].cooling_initial_speed; const float& final_speed = m_filpar[m_current_tool].cooling_final_speed; - float speed_inc = (final_speed - initial_speed) / (2.f * number_of_moves - 1.f); + float speed_inc = (final_speed - initial_speed) / (2.f * number_of_cooling_moves - 1.f); + + if (m_is_mk4mmu3) + writer.disable_linear_advance(); writer.suppress_preview() .travel(writer.x(), writer.y() + y_step); old_x = writer.x(); turning_point = xr-old_x > old_x-xl ? xr : xl; - for (int i=0; i0 && m_filpar[m_current_tool].filament_stamping_distance != 0) { + + // Stamping turning point shall be no farther than 20mm from the current nozzle position: + float stamping_turning_point = std::clamp(old_x + 20.f * (turning_point - old_x > 0.f ? 1.f : -1.f), xl, xr); + + // Only last 5mm will be done with the fast x travel. The point is to spread possible blobs + // along the whole wipe tower. + if (stamping_dist_e > 5) { + float cent = writer.x(); + writer.load_move_x_advanced(stamping_turning_point, (stamping_dist_e - 5), m_filpar[m_current_tool].filament_stamping_loading_speed, 200); + writer.load_move_x_advanced(cent, 5, m_filpar[m_current_tool].filament_stamping_loading_speed, m_travel_speed); + writer.travel(cent, writer.y()); + } else + writer.load_move_x_advanced_there_and_back(stamping_turning_point, stamping_dist_e, m_filpar[m_current_tool].filament_stamping_loading_speed, m_travel_speed); + + // Retract while the print head is stationary, so if there is a blob, it is not dragged along. + writer.retract(stamping_dist_e, m_filpar[m_current_tool].unloading_speed * 60.f); + } + + if (i == number_of_cooling_moves - 1 && change_temp_later) { + // If cold_ramming, the temperature change should be done before the last cooling move. + writer.set_extruder_temp(new_temperature, false); + } + float speed = initial_speed + speed_inc * 2*i; writer.load_move_x_advanced(turning_point, m_cooling_tube_length, speed); speed += speed_inc; @@ -998,7 +1065,7 @@ void WipeTower2::toolchange_Unload( // this is to align ramming and future wiping extrusions, so the future y-steps can be uniform from the start: // the perimeter_width will later be subtracted, it is there to not load while moving over just extruded material - Vec2f pos = Vec2f(end_of_ramming.x(), end_of_ramming.y() + (y_step/m_extra_spacing-m_perimeter_width) / 2.f + m_perimeter_width); + Vec2f pos = Vec2f(end_of_ramming.x(), end_of_ramming.y() + (y_step/m_extra_spacing_ramming-m_perimeter_width) / 2.f + m_perimeter_width); if (do_ramming) writer.travel(pos, 2400.f); else @@ -1018,11 +1085,14 @@ void WipeTower2::toolchange_Change( if (m_current_tool < m_used_filament_length.size()) m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length(); - // This is where we want to place the custom gcodes. We will use placeholders for this. // These will be substituted by the actual gcodes when the gcode is generated. + //writer.append("[end_filament_gcode]\n"); writer.append("[change_filament_gcode]\n"); + if (m_is_mk4mmu3) + writer.switch_filament_monitoring(true); + // Travel to where we assume we are. Custom toolchange or some special T code handling (parking extruder etc) // gcode could have left the extruder somewhere, we cannot just start extruding. We should also inform the // postprocessor that we absolutely want to have this in the gcode, even if it thought it is the same as before. @@ -1030,10 +1100,11 @@ void WipeTower2::toolchange_Change( writer.feedrate(m_travel_speed * 60.f) // see https://github.com/prusa3d/PrusaSlicer/issues/5483 .append(std::string("G1 X") + Slic3r::float_to_string_decimal_point(current_pos.x()) + " Y" + Slic3r::float_to_string_decimal_point(current_pos.y()) - + never_skip_tag() + "\n"); + + never_skip_tag() + "\n" + ); + writer.append("[deretraction_from_wipe_tower_generator]"); - // Orca TODO: handle multi extruders // The toolchange Tn command will be inserted later, only in case that the user does // not provide a custom toolchange gcode. writer.set_tool(new_tool); // This outputs nothing, the writer just needs to know the tool has changed. @@ -1084,21 +1155,25 @@ void WipeTower2::toolchange_Wipe( const float& xl = cleaning_box.ld.x(); const float& xr = cleaning_box.rd.x(); + writer.set_extrusion_flow(m_extrusion_flow * m_extra_flow); + const float line_width = m_perimeter_width * m_extra_flow; + writer.change_analyzer_line_width(line_width); + // Variables x_to_wipe and traversed_x are here to be able to make sure it always wipes at least // the ordered volume, even if it means violating the box. This can later be removed and simply // wipe until the end of the assigned area. - float x_to_wipe = volume_to_length(wipe_volume, m_perimeter_width, m_layer_height) * (is_first_layer() ? m_extra_spacing : 1.f); - float dy = (is_first_layer() ? 1.f : m_extra_spacing) * m_perimeter_width; // Don't use the extra spacing for the first layer. + float x_to_wipe = volume_to_length(wipe_volume, m_perimeter_width, m_layer_height) / m_extra_flow; + float dy = (is_first_layer() ? m_extra_flow : m_extra_spacing_wipe) * m_perimeter_width; // Don't use the extra spacing for the first layer, but do use the spacing resulting from increased flow. // All the calculations in all other places take the spacing into account for all the layers. // If spare layers are excluded->if 1 or less toolchange has been done, it must be sill the first layer, too.So slow down. const float target_speed = is_first_layer() || (m_num_tool_changes <= 1 && m_no_sparse_layers) ? m_first_layer_speed * 60.f : std::min(m_wipe_tower_max_purge_speed * 60.f, m_infill_speed * 60.f); float wipe_speed = 0.33f * target_speed; - // if there is less than 2.5*m_perimeter_width to the edge, advance straightaway (there is likely a blob anyway) - if ((m_left_to_right ? xr-writer.x() : writer.x()-xl) < 2.5f*m_perimeter_width) { - writer.travel((m_left_to_right ? xr-m_perimeter_width : xl+m_perimeter_width),writer.y()+dy); + // if there is less than 2.5*line_width to the edge, advance straightaway (there is likely a blob anyway) + if ((m_left_to_right ? xr-writer.x() : writer.x()-xl) < 2.5f*line_width) { + writer.travel((m_left_to_right ? xr-line_width : xl+line_width),writer.y()+dy); m_left_to_right = !m_left_to_right; } @@ -1113,21 +1188,21 @@ void WipeTower2::toolchange_Wipe( float traversed_x = writer.x(); if (m_left_to_right) - writer.extrude(xr - (i % 4 == 0 ? 0 : 1.5f*m_perimeter_width), writer.y(), wipe_speed); + writer.extrude(xr - (i % 4 == 0 ? 0 : 1.5f*line_width), writer.y(), wipe_speed); else - writer.extrude(xl + (i % 4 == 1 ? 0 : 1.5f*m_perimeter_width), writer.y(), wipe_speed); + writer.extrude(xl + (i % 4 == 1 ? 0 : 1.5f*line_width), writer.y(), wipe_speed); - if (writer.y()+float(EPSILON) > cleaning_box.lu.y()-0.5f*m_perimeter_width) + if (writer.y()+float(EPSILON) > cleaning_box.lu.y()-0.5f*line_width) break; // in case next line would not fit traversed_x -= writer.x(); x_to_wipe -= std::abs(traversed_x); if (x_to_wipe < WT_EPSILON) { - writer.travel(m_left_to_right ? xl + 1.5f*m_perimeter_width : xr - 1.5f*m_perimeter_width, writer.y(), 7200); + writer.travel(m_left_to_right ? xl + 1.5f*line_width : xr - 1.5f*line_width, writer.y(), 7200); break; } // stepping to the next line: - writer.extrude(writer.x() + (i % 4 == 0 ? -1.f : (i % 4 == 1 ? 1.f : 0.f)) * 1.5f*m_perimeter_width, writer.y() + dy); + writer.extrude(writer.x() + (i % 4 == 0 ? -1.f : (i % 4 == 1 ? 1.f : 0.f)) * 1.5f*line_width, writer.y() + dy); m_left_to_right = !m_left_to_right; } @@ -1141,6 +1216,7 @@ void WipeTower2::toolchange_Wipe( m_left_to_right = !m_left_to_right; writer.set_extrusion_flow(m_extrusion_flow); // Reset the extrusion flow. + writer.change_analyzer_line_width(m_perimeter_width); } @@ -1414,16 +1490,15 @@ std::vector> WipeTower2::extract_wipe_volumes(const PrintConf std::vector wiping_matrix(cast(config.flush_volumes_matrix.values)); auto scale = config.flush_multiplier; - // Orca todo: currently we only/always support SEMM. // The values shall only be used when SEMM is enabled. The purging for other printers // is determined by filament_minimal_purge_on_wipe_tower. - if (! config.purge_in_prime_tower.value) + if (! config.purge_in_prime_tower.value || ! config.single_extruder_multi_material.value) std::fill(wiping_matrix.begin(), wiping_matrix.end(), 0.f); // Extract purging volumes for each extruder pair: std::vector> wipe_volumes; const unsigned int number_of_extruders = (unsigned int)(sqrt(wiping_matrix.size())+EPSILON); - for (unsigned int i = 0; i(wiping_matrix.begin()+i*number_of_extruders, wiping_matrix.begin()+(i+1)*number_of_extruders)); // Also include filament_minimal_purge_on_wipe_tower. This is needed for the preview. @@ -1434,6 +1509,14 @@ std::vector> WipeTower2::extract_wipe_volumes(const PrintConf return wipe_volumes; } +static float get_wipe_depth(float volume, float layer_height, float perimeter_width, float extra_flow, float extra_spacing, float width) +{ + float length_to_extrude = (volume_to_length(volume, perimeter_width, layer_height)) / extra_flow; + length_to_extrude = std::max(length_to_extrude,0.f); + + return (int(length_to_extrude / width) + 1) * perimeter_width * extra_spacing; +} + // Appends a toolchange into m_plan and calculates neccessary depth of the corresponding box void WipeTower2::plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, float wipe_volume) @@ -1449,23 +1532,18 @@ void WipeTower2::plan_toolchange(float z_par, float layer_height_par, unsigned i if (old_tool == new_tool) // new layer without toolchanges - we are done return; - // this is an actual toolchange - let's calculate depth to reserve on the wipe tower - float depth = 0.f; - float width = m_wipe_tower_width - 3*m_perimeter_width; + // this is an actual toolchange - let's calculate depth to reserve on the wipe tower + float width = m_wipe_tower_width - 3*m_perimeter_width; float length_to_extrude = volume_to_length(0.25f * std::accumulate(m_filpar[old_tool].ramming_speed.begin(), m_filpar[old_tool].ramming_speed.end(), 0.f), m_perimeter_width * m_filpar[old_tool].ramming_line_width_multiplicator, layer_height_par); - depth = (int(length_to_extrude / width) + 1) * (m_perimeter_width * m_filpar[old_tool].ramming_line_width_multiplicator * m_filpar[old_tool].ramming_step_multiplicator); - float ramming_depth = depth; - length_to_extrude = width*((length_to_extrude / width)-int(length_to_extrude / width)) - width; - float first_wipe_line = -length_to_extrude; - length_to_extrude += volume_to_length(wipe_volume, m_perimeter_width, layer_height_par); - length_to_extrude = std::max(length_to_extrude,0.f); + float ramming_depth = (int(length_to_extrude / width) + 1) * (m_perimeter_width * m_filpar[old_tool].ramming_line_width_multiplicator * m_filpar[old_tool].ramming_step_multiplicator) * m_extra_spacing_ramming; + float first_wipe_line = - (width*((length_to_extrude / width)-int(length_to_extrude / width)) - width); - depth += (int(length_to_extrude / width) + 1) * m_perimeter_width; - depth *= m_extra_spacing; - - m_plan.back().tool_changes.push_back(WipeTowerInfo::ToolChange(old_tool, new_tool, depth, ramming_depth, first_wipe_line, wipe_volume)); + float first_wipe_volume = length_to_volume(first_wipe_line, m_perimeter_width * m_extra_flow, layer_height_par); + float wiping_depth = get_wipe_depth(wipe_volume - first_wipe_volume, layer_height_par, m_perimeter_width, m_extra_flow, m_extra_spacing_wipe, width); + + m_plan.back().tool_changes.push_back(WipeTowerInfo::ToolChange(old_tool, new_tool, ramming_depth + wiping_depth, ramming_depth, first_wipe_line, wipe_volume)); } @@ -1505,20 +1583,25 @@ void WipeTower2::save_on_last_wipe() // Which toolchange will finish_layer extrusions be subtracted from? int idx = first_toolchange_to_nonsoluble(m_layer_info->tool_changes); + if (idx == -1) { + // In this case, finish_layer will be called at the very beginning. + finish_layer().total_extrusion_length_in_plane(); + } + for (int i=0; itool_changes.size()); ++i) { auto& toolchange = m_layer_info->tool_changes[i]; tool_change(toolchange.new_tool); if (i == idx) { float width = m_wipe_tower_width - 3*m_perimeter_width; // width we draw into - float length_to_save = finish_layer().total_extrusion_length_in_plane(); - float length_to_wipe = volume_to_length(toolchange.wipe_volume, - m_perimeter_width, m_layer_info->height) - toolchange.first_wipe_line - length_to_save; - length_to_wipe = std::max(length_to_wipe,0.f); - float depth_to_wipe = m_perimeter_width * (std::floor(length_to_wipe/width) + ( length_to_wipe > 0.f ? 1.f : 0.f ) ) * m_extra_spacing; + float volume_to_save = length_to_volume(finish_layer().total_extrusion_length_in_plane(), m_perimeter_width, m_layer_info->height); + float volume_left_to_wipe = std::max(m_filpar[toolchange.new_tool].filament_minimal_purge_on_wipe_tower, toolchange.wipe_volume_total - volume_to_save); + float volume_we_need_depth_for = std::max(0.f, volume_left_to_wipe - length_to_volume(toolchange.first_wipe_line, m_perimeter_width*m_extra_flow, m_layer_info->height)); + float depth_to_wipe = get_wipe_depth(volume_we_need_depth_for, m_layer_info->height, m_perimeter_width, m_extra_flow, m_extra_spacing_wipe, width); toolchange.required_depth = toolchange.ramming_depth + depth_to_wipe; + toolchange.wipe_volume = volume_left_to_wipe; } } } @@ -1563,7 +1646,7 @@ void WipeTower2::generate(std::vector> return; plan_tower(); - for (int i=0;i<5;++i) { + for (int i = 0; i<5; ++i) { save_on_last_wipe(); plan_tower(); } @@ -1579,14 +1662,15 @@ void WipeTower2::generate(std::vector> } } - for (auto& used : m_used_filament_length) // reset used filament stats - used = 0.f; + m_used_filament_length.assign(m_used_filament_length.size(), 0.f); // reset used filament stats + assert(m_used_filament_length_until_layer.empty()); + m_used_filament_length_until_layer.emplace_back(0.f, m_used_filament_length); m_old_temperature = -1; // reset last temperature written in the gcode - std::vector layer_result; for (const WipeTower2::WipeTowerInfo& layer : m_plan) { + std::vector layer_result; set_layer(layer.z, layer.height, 0, false/*layer.z == m_plan.front().z*/, layer.z == m_plan.back().z); m_internal_rotation += 180.f; @@ -1623,6 +1707,10 @@ void WipeTower2::generate(std::vector> } result.emplace_back(std::move(layer_result)); + + if (m_used_filament_length_until_layer.empty() || m_used_filament_length_until_layer.back().first != layer.z) + m_used_filament_length_until_layer.emplace_back(); + m_used_filament_length_until_layer.back() = std::make_pair(layer.z, m_used_filament_length); } } diff --git a/src/libslic3r/GCode/WipeTower2.hpp b/src/libslic3r/GCode/WipeTower2.hpp index 58bdd6fc39..07c5ca330f 100644 --- a/src/libslic3r/GCode/WipeTower2.hpp +++ b/src/libslic3r/GCode/WipeTower2.hpp @@ -1,6 +1,5 @@ -// Orca: This file is ported from latest PrusaSlicer +// Orca: WipeTower2 for all non bbl printers, support all MMU device and toolchanger -// Original PrusaSlicer Copyright: #ifndef WipeTower2_ #define WipeTower2_ @@ -128,6 +127,7 @@ public: } std::vector get_used_filament() const { return m_used_filament_length; } + std::vector>> get_used_filament_until_layer() const { return m_used_filament_length_until_layer; } int get_number_of_toolchanges() const { return m_num_tool_changes; } struct FilamentParameters { @@ -140,6 +140,10 @@ public: float unloading_speed = 0.f; float unloading_speed_start = 0.f; float delay = 0.f ; + + float filament_stamping_loading_speed = 0.f; + float filament_stamping_distance = 0.f; + int cooling_moves = 0; float cooling_initial_speed = 0.f; float cooling_final_speed = 0.f; @@ -151,6 +155,7 @@ public: float filament_area; bool multitool_ramming; float multitool_ramming_time = 0.f; + float filament_minimal_purge_on_wipe_tower = 0.f; }; private: @@ -169,6 +174,7 @@ private: bool m_semm = true; // Are we using a single extruder multimaterial printer? bool m_enable_filament_ramming = true; + bool m_is_mk4mmu3 = false; Vec2f m_wipe_tower_pos; // Left front corner of the wipe tower in mm. float m_wipe_tower_width; // Width of the wipe tower. float m_wipe_tower_depth = 0.f; // Depth of the wipe tower @@ -219,8 +225,7 @@ private: // State of the wipe tower generator. unsigned int m_num_layer_changes = 0; // Layer change counter for the output statistics. unsigned int m_num_tool_changes = 0; // Tool change change counter for the output statistics. - ///unsigned int m_idx_tool_change_in_layer = 0; // Layer change counter in this layer. Counting up to m_max_color_changes. - bool m_print_brim = true; + // A fill-in direction (positive Y, negative Y) alternates with each layer. wipe_shape m_current_shape = SHAPE_NORMAL; size_t m_current_tool = 0; @@ -229,7 +234,9 @@ private: float m_depth_traversed = 0.f; // Current y position at the wipe tower. bool m_current_layer_finished = false; bool m_left_to_right = true; - float m_extra_spacing = 1.f; + float m_extra_flow = 1.f; + float m_extra_spacing_wipe = 1.f; + float m_extra_spacing_ramming = 1.f; bool is_first_layer() const { return size_t(m_layer_info - m_plan.begin()) == m_first_layer_idx; } @@ -241,17 +248,10 @@ private: return layer_height * ( m_perimeter_width - layer_height * (1.f-float(M_PI)/4.f)) / filament_area(); } - // Calculates length of extrusion line to extrude given volume - float volume_to_length(float volume, float line_width, float layer_height) const { - return std::max(0.f, volume / (layer_height * (line_width - layer_height * (1.f - float(M_PI) / 4.f)))); - } // Calculates depth for all layers and propagates them downwards void plan_tower(); - // Goes through m_plan and recalculates depths and width of the WT to make it exactly square - experimental - void make_wipe_tower_square(); - // Goes through m_plan, calculates border and finish_layer extrusions and subtracts them from last wipe void save_on_last_wipe(); @@ -265,19 +265,19 @@ private: float ramming_depth; float first_wipe_line; float wipe_volume; + float wipe_volume_total; ToolChange(size_t old, size_t newtool, float depth=0.f, float ramming_depth=0.f, float fwl=0.f, float wv=0.f) - : old_tool{old}, new_tool{newtool}, required_depth{depth}, ramming_depth{ramming_depth}, first_wipe_line{fwl}, wipe_volume{wv} {} + : old_tool{old}, new_tool{newtool}, required_depth{depth}, ramming_depth{ramming_depth}, first_wipe_line{fwl}, wipe_volume{wv}, wipe_volume_total{wv} {} }; float z; // z position of the layer float height; // layer height float depth; // depth of the layer based on all layers above - float extra_spacing; float toolchanges_depth() const { float sum = 0.f; for (const auto &a : tool_changes) sum += a.required_depth; return sum; } std::vector tool_changes; WipeTowerInfo(float z_par, float layer_height_par) - : z{z_par}, height{layer_height_par}, depth{0}, extra_spacing{1.f} {} + : z{z_par}, height{layer_height_par}, depth{0} {} }; std::vector m_plan; // Stores information about all layers and toolchanges for the future wipe tower (filled by plan_toolchange(...)) @@ -289,6 +289,7 @@ private: // Stores information about used filament length per extruder: std::vector m_used_filament_length; + std::vector>> m_used_filament_length_until_layer; // Return index of first toolchange that switches to non-soluble extruder // ot -1 if there is no such toolchange. @@ -299,6 +300,7 @@ private: WipeTowerWriter2 &writer, const WipeTower::box_coordinates &cleaning_box, const std::string& current_material, + const int old_temperature, const int new_temperature); void toolchange_Change( @@ -316,6 +318,9 @@ private: float wipe_volume); }; + + + } // namespace Slic3r -#endif // WipeTowerPrusaMM_hpp_ +#endif // slic3r_GCode_WipeTower_hpp_ diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 724bdc148e..1a3a984a74 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -809,7 +809,7 @@ static std::vector s_Preset_print_options { "tree_support_brim_width", "gcode_comments", "gcode_label_objects", "initial_layer_travel_speed", "exclude_object", "slow_down_layers", "infill_anchor", "infill_anchor_max","initial_layer_min_bead_width", "make_overhang_printable", "make_overhang_printable_angle", "make_overhang_printable_hole_size" ,"notes", - "wipe_tower_cone_angle", "wipe_tower_extra_spacing","wipe_tower_max_purge_speed", "wipe_tower_filament", "wiping_volumes_extruders","wipe_tower_bridging", "single_extruder_multi_material_priming", + "wipe_tower_cone_angle", "wipe_tower_extra_spacing","wipe_tower_max_purge_speed", "wipe_tower_filament", "wiping_volumes_extruders","wipe_tower_bridging", "wipe_tower_extra_flow","single_extruder_multi_material_priming", "wipe_tower_rotation_angle", "tree_support_branch_distance_organic", "tree_support_branch_diameter_organic", "tree_support_branch_angle_organic", "hole_to_polyhole", "hole_to_polyhole_threshold", "hole_to_polyhole_twisted", "mmu_segmented_region_max_width", "mmu_segmented_region_interlocking_depth", "small_area_infill_flow_compensation", "small_area_infill_flow_compensation_model", @@ -842,7 +842,7 @@ static std::vector s_Preset_filament_options { //SoftFever "enable_pressure_advance", "pressure_advance","chamber_temperature", "filament_shrink", "support_material_interface_fan_speed", "filament_notes" /*,"filament_seam_gap"*/, "filament_loading_speed", "filament_loading_speed_start", "filament_load_time", - "filament_unloading_speed", "filament_unloading_speed_start", "filament_unload_time", "filament_toolchange_delay", "filament_cooling_moves", + "filament_unloading_speed", "filament_unloading_speed_start", "filament_unload_time", "filament_toolchange_delay", "filament_cooling_moves", "filament_stamping_loading_speed", "filament_stamping_distance", "filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", "filament_multitool_ramming", "filament_multitool_ramming_volume", "filament_multitool_ramming_flow", "activate_chamber_temp_control", "filament_long_retractions_when_cut","filament_retraction_distances_when_cut", "idle_temperature" diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 6bb1ff8508..5e687cbbd4 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -252,6 +252,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n || opt_key == "filament_unloading_speed_start" || opt_key == "filament_toolchange_delay" || opt_key == "filament_cooling_moves" + || opt_key == "filament_stamping_loading_speed" + || opt_key == "filament_stamping_distance" || opt_key == "filament_cooling_initial_speed" || opt_key == "filament_cooling_final_speed" || opt_key == "filament_ramming_parameters" @@ -273,6 +275,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n || opt_key == "other_layers_print_sequence" || opt_key == "other_layers_print_sequence_nums" || opt_key == "wipe_tower_bridging" + || opt_key == "wipe_tower_extra_flow" || opt_key == "wipe_tower_no_sparse_layers" || opt_key == "flush_volumes_matrix" || opt_key == "prime_volume" diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index a44fa6ebbb..bfe3590ea5 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1883,6 +1883,21 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionInts { 4 }); + def = this->add("filament_stamping_loading_speed", coFloats); + def->label = L("Stamping loading speed"); + def->tooltip = L("Speed used for stamping."); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats { 0. }); + + def = this->add("filament_stamping_distance", coFloats); + def->label = L("Stamping distance measured from the center of the cooling tube"); + def->tooltip = L("If set to nonzero value, filament is moved toward the nozzle between the individual cooling moves (\"stamping\"). " + "This option configures how long this movement should be before the filament is retracted again."); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats { 0. }); + def = this->add("filament_cooling_initial_speed", coFloats); def->label = L("Speed of the first cooling move"); def->tooltip = L("Cooling moves are gradually accelerating beginning at this speed."); @@ -4958,6 +4973,15 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(10.)); + def = this->add("wipe_tower_extra_flow", coPercent); + def->label = L("MATHIEU TEST: extra flow"); + def->tooltip = L(""); + def->sidetext = L("%"); + def->mode = comAdvanced; + def->min = 100.; + def->max = 300.; + def->set_default_value(new ConfigOptionPercent(100.)); + def = this->add("idle_temperature", coInts); def->label = L("Idle temperature"); def->tooltip = L("Nozzle temperature when the tool is currently not used in multi-tool setups." diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 3401423eb4..89a020774e 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1130,6 +1130,8 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBools, filament_multitool_ramming)) ((ConfigOptionFloats, filament_multitool_ramming_volume)) ((ConfigOptionFloats, filament_multitool_ramming_flow)) + ((ConfigOptionFloats, filament_stamping_loading_speed)) + ((ConfigOptionFloats, filament_stamping_distance)) ((ConfigOptionBool, purge_in_prime_tower)) ((ConfigOptionBool, enable_filament_ramming)) ((ConfigOptionBool, support_multi_bed_types)) @@ -1238,6 +1240,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionFloat, wipe_tower_rotation_angle)) ((ConfigOptionFloat, prime_tower_brim_width)) ((ConfigOptionFloat, wipe_tower_bridging)) + ((ConfigOptionPercent, wipe_tower_extra_flow)) ((ConfigOptionFloats, flush_volumes_matrix)) ((ConfigOptionFloats, flush_volumes_vector)) diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 263f57e19b..4752e24c0b 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -674,11 +674,14 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co toggle_line(el, have_prime_tower); bool purge_in_primetower = preset_bundle->printers.get_edited_preset().config.opt_bool("purge_in_prime_tower"); - - // Orca: do we really need to hide these options when not purge_in_primetower? - for (auto el : {"wipe_tower_rotation_angle", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_max_purge_speed", "wipe_tower_bridging", "wipe_tower_no_sparse_layers", "single_extruder_multi_material_priming"}) - toggle_line(el, have_prime_tower); - + + for (auto el : {"wipe_tower_rotation_angle", "wipe_tower_cone_angle", + "wipe_tower_extra_spacing", "wipe_tower_max_purge_speed", + "wipe_tower_bridging", "wipe_tower_extra_flow", + "wipe_tower_no_sparse_layers", + "single_extruder_multi_material_priming"}) + toggle_line(el, have_prime_tower); + toggle_line("prime_volume",have_prime_tower && !purge_in_primetower); for (auto el : {"flush_into_infill", "flush_into_support", "flush_into_objects"}) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 5000424a2a..b1812aa6c2 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2771,7 +2771,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) "brim_width", "wall_loops", "wall_filament", "sparse_infill_density", "sparse_infill_filament", "top_shell_layers", "enable_support", "support_filament", "support_interface_filament", "support_top_z_distance", "support_bottom_z_distance", "raft_layers", - "wipe_tower_rotation_angle", "wipe_tower_cone_angle", "wipe_tower_extra_spacing","wipe_tower_max_purge_speed", "wipe_tower_filament", + "wipe_tower_rotation_angle", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_extra_flow", "wipe_tower_max_purge_speed", "wipe_tower_filament", "best_object_pos" })) , sidebar(new Sidebar(q)) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 7f89e45104..f1345bc0e8 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2302,6 +2302,7 @@ void TabPrint::build() optgroup->append_single_option_line("wipe_tower_bridging"); optgroup->append_single_option_line("wipe_tower_cone_angle"); optgroup->append_single_option_line("wipe_tower_extra_spacing"); + optgroup->append_single_option_line("wipe_tower_extra_flow"); optgroup->append_single_option_line("wipe_tower_max_purge_speed"); optgroup->append_single_option_line("wipe_tower_no_sparse_layers"); optgroup->append_single_option_line("single_extruder_multi_material_priming"); @@ -3444,7 +3445,8 @@ void TabFilament::build() optgroup->append_single_option_line("filament_cooling_moves", "semm"); optgroup->append_single_option_line("filament_cooling_initial_speed", "semm"); optgroup->append_single_option_line("filament_cooling_final_speed", "semm"); - + optgroup->append_single_option_line("filament_stamping_loading_speed"); + optgroup->append_single_option_line("filament_stamping_distance"); create_line_with_widget(optgroup.get(), "filament_ramming_parameters", "", [this](wxWindow* parent) { auto ramming_dialog_btn = new wxButton(parent, wxID_ANY, _(L("Ramming settings"))+dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); wxGetApp().UpdateDarkUI(ramming_dialog_btn); From 18e417b34b5e6eeb2401e3705cef48145cef81dd Mon Sep 17 00:00:00 2001 From: SoftFever Date: Wed, 10 Jul 2024 00:32:11 +0800 Subject: [PATCH 06/32] tidy up some codes --- src/libslic3r/PrintConfig.cpp | 23 ++++++++++++----------- src/slic3r/GUI/Tab.cpp | 4 ---- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index bfe3590ea5..bc34ccc6ed 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -4901,15 +4901,6 @@ void PrintConfigDef::init_fff_params() def->min = 0.; def->max = 90.; def->set_default_value(new ConfigOptionFloat(0.)); - - def = this->add("wipe_tower_extra_spacing", coPercent); - def->label = L("Wipe tower purge lines spacing"); - def->tooltip = L("Spacing of purge lines on the wipe tower."); - def->sidetext = L("%"); - def->mode = comAdvanced; - def->min = 100.; - def->max = 300.; - def->set_default_value(new ConfigOptionPercent(100.)); def = this->add("wipe_tower_max_purge_speed", coFloat); def->label = L("Maximum wipe tower print speed"); @@ -4973,9 +4964,19 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(10.)); + def = this->add("wipe_tower_extra_spacing", coPercent); + def->label = L("Wipe tower purge lines spacing"); + def->tooltip = L("Spacing of purge lines on the wipe tower."); + def->sidetext = L("%"); + def->mode = comAdvanced; + def->min = 100.; + def->max = 300.; + def->set_default_value(new ConfigOptionPercent(100.)); + def = this->add("wipe_tower_extra_flow", coPercent); - def->label = L("MATHIEU TEST: extra flow"); - def->tooltip = L(""); + def->label = L("Extra flow for purging"); + def->tooltip = L("Extra flow used for the purging lines on the wipe tower. This makes the purging lines thicker or narrower " + "than they normally would be. The spacing is adjusted automatically."); def->sidetext = L("%"); def->mode = comAdvanced; def->min = 100.; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index f1345bc0e8..26e3ec001c 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3465,14 +3465,10 @@ void TabFilament::build() return sizer; }); - // Orca: multi tool is not supported yet. -#define ORCA_MULTI_TOOL -#ifdef ORCA_MULTI_TOOL optgroup = page->new_optgroup(L("Toolchange parameters with multi extruder MM printers")); optgroup->append_single_option_line("filament_multitool_ramming"); optgroup->append_single_option_line("filament_multitool_ramming_volume"); optgroup->append_single_option_line("filament_multitool_ramming_flow"); -#endif page = add_options_page(L("Notes"), "custom-gcode_note"); // ORCA: icon only visible on placeholders optgroup = page->new_optgroup(L("Notes"),"note", 0); From d872c622564838b5187e27ad15bc73d0ff5e1f89 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Wed, 10 Jul 2024 00:55:45 +0800 Subject: [PATCH 07/32] Add Generic ToolChanger Printer profile --- resources/profiles/Custom.json | 112 ++++++++++- resources/profiles/Custom/Custom_350_bed.stl | Bin 0 -> 5484 bytes .../My Generic ABS @MyToolChanger.json | 57 ++++++ .../My Generic ASA @MyToolChanger.json | 57 ++++++ .../My Generic PA @MyToolChanger.json | 60 ++++++ .../My Generic PA-CF @MyToolChanger.json | 63 ++++++ .../My Generic PC @MyToolChanger.json | 57 ++++++ .../My Generic PETG @MyToolChanger.json | 87 ++++++++ .../My Generic PLA @MyToolChanger.json | 60 ++++++ .../My Generic PLA-CF @MyToolChanger.json | 63 ++++++ .../My Generic PVA @MyToolChanger.json | 27 +++ .../My Generic TPU @MyToolChanger.json | 18 ++ .../machine/MyToolChanger 0.2 nozzle.json | 30 +++ .../machine/MyToolChanger 0.4 nozzle.json | 24 +++ .../machine/MyToolChanger 0.6 nozzle.json | 30 +++ .../machine/MyToolChanger 0.8 nozzle.json | 30 +++ .../Custom/machine/MyToolChanger.json | 12 ++ .../machine/fdm_toolchanger_common.json | 189 ++++++++++++++++++ .../0.08mm Extra Fine @MyToolChanger.json | 19 ++ .../process/0.12mm Fine @MyToolChanger.json | 19 ++ .../0.15mm Optimal @MyToolChanger.json | 20 ++ .../0.16mm Optimal @MyToolChanger.json | 20 ++ .../0.20mm Standard @MyToolChanger.json | 14 ++ .../process/0.24mm Draft @MyToolChanger.json | 17 ++ .../0.28mm Extra Draft @MyToolChanger.json | 15 ++ .../0.32mm Extra Draft @MyToolChanger.json | 17 ++ .../0.40mm Extra Draft @MyToolChanger.json | 16 ++ .../0.56mm Extra Draft @MyToolChanger.json | 15 ++ .../fdm_process_mytoolchanger_common.json | 27 +++ 29 files changed, 1173 insertions(+), 2 deletions(-) create mode 100644 resources/profiles/Custom/Custom_350_bed.stl create mode 100644 resources/profiles/Custom/filament/My Generic ABS @MyToolChanger.json create mode 100644 resources/profiles/Custom/filament/My Generic ASA @MyToolChanger.json create mode 100644 resources/profiles/Custom/filament/My Generic PA @MyToolChanger.json create mode 100644 resources/profiles/Custom/filament/My Generic PA-CF @MyToolChanger.json create mode 100644 resources/profiles/Custom/filament/My Generic PC @MyToolChanger.json create mode 100644 resources/profiles/Custom/filament/My Generic PETG @MyToolChanger.json create mode 100644 resources/profiles/Custom/filament/My Generic PLA @MyToolChanger.json create mode 100644 resources/profiles/Custom/filament/My Generic PLA-CF @MyToolChanger.json create mode 100644 resources/profiles/Custom/filament/My Generic PVA @MyToolChanger.json create mode 100644 resources/profiles/Custom/filament/My Generic TPU @MyToolChanger.json create mode 100644 resources/profiles/Custom/machine/MyToolChanger 0.2 nozzle.json create mode 100644 resources/profiles/Custom/machine/MyToolChanger 0.4 nozzle.json create mode 100644 resources/profiles/Custom/machine/MyToolChanger 0.6 nozzle.json create mode 100644 resources/profiles/Custom/machine/MyToolChanger 0.8 nozzle.json create mode 100644 resources/profiles/Custom/machine/MyToolChanger.json create mode 100644 resources/profiles/Custom/machine/fdm_toolchanger_common.json create mode 100644 resources/profiles/Custom/process/0.08mm Extra Fine @MyToolChanger.json create mode 100644 resources/profiles/Custom/process/0.12mm Fine @MyToolChanger.json create mode 100644 resources/profiles/Custom/process/0.15mm Optimal @MyToolChanger.json create mode 100644 resources/profiles/Custom/process/0.16mm Optimal @MyToolChanger.json create mode 100644 resources/profiles/Custom/process/0.20mm Standard @MyToolChanger.json create mode 100644 resources/profiles/Custom/process/0.24mm Draft @MyToolChanger.json create mode 100644 resources/profiles/Custom/process/0.28mm Extra Draft @MyToolChanger.json create mode 100644 resources/profiles/Custom/process/0.32mm Extra Draft @MyToolChanger.json create mode 100644 resources/profiles/Custom/process/0.40mm Extra Draft @MyToolChanger.json create mode 100644 resources/profiles/Custom/process/0.56mm Extra Draft @MyToolChanger.json create mode 100644 resources/profiles/Custom/process/fdm_process_mytoolchanger_common.json diff --git a/resources/profiles/Custom.json b/resources/profiles/Custom.json index a6015b1a4e..9aa9bfde7b 100644 --- a/resources/profiles/Custom.json +++ b/resources/profiles/Custom.json @@ -1,6 +1,6 @@ { "name": "Custom Printer", - "version": "02.01.01.00", + "version": "02.01.03.00", "force_update": "0", "description": "My configurations", "machine_model_list": [ @@ -15,6 +15,10 @@ { "name": "Generic RRF Printer", "sub_path": "machine/MyRRF.json" + }, + { + "name": "Generic ToolChanger Printer", + "sub_path": "machine/MyToolChanger.json" } ], "process_list": [ @@ -34,6 +38,10 @@ "name": "fdm_process_marlin_common", "sub_path": "process/fdm_process_marlin_common.json" }, + { + "name": "fdm_process_mytoolchanger_common", + "sub_path": "process/fdm_process_mytoolchanger_common.json" + }, { "name": "0.08mm Extra Fine @MyKlipper", "sub_path": "process/0.08mm Extra Fine @MyKlipper.json" @@ -121,6 +129,46 @@ { "name": "0.28mm Extra Draft @MyMarlin", "sub_path": "process/0.28mm Extra Draft @MyMarlin.json" + }, + { + "name": "0.08mm Extra Fine @MyToolChanger", + "sub_path": "process/0.08mm Extra Fine @MyToolChanger.json" + }, + { + "name": "0.12mm Fine @MyToolChanger", + "sub_path": "process/0.12mm Fine @MyToolChanger.json" + }, + { + "name": "0.15mm Optimal @MyToolChanger", + "sub_path": "process/0.15mm Optimal @MyToolChanger.json" + }, + { + "name": "0.16mm Optimal @MyToolChanger", + "sub_path": "process/0.16mm Optimal @MyToolChanger.json" + }, + { + "name": "0.20mm Standard @MyToolChanger", + "sub_path": "process/0.20mm Standard @MyToolChanger.json" + }, + { + "name": "0.24mm Draft @MyToolChanger", + "sub_path": "process/0.24mm Draft @MyToolChanger.json" + }, + { + "name": "0.28mm Extra Draft @MyToolChanger", + "sub_path": "process/0.28mm Extra Draft @MyToolChanger.json" + }, + { + "name": "0.32mm Extra Draft @MyToolChanger", + "sub_path": "process/0.32mm Extra Draft @MyToolChanger.json" + }, + { + "name": "0.40mm Extra Draft @MyToolChanger", + "sub_path": "process/0.40mm Extra Draft @MyToolChanger.json" + }, + { + "name": "0.56mm Extra Draft @MyToolChanger", + "sub_path": "process/0.56mm Extra Draft @MyToolChanger.json" } ], "filament_list": [ @@ -199,6 +247,46 @@ { "name": "My Generic PA-CF", "sub_path": "filament/My Generic PA-CF.json" + }, + { + "name": "My Generic PLA @MyToolChanger", + "sub_path": "filament/My Generic PLA @MyToolChanger.json" + }, + { + "name": "My Generic PLA-CF @MyToolChanger", + "sub_path": "filament/My Generic PLA-CF @MyToolChanger.json" + }, + { + "name": "My Generic PETG @MyToolChanger", + "sub_path": "filament/My Generic PETG @MyToolChanger.json" + }, + { + "name": "My Generic ABS @MyToolChanger", + "sub_path": "filament/My Generic ABS @MyToolChanger.json" + }, + { + "name": "My Generic TPU @MyToolChanger", + "sub_path": "filament/My Generic TPU @MyToolChanger.json" + }, + { + "name": "My Generic ASA @MyToolChanger", + "sub_path": "filament/My Generic ASA @MyToolChanger.json" + }, + { + "name": "My Generic PC @MyToolChanger", + "sub_path": "filament/My Generic PC @MyToolChanger.json" + }, + { + "name": "My Generic PVA @MyToolChanger", + "sub_path": "filament/My Generic PVA @MyToolChanger.json" + }, + { + "name": "My Generic PA @MyToolChanger", + "sub_path": "filament/My Generic PA @MyToolChanger.json" + }, + { + "name": "My Generic PA-CF @MyToolChanger", + "sub_path": "filament/My Generic PA-CF @MyToolChanger.json" } ], "machine_list": [ @@ -214,6 +302,10 @@ "name": "fdm_rrf_common", "sub_path": "machine/fdm_rrf_common.json" }, + { + "name": "fdm_toolchanger_common", + "sub_path": "machine/fdm_toolchanger_common.json" + }, { "name": "MyKlipper 0.4 nozzle", "sub_path": "machine/MyKlipper 0.4 nozzle.json" @@ -237,6 +329,22 @@ { "name": "MyRRF 0.4 nozzle", "sub_path": "machine/MyRRF 0.4 nozzle.json" + }, + { + "name": "MyToolChanger 0.4 nozzle", + "sub_path": "machine/MyToolChanger 0.4 nozzle.json" + }, + { + "name": "MyToolChanger 0.2 nozzle", + "sub_path": "machine/MyToolChanger 0.2 nozzle.json" + }, + { + "name": "MyToolChanger 0.6 nozzle", + "sub_path": "machine/MyToolChanger 0.6 nozzle.json" + }, + { + "name": "MyToolChanger 0.8 nozzle", + "sub_path": "machine/MyToolChanger 0.8 nozzle.json" } ] -} +} \ No newline at end of file diff --git a/resources/profiles/Custom/Custom_350_bed.stl b/resources/profiles/Custom/Custom_350_bed.stl new file mode 100644 index 0000000000000000000000000000000000000000..d2a9a497925cfc6dc753649ef436fae559767cfb GIT binary patch literal 5484 zcmb7|zityj5XLPeYAT8d3U_oN5l|tp!%1mCMB-0N6VcI8Bc0$uk_IVH5nDP5p){!w zkHI6re6!!}e0!dR*aEcn>~FuBotfP`-oAVFVt(-MaK8U&cmMJ3p8fM=-W|O0%i`?p_H!G~X8nFQ>vy|$yj=hKxZnLaeCWS_eyxOBf>vU={`~sG zw@-_^e+Ji3BF4-0{TdYBUQJ=QhC=+bG|5iyG~`ASp5eINIyu1k%Z5$a)1AX?S% zvE_fTolgk0s3%sHgY`#3s6`3ul>vW|xi)gOC{fnW2(>7I7~t`yhSpW->vDc*jkR8> zMTzM7X&g%EtmxnkLQa|JLGxZJ-@WP)5&DDq=*oA`K^gZ^l^bzHg_o>3!Cm+9)r8LC zt_RT)I9YFosIjp>oG>OV6N2{&G^}>d$LA8x>P!zbPa>~G z+&KPwOIR&cOHM$;D)AgUjAfOGvDYr{C~7ESwNx!R0S&9f)%cvKM2x+5ajQ{73H!BL zasnE*{t6Y3IFyL7*Y02|P(uleu3B;e8n#a>bS^ZMh_Tl$Zcb__VOgq{oPdVqdo{j) zC=p|?UCX~!kbPQ$ceq<}0vh0~h_F|^uY-!WQ%$QReviABPq1>QP6$?|c!eG`4Zn*9 zsK&VNmH%GjaDu*HLr6Y0h@flEslj|W!5p|HC!oP9@jh1~#JR2=rJ9HTC8^YzY#a}swGUr&l2&Gh*xks}ba%s|Cxdy*x73ZuWi6dm_6cvPQ$j6zQs2<4 zqSuvE!k@c*>~UC4;nVgY*BuGeRS*RzM71bE5C22xEXJ1*YT;gO;Z;M_C$;JBvOCMV KGK;l9ul@m{EI)(* literal 0 HcmV?d00001 diff --git a/resources/profiles/Custom/filament/My Generic ABS @MyToolChanger.json b/resources/profiles/Custom/filament/My Generic ABS @MyToolChanger.json new file mode 100644 index 0000000000..fb8f51bf95 --- /dev/null +++ b/resources/profiles/Custom/filament/My Generic ABS @MyToolChanger.json @@ -0,0 +1,57 @@ +{ + "type": "filament", + "filament_id": "GFB99", + "setting_id": "GFB99_MTC_0", + "name": "My Generic ABS @MyToolChanger", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_abs", + "filament_flow_ratio": [ + "0.926" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "filament_cooling_final_speed": [ + "3.5" + ], + "filament_cooling_initial_speed": [ + "10" + ], + "filament_cooling_moves": [ + "2" + ], + "filament_load_time": [ + "10.5" + ], + "filament_loading_speed": [ + "10" + ], + "filament_loading_speed_start": [ + "50" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_unload_time": [ + "8.5" + ], + "filament_unloading_speed": [ + "100" + ], + "compatible_printers": [ + "MyToolChanger 0.4 nozzle", + "MyToolChanger 0.2 nozzle", + "MyToolChanger 0.6 nozzle", + "MyToolChanger 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Custom/filament/My Generic ASA @MyToolChanger.json b/resources/profiles/Custom/filament/My Generic ASA @MyToolChanger.json new file mode 100644 index 0000000000..05bab114b4 --- /dev/null +++ b/resources/profiles/Custom/filament/My Generic ASA @MyToolChanger.json @@ -0,0 +1,57 @@ +{ + "type": "filament", + "filament_id": "GFB98", + "setting_id": "GFB98_MTC_0", + "name": "My Generic ASA @MyToolChanger", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_asa", + "filament_flow_ratio": [ + "0.93" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "filament_cooling_final_speed": [ + "3.5" + ], + "filament_cooling_initial_speed": [ + "10" + ], + "filament_cooling_moves": [ + "2" + ], + "filament_load_time": [ + "10.5" + ], + "filament_loading_speed": [ + "10" + ], + "filament_loading_speed_start": [ + "50" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_unload_time": [ + "8.5" + ], + "filament_unloading_speed": [ + "100" + ], + "compatible_printers": [ + "MyToolChanger 0.4 nozzle", + "MyToolChanger 0.2 nozzle", + "MyToolChanger 0.6 nozzle", + "MyToolChanger 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Custom/filament/My Generic PA @MyToolChanger.json b/resources/profiles/Custom/filament/My Generic PA @MyToolChanger.json new file mode 100644 index 0000000000..17a9b793cc --- /dev/null +++ b/resources/profiles/Custom/filament/My Generic PA @MyToolChanger.json @@ -0,0 +1,60 @@ +{ + "type": "filament", + "filament_id": "GFN99", + "setting_id": "GFN99_MTC_0", + "name": "My Generic PA @MyToolChanger", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pa", + "nozzle_temperature_initial_layer": [ + "280" + ], + "nozzle_temperature": [ + "280" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "filament_cooling_final_speed": [ + "3.5" + ], + "filament_cooling_initial_speed": [ + "10" + ], + "filament_cooling_moves": [ + "2" + ], + "filament_load_time": [ + "10.5" + ], + "filament_loading_speed": [ + "10" + ], + "filament_loading_speed_start": [ + "50" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_unload_time": [ + "8.5" + ], + "filament_unloading_speed": [ + "100" + ], + "compatible_printers": [ + "MyToolChanger 0.4 nozzle", + "MyToolChanger 0.2 nozzle", + "MyToolChanger 0.6 nozzle", + "MyToolChanger 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Custom/filament/My Generic PA-CF @MyToolChanger.json b/resources/profiles/Custom/filament/My Generic PA-CF @MyToolChanger.json new file mode 100644 index 0000000000..0b0f065eed --- /dev/null +++ b/resources/profiles/Custom/filament/My Generic PA-CF @MyToolChanger.json @@ -0,0 +1,63 @@ +{ + "type": "filament", + "filament_id": "GFN98", + "setting_id": "GFN98_MTC_0", + "name": "My Generic PA-CF @MyToolChanger", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pa", + "filament_type": [ + "PA-CF" + ], + "nozzle_temperature_initial_layer": [ + "280" + ], + "nozzle_temperature": [ + "280" + ], + "filament_max_volumetric_speed": [ + "8" + ], + "filament_cooling_final_speed": [ + "3.5" + ], + "filament_cooling_initial_speed": [ + "10" + ], + "filament_cooling_moves": [ + "2" + ], + "filament_load_time": [ + "10.5" + ], + "filament_loading_speed": [ + "10" + ], + "filament_loading_speed_start": [ + "50" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_unload_time": [ + "8.5" + ], + "filament_unloading_speed": [ + "100" + ], + "compatible_printers": [ + "MyToolChanger 0.4 nozzle", + "MyToolChanger 0.2 nozzle", + "MyToolChanger 0.6 nozzle", + "MyToolChanger 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Custom/filament/My Generic PC @MyToolChanger.json b/resources/profiles/Custom/filament/My Generic PC @MyToolChanger.json new file mode 100644 index 0000000000..7ae24c6774 --- /dev/null +++ b/resources/profiles/Custom/filament/My Generic PC @MyToolChanger.json @@ -0,0 +1,57 @@ +{ + "type": "filament", + "filament_id": "GFC99", + "setting_id": "GFC99_MTC_0", + "name": "My Generic PC @MyToolChanger", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pc", + "filament_max_volumetric_speed": [ + "12" + ], + "filament_flow_ratio": [ + "0.94" + ], + "filament_cooling_final_speed": [ + "3.5" + ], + "filament_cooling_initial_speed": [ + "10" + ], + "filament_cooling_moves": [ + "2" + ], + "filament_load_time": [ + "10.5" + ], + "filament_loading_speed": [ + "10" + ], + "filament_loading_speed_start": [ + "50" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_unload_time": [ + "8.5" + ], + "filament_unloading_speed": [ + "100" + ], + "compatible_printers": [ + "MyToolChanger 0.4 nozzle", + "MyToolChanger 0.2 nozzle", + "MyToolChanger 0.6 nozzle", + "MyToolChanger 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Custom/filament/My Generic PETG @MyToolChanger.json b/resources/profiles/Custom/filament/My Generic PETG @MyToolChanger.json new file mode 100644 index 0000000000..f9cb2e0b16 --- /dev/null +++ b/resources/profiles/Custom/filament/My Generic PETG @MyToolChanger.json @@ -0,0 +1,87 @@ +{ + "type": "filament", + "filament_id": "GFG99", + "setting_id": "GFG99_MTC_0", + "name": "My Generic PETG @MyToolChanger", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pet", + "reduce_fan_stop_start_freq": [ + "1" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "fan_cooling_layer_time": [ + "30" + ], + "overhang_fan_speed": [ + "90" + ], + "overhang_fan_threshold": [ + "25%" + ], + "fan_max_speed": [ + "90" + ], + "fan_min_speed": [ + "40" + ], + "slow_down_min_speed": [ + "10" + ], + "slow_down_layer_time": [ + "8" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_max_volumetric_speed": [ + "10" + ], + "filament_start_gcode": [ + "; filament start gcode\n" + ], + "filament_cooling_final_speed": [ + "3.5" + ], + "filament_cooling_initial_speed": [ + "10" + ], + "filament_cooling_moves": [ + "2" + ], + "filament_load_time": [ + "10.5" + ], + "filament_loading_speed": [ + "10" + ], + "filament_loading_speed_start": [ + "50" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_unload_time": [ + "8.5" + ], + "filament_unloading_speed": [ + "100" + ], + "compatible_printers": [ + "MyToolChanger 0.4 nozzle", + "MyToolChanger 0.2 nozzle", + "MyToolChanger 0.6 nozzle", + "MyToolChanger 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Custom/filament/My Generic PLA @MyToolChanger.json b/resources/profiles/Custom/filament/My Generic PLA @MyToolChanger.json new file mode 100644 index 0000000000..facaf08984 --- /dev/null +++ b/resources/profiles/Custom/filament/My Generic PLA @MyToolChanger.json @@ -0,0 +1,60 @@ +{ + "type": "filament", + "filament_id": "GFL99", + "setting_id": "GFL99_MTC_0", + "name": "My Generic PLA @MyToolChanger", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pla", + "filament_flow_ratio": [ + "0.98" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "slow_down_layer_time": [ + "8" + ], + "filament_cooling_final_speed": [ + "3.5" + ], + "filament_cooling_initial_speed": [ + "10" + ], + "filament_cooling_moves": [ + "2" + ], + "filament_load_time": [ + "10.5" + ], + "filament_loading_speed": [ + "10" + ], + "filament_loading_speed_start": [ + "50" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_unload_time": [ + "8.5" + ], + "filament_unloading_speed": [ + "100" + ], + "compatible_printers": [ + "MyToolChanger 0.4 nozzle", + "MyToolChanger 0.2 nozzle", + "MyToolChanger 0.6 nozzle", + "MyToolChanger 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Custom/filament/My Generic PLA-CF @MyToolChanger.json b/resources/profiles/Custom/filament/My Generic PLA-CF @MyToolChanger.json new file mode 100644 index 0000000000..8adf8d53d2 --- /dev/null +++ b/resources/profiles/Custom/filament/My Generic PLA-CF @MyToolChanger.json @@ -0,0 +1,63 @@ +{ + "type": "filament", + "filament_id": "GFL98", + "setting_id": "GFL98_MTC_0", + "name": "My Generic PLA-CF @MyToolChanger", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pla", + "filament_flow_ratio": [ + "0.95" + ], + "filament_type": [ + "PLA-CF" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "slow_down_layer_time": [ + "7" + ], + "filament_cooling_final_speed": [ + "3.5" + ], + "filament_cooling_initial_speed": [ + "10" + ], + "filament_cooling_moves": [ + "2" + ], + "filament_load_time": [ + "10.5" + ], + "filament_loading_speed": [ + "10" + ], + "filament_loading_speed_start": [ + "50" + ], + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_unload_time": [ + "8.5" + ], + "filament_unloading_speed": [ + "100" + ], + "compatible_printers": [ + "MyToolChanger 0.4 nozzle", + "MyToolChanger 0.2 nozzle", + "MyToolChanger 0.6 nozzle", + "MyToolChanger 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Custom/filament/My Generic PVA @MyToolChanger.json b/resources/profiles/Custom/filament/My Generic PVA @MyToolChanger.json new file mode 100644 index 0000000000..a2dd357753 --- /dev/null +++ b/resources/profiles/Custom/filament/My Generic PVA @MyToolChanger.json @@ -0,0 +1,27 @@ +{ + "type": "filament", + "filament_id": "GFS99", + "setting_id": "GFS99_MTC_0", + "name": "My Generic PVA @MyToolChanger", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pva", + "filament_flow_ratio": [ + "0.95" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "slow_down_layer_time": [ + "7" + ], + "slow_down_min_speed": [ + "10" + ], + "compatible_printers": [ + "MyToolChanger 0.4 nozzle", + "MyToolChanger 0.2 nozzle", + "MyToolChanger 0.6 nozzle", + "MyToolChanger 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Custom/filament/My Generic TPU @MyToolChanger.json b/resources/profiles/Custom/filament/My Generic TPU @MyToolChanger.json new file mode 100644 index 0000000000..54c4a15a19 --- /dev/null +++ b/resources/profiles/Custom/filament/My Generic TPU @MyToolChanger.json @@ -0,0 +1,18 @@ +{ + "type": "filament", + "filament_id": "GFU99", + "setting_id": "GFU99_MTC_0", + "name": "My Generic TPU @MyToolChanger", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_tpu", + "filament_max_volumetric_speed": [ + "3.2" + ], + "compatible_printers": [ + "MyToolChanger 0.4 nozzle", + "MyToolChanger 0.2 nozzle", + "MyToolChanger 0.6 nozzle", + "MyToolChanger 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Custom/machine/MyToolChanger 0.2 nozzle.json b/resources/profiles/Custom/machine/MyToolChanger 0.2 nozzle.json new file mode 100644 index 0000000000..f23384aee7 --- /dev/null +++ b/resources/profiles/Custom/machine/MyToolChanger 0.2 nozzle.json @@ -0,0 +1,30 @@ +{ + "type": "machine", + "setting_id": "GM_CUSTOM_001", + "name": "MyToolChanger 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_toolchanger_common", + "printer_model": "Generic ToolChanger Printer", + "nozzle_diameter": [ + "0.2", + "0.2", + "0.2", + "0.2", + "0.2" + ], + "max_layer_height": [ + "0.16" + ], + "min_layer_height": [ + "0.04" + ], + "printer_variant": "0.2", + "printable_area": [ + "0x0", + "350x0", + "350x350", + "0x350" + ], + "printable_height": "300" +} \ No newline at end of file diff --git a/resources/profiles/Custom/machine/MyToolChanger 0.4 nozzle.json b/resources/profiles/Custom/machine/MyToolChanger 0.4 nozzle.json new file mode 100644 index 0000000000..cf43dd0a41 --- /dev/null +++ b/resources/profiles/Custom/machine/MyToolChanger 0.4 nozzle.json @@ -0,0 +1,24 @@ +{ + "type": "machine", + "setting_id": "GM_CUSTOM_002", + "name": "MyToolChanger 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_toolchanger_common", + "printer_model": "Generic ToolChanger Printer", + "nozzle_diameter": [ + "0.4", + "0.4", + "0.4", + "0.4", + "0.4" + ], + "printer_variant": "0.4", + "printable_area": [ + "0x0", + "350x0", + "350x350", + "0x350" + ], + "printable_height": "300" +} \ No newline at end of file diff --git a/resources/profiles/Custom/machine/MyToolChanger 0.6 nozzle.json b/resources/profiles/Custom/machine/MyToolChanger 0.6 nozzle.json new file mode 100644 index 0000000000..b8d387573f --- /dev/null +++ b/resources/profiles/Custom/machine/MyToolChanger 0.6 nozzle.json @@ -0,0 +1,30 @@ +{ + "type": "machine", + "setting_id": "GM_CUSTOM_003", + "name": "MyToolChanger 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_toolchanger_common", + "printer_model": "Generic ToolChanger Printer", + "nozzle_diameter": [ + "0.6", + "0.6", + "0.6", + "0.6", + "0.6" + ], + "max_layer_height": [ + "0.4" + ], + "min_layer_height": [ + "0.12" + ], + "printer_variant": "0.6", + "printable_area": [ + "0x0", + "350x0", + "350x350", + "0x350" + ], + "printable_height": "300" +} \ No newline at end of file diff --git a/resources/profiles/Custom/machine/MyToolChanger 0.8 nozzle.json b/resources/profiles/Custom/machine/MyToolChanger 0.8 nozzle.json new file mode 100644 index 0000000000..2ce7029dce --- /dev/null +++ b/resources/profiles/Custom/machine/MyToolChanger 0.8 nozzle.json @@ -0,0 +1,30 @@ +{ + "type": "machine", + "setting_id": "GM_CUSTOM_004", + "name": "MyToolChanger 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_toolchanger_common", + "printer_model": "Generic ToolChanger Printer", + "nozzle_diameter": [ + "0.8", + "0.8", + "0.8", + "0.8", + "0.8" + ], + "max_layer_height": [ + "0.6" + ], + "min_layer_height": [ + "0.2" + ], + "printer_variant": "0.8", + "printable_area": [ + "0x0", + "350x0", + "350x350", + "0x350" + ], + "printable_height": "300" +} \ No newline at end of file diff --git a/resources/profiles/Custom/machine/MyToolChanger.json b/resources/profiles/Custom/machine/MyToolChanger.json new file mode 100644 index 0000000000..9c927e4be2 --- /dev/null +++ b/resources/profiles/Custom/machine/MyToolChanger.json @@ -0,0 +1,12 @@ +{ + "type": "machine_model", + "name": "Generic ToolChanger Printer", + "model_id": "my_toolchanger_01", + "nozzle_diameter": "0.4;0.2;0.6;0.8", + "machine_tech": "FFF", + "family": "MyPrinter", + "bed_model": "Custom_350_bed.stl", + "bed_texture": "orcaslicer_bed_texture.svg", + "hotend_model": "", + "default_materials": "My Generic PLA @MyToolChanger;My Generic ABS @MyToolChanger;My Generic PLA-CF @MyToolChanger;My Generic PETG @MyToolChanger;My Generic TPU @MyToolChanger;My Generic ASA @MyToolChanger;My Generic PC @MyToolChanger;My Generic PVA @MyToolChanger;My Generic PA @MyToolChanger;My Generic PA-CF @MyToolChanger" +} diff --git a/resources/profiles/Custom/machine/fdm_toolchanger_common.json b/resources/profiles/Custom/machine/fdm_toolchanger_common.json new file mode 100644 index 0000000000..9d724ed88f --- /dev/null +++ b/resources/profiles/Custom/machine/fdm_toolchanger_common.json @@ -0,0 +1,189 @@ +{ + "type": "machine", + "name": "fdm_toolchanger_common", + "from": "system", + "instantiation": "false", + "inherits": "fdm_klipper_common", + "gcode_flavor": "klipper", + "single_extruder_multi_material": "0", + "default_filament_profile": [ + "My Generic PLA @MyToolChanger" + ], + "default_print_profile": "0.20mm Standard @MyToolChanger", + "max_layer_height": [ + "0.32", + "0.32", + "0.32", + "0.32", + "0.32" + ], + "min_layer_height": [ + "0.08", + "0.08", + "0.08", + "0.08", + "0.08" + ], + "deretraction_speed": [ + "30", + "30", + "30", + "30", + "30" + ], + "extruder_colour": [ + "#FCE94F", + "#FCE94F", + "#FCE94F", + "#FCE94F", + "#FCE94F" + ], + "extruder_offset": [ + "0x0", + "0x0", + "0x0", + "0x0", + "0x0" + ], + "long_retractions_when_cut": [ + "0", + "0", + "0", + "0", + "0" + ], + "nozzle_diameter": [ + "0.4", + "0.4", + "0.4", + "0.4", + "0.4" + ], + "retract_before_wipe": [ + "70%", + "70%", + "70%", + "70%", + "70%" + ], + "retract_length_toolchange": [ + "2", + "2", + "2", + "2", + "2" + ], + "retract_lift_above": [ + "0", + "0", + "0", + "0", + "0" + ], + "retract_lift_below": [ + "0", + "0", + "0", + "0", + "0" + ], + "retract_lift_enforce": [ + "All Surfaces", + "All Surfaces", + "All Surfaces", + "All Surfaces", + "All Surfaces" + ], + "retract_restart_extra": [ + "0", + "0", + "0", + "0", + "0" + ], + "retract_restart_extra_toolchange": [ + "0", + "0", + "0", + "0", + "0" + ], + "retract_when_changing_layer": [ + "1", + "1", + "1", + "1", + "1" + ], + "retraction_distances_when_cut": [ + "18", + "18", + "18", + "18", + "18" + ], + "retraction_length": [ + "0.8", + "0.8", + "0.8", + "0.8", + "0.8" + ], + "retraction_minimum_travel": [ + "1", + "1", + "1", + "1", + "1" + ], + "retraction_speed": [ + "30", + "30", + "30", + "30", + "30" + ], + "travel_slope": [ + "3", + "3", + "3", + "3", + "3" + ], + "version": "2.1.1.1", + "wipe": [ + "1", + "1", + "1", + "1", + "1" + ], + "wipe_distance": [ + "1", + "1", + "1", + "1", + "1" + ], + "z_hop": [ + "0.4", + "0.4", + "0.4", + "0.4", + "0.4" + ], + "z_hop_types": [ + "Normal Lift", + "Normal Lift", + "Normal Lift", + "Normal Lift", + "Normal Lift" + ], + "purge_in_prime_tower": "0", + "machine_pause_gcode": "M601", + "machine_start_gcode": "PRINT_START TOOL_TEMP={first_layer_temperature[initial_tool]} {if is_extruder_used[0]}T0_TEMP={first_layer_temperature[0]}{endif} {if is_extruder_used[1]}T1_TEMP={first_layer_temperature[1]}{endif} {if is_extruder_used[2]}T2_TEMP={first_layer_temperature[2]}{endif} {if is_extruder_used[3]}T3_TEMP={first_layer_temperature[3]}{endif} {if is_extruder_used[4]}T4_TEMP={first_layer_temperature[4]}{endif} {if is_extruder_used[5]}T5_TEMP={first_layer_temperature[5]}{endif} BED_TEMP=[first_layer_bed_temperature] TOOL=[initial_tool]\n\n", + "change_filament_gcode": "M104 S{nozzle_temperature[next_extruder]} T[next_extruder] ; set new tool temperature so it can start heating while changing", + "scan_first_layer": "0", + "nozzle_type": "undefine", + "auxiliary_fan": "0" +} \ No newline at end of file diff --git a/resources/profiles/Custom/process/0.08mm Extra Fine @MyToolChanger.json b/resources/profiles/Custom/process/0.08mm Extra Fine @MyToolChanger.json new file mode 100644 index 0000000000..4ce1736916 --- /dev/null +++ b/resources/profiles/Custom/process/0.08mm Extra Fine @MyToolChanger.json @@ -0,0 +1,19 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.08mm Extra Fine @MyToolChanger", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_mytoolchanger_common", + "layer_height": "0.08", + "bottom_shell_layers": "7", + "top_shell_layers": "9", + "support_top_z_distance": "0.08", + "support_bottom_z_distance": "0.08", + "initial_layer_print_height": "0.2", + "compatible_printers": [ + "MyToolChanger 0.4 nozzle", + "MyToolChanger 0.2 nozzle", + "MyToolChanger 0.6 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Custom/process/0.12mm Fine @MyToolChanger.json b/resources/profiles/Custom/process/0.12mm Fine @MyToolChanger.json new file mode 100644 index 0000000000..1117ba588f --- /dev/null +++ b/resources/profiles/Custom/process/0.12mm Fine @MyToolChanger.json @@ -0,0 +1,19 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.12mm Fine @MyToolChanger", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_mytoolchanger_common", + "layer_height": "0.12", + "bottom_shell_layers": "5", + "top_shell_layers": "6", + "support_top_z_distance": "0.08", + "support_bottom_z_distance": "0.08", + "initial_layer_print_height": "0.2", + "compatible_printers": [ + "MyToolChanger 0.4 nozzle", + "MyToolChanger 0.2 nozzle", + "MyToolChanger 0.6 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Custom/process/0.15mm Optimal @MyToolChanger.json b/resources/profiles/Custom/process/0.15mm Optimal @MyToolChanger.json new file mode 100644 index 0000000000..13254161c8 --- /dev/null +++ b/resources/profiles/Custom/process/0.15mm Optimal @MyToolChanger.json @@ -0,0 +1,20 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.15mm Optimal @MyToolChanger", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_mytoolchanger_common", + "bottom_shell_layers": "4", + "top_shell_layers": "5", + "layer_height": "0.15", + "support_top_z_distance": "0.15", + "support_bottom_z_distance": "0.15", + "initial_layer_print_height": "0.2", + "compatible_printers": [ + "MyToolChanger 0.4 nozzle", + "MyToolChanger 0.2 nozzle", + "MyToolChanger 0.6 nozzle", + "MyToolChanger 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Custom/process/0.16mm Optimal @MyToolChanger.json b/resources/profiles/Custom/process/0.16mm Optimal @MyToolChanger.json new file mode 100644 index 0000000000..f3fa8058a5 --- /dev/null +++ b/resources/profiles/Custom/process/0.16mm Optimal @MyToolChanger.json @@ -0,0 +1,20 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.16mm Optimal @MyToolChanger", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_mytoolchanger_common", + "bottom_shell_layers": "4", + "top_shell_layers": "5", + "support_top_z_distance": "0.16", + "support_bottom_z_distance": "0.16", + "layer_height": "0.16", + "initial_layer_print_height": "0.2", + "compatible_printers": [ + "MyToolChanger 0.4 nozzle", + "MyToolChanger 0.2 nozzle", + "MyToolChanger 0.6 nozzle", + "MyToolChanger 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Custom/process/0.20mm Standard @MyToolChanger.json b/resources/profiles/Custom/process/0.20mm Standard @MyToolChanger.json new file mode 100644 index 0000000000..812886e486 --- /dev/null +++ b/resources/profiles/Custom/process/0.20mm Standard @MyToolChanger.json @@ -0,0 +1,14 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.20mm Standard @MyToolChanger", + "from": "system", + "inherits": "fdm_process_mytoolchanger_common", + "instantiation": "true", + "layer_height": "0.2", + "compatible_printers": [ + "MyToolChanger 0.4 nozzle", + "MyToolChanger 0.6 nozzle", + "MyToolChanger 0.8 nozzle" + ] +} diff --git a/resources/profiles/Custom/process/0.24mm Draft @MyToolChanger.json b/resources/profiles/Custom/process/0.24mm Draft @MyToolChanger.json new file mode 100644 index 0000000000..af372cc109 --- /dev/null +++ b/resources/profiles/Custom/process/0.24mm Draft @MyToolChanger.json @@ -0,0 +1,17 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.24mm Draft @MyToolChanger", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_mytoolchanger_common", + "support_top_z_distance": "0.2", + "support_bottom_z_distance": "0.2", + "layer_height": "0.24", + "initial_layer_print_height": "0.2", + "compatible_printers": [ + "MyToolChanger 0.4 nozzle", + "MyToolChanger 0.6 nozzle", + "MyToolChanger 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Custom/process/0.28mm Extra Draft @MyToolChanger.json b/resources/profiles/Custom/process/0.28mm Extra Draft @MyToolChanger.json new file mode 100644 index 0000000000..71f435467b --- /dev/null +++ b/resources/profiles/Custom/process/0.28mm Extra Draft @MyToolChanger.json @@ -0,0 +1,15 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.28mm Extra Draft @MyToolChanger", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_mytoolchanger_common", + "layer_height": "0.28", + "initial_layer_print_height": "0.2", + "compatible_printers": [ + "MyToolChanger 0.4 nozzle", + "MyToolChanger 0.6 nozzle", + "MyToolChanger 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Custom/process/0.32mm Extra Draft @MyToolChanger.json b/resources/profiles/Custom/process/0.32mm Extra Draft @MyToolChanger.json new file mode 100644 index 0000000000..d5282eecef --- /dev/null +++ b/resources/profiles/Custom/process/0.32mm Extra Draft @MyToolChanger.json @@ -0,0 +1,17 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.32mm Standard @MyToolChanger", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_mytoolchanger_common", + "support_top_z_distance": "0.24", + "support_bottom_z_distance": "0.24", + "layer_height": "0.32", + "initial_layer_print_height": "0.2", + "compatible_printers": [ + "MyToolChanger 0.4 nozzle", + "MyToolChanger 0.6 nozzle", + "MyToolChanger 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Custom/process/0.40mm Extra Draft @MyToolChanger.json b/resources/profiles/Custom/process/0.40mm Extra Draft @MyToolChanger.json new file mode 100644 index 0000000000..940d51d8bf --- /dev/null +++ b/resources/profiles/Custom/process/0.40mm Extra Draft @MyToolChanger.json @@ -0,0 +1,16 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.40mm Standard @MyToolChanger", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_mytoolchanger_common", + "support_top_z_distance": "0.24", + "support_bottom_z_distance": "0.24", + "layer_height": "0.40", + "initial_layer_print_height": "0.2", + "compatible_printers": [ + "MyToolChanger 0.6 nozzle", + "MyToolChanger 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Custom/process/0.56mm Extra Draft @MyToolChanger.json b/resources/profiles/Custom/process/0.56mm Extra Draft @MyToolChanger.json new file mode 100644 index 0000000000..ea4ba5c07d --- /dev/null +++ b/resources/profiles/Custom/process/0.56mm Extra Draft @MyToolChanger.json @@ -0,0 +1,15 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.56mm Standard @MyToolChanger", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_mytoolchanger_common", + "support_top_z_distance": "0.24", + "support_bottom_z_distance": "0.24", + "layer_height": "0.56", + "initial_layer_print_height": "0.2", + "compatible_printers": [ + "MyToolChanger 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Custom/process/fdm_process_mytoolchanger_common.json b/resources/profiles/Custom/process/fdm_process_mytoolchanger_common.json new file mode 100644 index 0000000000..9d6e497afe --- /dev/null +++ b/resources/profiles/Custom/process/fdm_process_mytoolchanger_common.json @@ -0,0 +1,27 @@ +{ + "type": "process", + "name": "fdm_process_mytoolchanger_common", + "from": "system", + "instantiation": "false", + "inherits": "fdm_process_klipper_common", + "default_acceleration": "5000", + "top_surface_acceleration": "3000", + "travel_acceleration": "7000", + "inner_wall_acceleration": "5000", + "outer_wall_acceleration": "3000", + "initial_layer_acceleration": "500", + "initial_layer_speed": "50", + "initial_layer_infill_speed": "105", + "outer_wall_speed": "120", + "inner_wall_speed": "200", + "internal_solid_infill_speed": "200", + "top_surface_speed": "100", + "gap_infill_speed": "100", + "sparse_infill_speed": "200", + "travel_speed": "350", + "exclude_object": "1", + "enable_prime_tower": "1", + "wipe_tower_cone_angle": "25", + "wipe_tower_extra_spacing": "150%", + "wipe_tower_rotation_angle": "90" +} \ No newline at end of file From c3f0b5e565f91721abe110b5f81a11d0dad88e75 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Wed, 10 Jul 2024 21:17:04 +0800 Subject: [PATCH 08/32] ooze prevention update: sync with PrusaSlicer --- src/libslic3r/GCode.cpp | 69 +++++++++-------------------------------- src/libslic3r/GCode.hpp | 3 +- 2 files changed, 16 insertions(+), 56 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index c9c48fce7d..1d7dc09f0e 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -256,30 +256,15 @@ static std::vector get_path_of_change_filament(const Print& print) { std::string gcode; - // move to the nearest standby point - if (!this->standby_points.empty()) { - // get current position in print coordinates - Vec3d writer_pos = gcodegen.writer().get_position(); - Point pos = Point::new_scale(writer_pos(0), writer_pos(1)); - - // find standby point - Point standby_point; - pos.nearest_point(this->standby_points, &standby_point); - - /* We don't call gcodegen.travel_to() because we don't need retraction (it was already - triggered by the caller) nor reduce_crossing_wall and also because the coordinates - of the destination point must not be transformed by origin nor current extruder offset. */ - gcode += gcodegen.writer().travel_to_xy(unscale(standby_point), - "move to standby position"); - } unsigned int extruder_id = gcodegen.writer().extruder()->id(); - const ConfigOptionInts& filament_idle_temp = gcodegen.config().idle_temperature; - - if (filament_idle_temp.get_at(extruder_id) == 0) { + const auto& filament_idle_temp = gcodegen.config().idle_temperature; + if (filament_idle_temp.get_at(extruder_id) > 0) { + // There is no idle temperature defined in filament settings. + // Use the delta value from print config. if (gcodegen.config().standby_temperature_delta.value != 0) { // we assume that heating is always slower than cooling, so no need to block - gcode += gcodegen.writer().set_temperature(this->_get_temp(gcodegen) + gcodegen.config().standby_temperature_delta.value, - false, gcodegen.writer().extruder()->id()); + gcode += gcodegen.writer().set_temperature + (this->_get_temp(gcodegen) + gcodegen.config().standby_temperature_delta.value, false, extruder_id); gcode.pop_back(); gcode += " ;cooldown\n"; // this is a marker for GCodeProcessor, so it can supress the commands when needed } @@ -300,14 +285,16 @@ static std::vector get_path_of_change_filament(const Print& print) std::string(); } - int - OozePrevention::_get_temp(GCode& gcodegen) + int OozePrevention::_get_temp(const GCode &gcodegen) const { - return (gcodegen.layer() != NULL && gcodegen.layer()->id() == 0) + // First layer temperature should be used when on the first layer (obviously) and when + // "other layers" is set to zero (which means it should not be used). + return (gcodegen.layer() == nullptr || gcodegen.layer()->id() == 0 + || gcodegen.config().nozzle_temperature.get_at(gcodegen.writer().extruder()->id()) == 0) ? gcodegen.config().nozzle_temperature_initial_layer.get_at(gcodegen.writer().extruder()->id()) : gcodegen.config().nozzle_temperature.get_at(gcodegen.writer().extruder()->id()); } - + // Orca: // Function to calculate the excess retraction length that should be retracted either before or after wiping // in order for the wipe operation to respect the filament retraction speed @@ -1732,34 +1719,7 @@ namespace DoExport { static void init_ooze_prevention(const Print &print, OozePrevention &ooze_prevention) { - // Calculate wiping points if needed - if (print.config().ooze_prevention.value && ! print.config().single_extruder_multi_material) { - Points skirt_points; - for (const ExtrusionEntity *ee : print.skirt().entities) - for (const ExtrusionPath &path : dynamic_cast(ee)->paths) - append(skirt_points, path.polyline.points); - if (! skirt_points.empty()) { - Polygon outer_skirt = Slic3r::Geometry::convex_hull(skirt_points); - Polygons skirts; - for (unsigned int extruder_id : print.extruders()) { - const Vec2d &extruder_offset = print.config().extruder_offset.get_at(extruder_id); - Polygon s(outer_skirt); - s.translate(Point::new_scale(-extruder_offset(0), -extruder_offset(1))); - skirts.emplace_back(std::move(s)); - } - ooze_prevention.enable = true; - ooze_prevention.standby_points = offset(Slic3r::Geometry::convex_hull(skirts), float(scale_(3.))).front().equally_spaced_points(float(scale_(10.))); - #if 0 - require "Slic3r/SVG.pm"; - Slic3r::SVG::output( - "ooze_prevention.svg", - red_polygons => \@skirts, - polygons => [$outer_skirt], - points => $gcodegen->ooze_prevention->standby_points, - ); - #endif - } - } + ooze_prevention.enable = print.config().ooze_prevention.value && ! print.config().single_extruder_multi_material; } // Fill in print_statistics and return formatted string containing filament statistics to be inserted into G-code comment section. @@ -3776,7 +3736,8 @@ LayerResult GCode::process_layer( // Transition from 1st to 2nd layer. Adjust nozzle temperatures as prescribed by the nozzle dependent // nozzle_temperature_initial_layer vs. temperature settings. for (const Extruder &extruder : m_writer.extruders()) { - if (print.config().single_extruder_multi_material.value && extruder.id() != m_writer.extruder()->id()) + if ((print.config().single_extruder_multi_material.value || m_ooze_prevention.enable) && + extruder.id() != m_writer.extruder()->id()) // In single extruder multi material mode, set the temperature for the current extruder only. continue; int temperature = print.config().nozzle_temperature.get_at(extruder.id()); diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 18ea653546..9fff855040 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -43,14 +43,13 @@ class ConstPrintObjectPtrsAdaptor; class OozePrevention { public: bool enable; - Points standby_points; OozePrevention() : enable(false) {} std::string pre_toolchange(GCode &gcodegen); std::string post_toolchange(GCode &gcodegen); private: - int _get_temp(GCode &gcodegen); + int _get_temp(const GCode &gcodegen) const; }; class Wipe { From c719f5c95c5c369320ddc9afdc18519a3058dc8a Mon Sep 17 00:00:00 2001 From: SoftFever Date: Wed, 10 Jul 2024 21:37:06 +0800 Subject: [PATCH 09/32] tweak UI --- .../Generic ToolChanger Printer_cover.png | Bin 0 -> 118525 bytes src/libslic3r/PrintConfig.cpp | 10 ++- src/slic3r/GUI/ConfigManipulation.cpp | 10 ++- src/slic3r/GUI/Tab.cpp | 61 +++++++++--------- 4 files changed, 42 insertions(+), 39 deletions(-) create mode 100644 resources/profiles/Custom/Generic ToolChanger Printer_cover.png diff --git a/resources/profiles/Custom/Generic ToolChanger Printer_cover.png b/resources/profiles/Custom/Generic ToolChanger Printer_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..508720da28d162892bc33e7176b26b23dcac83f1 GIT binary patch literal 118525 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 F{{Yp%WZ3`! literal 0 HcmV?d00001 diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index bc34ccc6ed..4045f41e33 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -3355,10 +3355,8 @@ void PrintConfigDef::init_fff_params() def = this->add("ooze_prevention", coBool); def->label = L("Enable"); - //def->tooltip = L("This option will drop the temperature of the inactive extruders to prevent oozing. " - // "It will enable a tall skirt automatically and move extruders outside such " - // "skirt when changing temperatures."); - def->mode = comDevelop; + def->tooltip = L("This option will drop the temperature of the inactive extruders to prevent oozing."); + def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(false)); def = this->add("filename_format", coString); @@ -4002,7 +4000,7 @@ void PrintConfigDef::init_fff_params() def->category = "Extruders"; def->tooltip = "Filament to print solid infill"; def->min = 1; - def->mode = comDevelop; + def->mode = comAdvanced; def->set_default_value(new ConfigOptionInt(1)); def = this->add("internal_solid_infill_line_width", coFloatOrPercent); @@ -4079,7 +4077,7 @@ void PrintConfigDef::init_fff_params() def->sidetext = "∆°C"; def->min = -max_temp; def->max = max_temp; - def->mode = comDevelop; + def->mode = comAdvanced; def->set_default_value(new ConfigOptionInt(-5)); def = this->add("machine_start_gcode", coString); diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 4752e24c0b..796a11ff0b 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -672,7 +672,13 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co bool have_prime_tower = config->opt_bool("enable_prime_tower"); for (auto el : { "prime_tower_width", "prime_tower_brim_width"}) toggle_line(el, have_prime_tower); - + + auto bSEMM = preset_bundle->printers.get_edited_preset().config.opt_bool("single_extruder_multi_material"); + toggle_field("purge_in_prime_tower", bSEMM); + + for (auto el : {"wall_filament", "sparse_infill_filament", "solid_infill_filament", "wipe_tower_filament"}) + toggle_line(el, !bSEMM); + bool purge_in_primetower = preset_bundle->printers.get_edited_preset().config.opt_bool("purge_in_prime_tower"); for (auto el : {"wipe_tower_rotation_angle", "wipe_tower_cone_angle", @@ -682,7 +688,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co "single_extruder_multi_material_priming"}) toggle_line(el, have_prime_tower); - toggle_line("prime_volume",have_prime_tower && !purge_in_primetower); + toggle_line("prime_volume",have_prime_tower && (!purge_in_primetower || !bSEMM)); for (auto el : {"flush_into_infill", "flush_into_support", "flush_into_objects"}) toggle_field(el, have_prime_tower); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 26e3ec001c..1e5384bc06 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1656,9 +1656,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) //Orca: sync filament num if it's a multi tool printer if (opt_key == "extruders_count" && !m_config->opt_bool("single_extruder_multi_material")){ auto num_extruder = boost::any_cast(value); - wxColour new_col = Plater::get_next_color_for_filament(); - std::string new_color = new_col.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(); - wxGetApp().preset_bundle->set_num_filaments(num_extruder, new_color); + wxGetApp().preset_bundle->set_num_filaments(num_extruder); wxGetApp().plater()->on_filaments_change(num_extruder); wxGetApp().get_tab(Preset::TYPE_PRINT)->update(); wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config); @@ -2277,22 +2275,7 @@ void TabPrint::build() optgroup->append_single_option_line("tree_support_auto_brim"); optgroup->append_single_option_line("tree_support_brim_width"); - page = add_options_page(L("Others"), "custom-gcode_other"); // ORCA: icon only visible on placeholders - optgroup = page->new_optgroup(L("Skirt"), L"param_skirt"); - optgroup->append_single_option_line("skirt_loops"); - optgroup->append_single_option_line("min_skirt_length"); - optgroup->append_single_option_line("skirt_distance"); - optgroup->append_single_option_line("skirt_height"); - optgroup->append_single_option_line("skirt_speed"); - optgroup->append_single_option_line("draft_shield"); - - optgroup = page->new_optgroup(L("Brim"), L"param_adhension"); - optgroup->append_single_option_line("brim_type", "auto-brim"); - optgroup->append_single_option_line("brim_width", "auto-brim#manual"); - optgroup->append_single_option_line("brim_object_gap", "auto-brim#brim-object-gap"); - optgroup->append_single_option_line("brim_ears_max_angle"); - optgroup->append_single_option_line("brim_ears_detection_length"); - + page = add_options_page(L("Multimaterial"), "custom-gcode_multi_material"); // ORCA: icon only visible on placeholders optgroup = page->new_optgroup(L("Prime tower"), L"param_tower"); optgroup->append_single_option_line("enable_prime_tower"); optgroup->append_single_option_line("prime_tower_width"); @@ -2321,6 +2304,31 @@ void TabPrint::build() optgroup->append_single_option_line("flush_into_infill", "reduce-wasting-during-filament-change#wipe-into-infill"); optgroup->append_single_option_line("flush_into_objects", "reduce-wasting-during-filament-change#wipe-into-object"); optgroup->append_single_option_line("flush_into_support", "reduce-wasting-during-filament-change#wipe-into-support-enabled-by-default"); + optgroup = page->new_optgroup(L("Advanced"), L"advanced"); + optgroup->append_single_option_line("interlocking_beam"); + optgroup->append_single_option_line("mmu_segmented_region_max_width"); + optgroup->append_single_option_line("mmu_segmented_region_interlocking_depth"); + optgroup->append_single_option_line("interlocking_beam_width"); + optgroup->append_single_option_line("interlocking_orientation"); + optgroup->append_single_option_line("interlocking_beam_layer_count"); + optgroup->append_single_option_line("interlocking_depth"); + optgroup->append_single_option_line("interlocking_boundary_avoidance"); + +page = add_options_page(L("Others"), "custom-gcode_other"); // ORCA: icon only visible on placeholders + optgroup = page->new_optgroup(L("Skirt"), L"param_skirt"); + optgroup->append_single_option_line("skirt_loops"); + optgroup->append_single_option_line("min_skirt_length"); + optgroup->append_single_option_line("skirt_distance"); + optgroup->append_single_option_line("skirt_height"); + optgroup->append_single_option_line("skirt_speed"); + optgroup->append_single_option_line("draft_shield"); + + optgroup = page->new_optgroup(L("Brim"), L"param_adhension"); + optgroup->append_single_option_line("brim_type", "auto-brim"); + optgroup->append_single_option_line("brim_width", "auto-brim#manual"); + optgroup->append_single_option_line("brim_object_gap", "auto-brim#brim-object-gap"); + optgroup->append_single_option_line("brim_ears_max_angle"); + optgroup->append_single_option_line("brim_ears_detection_length"); optgroup = page->new_optgroup(L("Special mode"), L"param_special"); optgroup->append_single_option_line("slicing_mode"); @@ -2336,16 +2344,6 @@ void TabPrint::build() optgroup->append_single_option_line("fuzzy_skin_thickness"); optgroup->append_single_option_line("fuzzy_skin_first_layer"); - optgroup = page->new_optgroup(L("Advanced"), L"advanced"); - optgroup->append_single_option_line("interlocking_beam"); - optgroup->append_single_option_line("mmu_segmented_region_max_width"); - optgroup->append_single_option_line("mmu_segmented_region_interlocking_depth"); - optgroup->append_single_option_line("interlocking_beam_width"); - optgroup->append_single_option_line("interlocking_orientation"); - optgroup->append_single_option_line("interlocking_beam_layer_count"); - optgroup->append_single_option_line("interlocking_depth"); - optgroup->append_single_option_line("interlocking_boundary_avoidance"); - optgroup = page->new_optgroup(L("G-code output"), L"param_gcode"); optgroup->append_single_option_line("reduce_infill_retraction"); optgroup->append_single_option_line("gcode_add_line_number"); @@ -2365,13 +2363,13 @@ void TabPrint::build() option.opt.is_code = true; option.opt.height = 15; optgroup->append_single_option_line(option); - page = add_options_page(L("Notes"), "custom-gcode_note"); // ORCA: icon only visible on placeholders + optgroup = page->new_optgroup(L("Notes"), "note", 0); option = optgroup->get_option("notes"); option.opt.full_width = true; option.opt.height = 25;//250; optgroup->append_single_option_line(option); - + #if 0 //page = add_options_page(L("Dependencies"), "advanced.png"); // optgroup = page->new_optgroup(L("Profile dependencies")); @@ -4459,6 +4457,7 @@ void TabPrinter::toggle_options() } toggle_option("extruders_count", !bSEMM); toggle_option("manual_filament_change", bSEMM); + toggle_option("purge_in_prime_tower", bSEMM); } wxString extruder_number; long val = 1; From 47d154ebdbaa66c060fafea8aa7ffad6149cff16 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Wed, 10 Jul 2024 21:51:18 +0800 Subject: [PATCH 10/32] update cover image bg --- .../Generic ToolChanger Printer_cover.png | Bin 118525 -> 132945 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/resources/profiles/Custom/Generic ToolChanger Printer_cover.png b/resources/profiles/Custom/Generic ToolChanger Printer_cover.png index 508720da28d162892bc33e7176b26b23dcac83f1..cf85288d7ae1eff989cc5bcc8444773b8785bcac 100644 GIT binary patch literal 132945 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 AtN;K2 literal 118525 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 F{{Yp%WZ3`! From 2fe68edc85f6d9053aafe0c4141f6b9f0a6e5178 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Thu, 11 Jul 2024 22:52:58 +0800 Subject: [PATCH 11/32] Fix crash on printer UI --- src/slic3r/GUI/Plater.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index b1812aa6c2..0a8db799fd 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1385,8 +1385,8 @@ void Sidebar::update_presets(Preset::Type preset_type) /* update bed shape */ Tab* printer_tab = wxGetApp().get_tab(Preset::TYPE_PRINTER); if (printer_tab) { - printer_tab->on_preset_loaded(); printer_tab->update(); + printer_tab->on_preset_loaded(); } Preset& printer_preset = wxGetApp().preset_bundle->printers.get_edited_preset(); From 4bca54873dcfed6462b3fc2b5c3def0e464f9f2a Mon Sep 17 00:00:00 2001 From: SoftFever Date: Fri, 12 Jul 2024 23:03:07 +0800 Subject: [PATCH 12/32] Fix ooze prevention bug --- src/libslic3r/GCode.cpp | 2 +- src/libslic3r/Print.cpp | 6 +++--- src/libslic3r/PrintConfig.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 1d7dc09f0e..0236125186 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -258,7 +258,7 @@ static std::vector get_path_of_change_filament(const Print& print) unsigned int extruder_id = gcodegen.writer().extruder()->id(); const auto& filament_idle_temp = gcodegen.config().idle_temperature; - if (filament_idle_temp.get_at(extruder_id) > 0) { + if (filament_idle_temp.get_at(extruder_id) == 0) { // There is no idle temperature defined in filament settings. // Use the delta value from print config. if (gcodegen.config().standby_temperature_delta.value != 0) { diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 5e687cbbd4..3650b4ef90 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1162,10 +1162,10 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons* if (! m_config.use_relative_e_distances) return { L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1).") }; - if (m_config.ooze_prevention) - return { L("Ooze prevention is currently not supported with the prime tower enabled.") }; - // BBS: remove following logic and _L() + if (m_config.ooze_prevention && m_config.single_extruder_multi_material) + return {L("Ooze prevention is only supported with the wipe tower when 'single_extruder_multi_material' is off.")}; + #if 0 if (m_config.gcode_flavor != gcfRepRapSprinter && m_config.gcode_flavor != gcfRepRapFirmware && m_config.gcode_flavor != gcfRepetier && m_config.gcode_flavor != gcfMarlinLegacy && m_config.gcode_flavor != gcfMarlinFirmware) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 4045f41e33..d6f5cd278c 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -4073,7 +4073,7 @@ void PrintConfigDef::init_fff_params() // TRN PrintSettings : "Ooze prevention" > "Temperature variation" def->tooltip = L("Temperature difference to be applied when an extruder is not active. " "The value is not used when 'idle_temperature' in filament settings " - "is defined."); + "is set to non zero value."); def->sidetext = "∆°C"; def->min = -max_temp; def->max = max_temp; From dd8ce17693c94909777af909fb967cf0a1c62b1d Mon Sep 17 00:00:00 2001 From: SoftFever Date: Fri, 12 Jul 2024 23:17:50 +0800 Subject: [PATCH 13/32] optimize UI: hide flushing_volume_btn for multi tool --- src/slic3r/GUI/Plater.cpp | 6 ++++-- src/slic3r/GUI/Plater.hpp | 2 +- src/slic3r/GUI/Tab.cpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 0a8db799fd..09e91840a2 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1280,7 +1280,7 @@ void Sidebar::update_all_preset_comboboxes() p->m_filament_icon->SetBitmap_("filament"); } - show_add_del_filament_button(cfg.opt_bool("single_extruder_multi_material")); + show_SEMM_buttons(cfg.opt_bool("single_extruder_multi_material")); //p->m_staticText_filament_settings->Update(); @@ -1845,12 +1845,14 @@ void Sidebar::sync_ams_list() Layout(); } -void Sidebar::show_add_del_filament_button(bool bshow) +void Sidebar::show_SEMM_buttons(bool bshow) { if(p->m_bpButton_add_filament) p->m_bpButton_add_filament->Show(bshow); if(p->m_bpButton_del_filament) p->m_bpButton_del_filament->Show(bshow); + if (p->m_flushing_volume_btn) + p->m_flushing_volume_btn->Show(bshow); Layout(); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 95a08c1827..52f0706e89 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -149,7 +149,7 @@ public: std::map build_filament_ams_list(MachineObject* obj); void sync_ams_list(); // Orca - void show_add_del_filament_button(bool bshow); + void show_SEMM_buttons(bool bshow); ObjectList* obj_list(); ObjectSettings* obj_settings(); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 1e5384bc06..0942714fac 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1434,7 +1434,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) if (opt_key == "single_extruder_multi_material" ){ const auto bSEMM = m_config->opt_bool("single_extruder_multi_material"); - wxGetApp().sidebar().show_add_del_filament_button(bSEMM); + wxGetApp().sidebar().show_SEMM_buttons(bSEMM); wxGetApp().get_tab(Preset::TYPE_PRINT)->update(); } From f59c70a7fc2af790af6c00670f87f87894cb1814 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Sat, 13 Jul 2024 13:33:45 +0800 Subject: [PATCH 14/32] Add Prusa XL 5T --- resources/profiles/Prusa.json | 294 +++++++++++++++--- .../filament/Prusa Generic ABS @XL 5T.json | 69 ++++ .../filament/Prusa Generic PETG @XL 5T.json | 72 +++++ .../filament/Prusa Generic PLA @XL 5T.json | 67 ++++ .../Prusa/filament/Prusament ASA @XL 5T.json | 71 +++++ .../filament/Prusament PA-CF @XL 5T.json | 71 +++++ .../filament/Prusament PC Blend @XL 5T.json | 71 +++++ .../filament/Prusament PC-CF @XL 5T.json | 71 +++++ .../Prusa/filament/Prusament PETG @XL 5T.json | 72 +++++ .../Prusa/filament/Prusament PLA @XL 5T.json | 67 ++++ .../Prusa/filament/Prusament PVB @XL 5T.json | 72 +++++ .../Prusa/filament/Prusament rPLA @XL 5T.json | 70 +++++ .../machine/Prusa XL 5T 0.25 nozzle.json | 20 ++ .../Prusa/machine/Prusa XL 5T 0.3 nozzle.json | 20 ++ .../Prusa/machine/Prusa XL 5T 0.4 nozzle.json | 20 ++ .../Prusa/machine/Prusa XL 5T 0.5 nozzle.json | 20 ++ .../Prusa/machine/Prusa XL 5T 0.6 nozzle.json | 20 ++ .../Prusa/machine/Prusa XL 5T 0.8 nozzle.json | 20 ++ .../profiles/Prusa/machine/Prusa XL 5T.json | 12 + .../Prusa/machine/fdm_machine_common_xl.json | 114 +++++++ .../machine/fdm_machine_common_xl_5t.json | 22 ++ .../0.05mm Detail @Prusa XL 5T 0.25.json | 67 ++++ .../0.07mm Detail @Prusa XL 5T 0.25.json | 67 ++++ .../0.10mm FastDetail @Prusa XL 5T 0.4.json | 67 ++++ .../0.10mm Structural @Prusa XL 5T 0.5.json | 68 ++++ .../0.12mm Speed @Prusa XL 5T 0.25.json | 67 ++++ .../0.12mm Structural @Prusa XL 5T 0.25.json | 67 ++++ .../0.12mm Structural @Prusa XL 5T 0.3.json | 67 ++++ .../0.15mm Speed @Prusa XL 5T 0.25.json | 67 ++++ .../0.15mm Speed @Prusa XL 5T 0.4.json | 67 ++++ .../0.15mm Structural @Prusa XL 5T 0.25.json | 67 ++++ .../0.15mm Structural @Prusa XL 5T 0.4.json | 67 ++++ .../0.15mm Structural @Prusa XL 5T 0.5.json | 68 ++++ .../0.15mm Structural @Prusa XL 5T 0.6.json | 69 ++++ .../0.16mm Speed @Prusa XL 5T 0.3.json | 67 ++++ .../0.16mm Structural @Prusa XL 5T 0.3.json | 67 ++++ .../0.20mm Speed @Prusa XL 5T 0.3.json | 67 ++++ .../0.20mm Speed @Prusa XL 5T 0.4.json | 67 ++++ .../0.20mm Speed @Prusa XL 5T 0.5.json | 68 ++++ .../0.20mm Speed @Prusa XL 5T 0.6.json | 69 ++++ .../0.20mm Structural @Prusa XL 5T 0.4.json | 67 ++++ .../0.20mm Structural @Prusa XL 5T 0.5.json | 68 ++++ .../0.20mm Structural @Prusa XL 5T 0.6.json | 69 ++++ .../0.25mm Speed @Prusa XL 5T 0.5.json | 68 ++++ .../0.25mm Speed @Prusa XL 5T 0.6.json | 69 ++++ .../0.25mm Structural @Prusa XL 5T 0.4.json | 67 ++++ .../0.25mm Structural @Prusa XL 5T 0.5.json | 68 ++++ .../0.25mm Structural @Prusa XL 5T 0.6.json | 69 ++++ .../0.30mm Detail @Prusa XL 5T 0.8.json | 71 +++++ .../0.32mm Speed @Prusa XL 5T 0.6.json | 69 ++++ .../0.32mm Structural @Prusa XL 5T 0.6.json | 69 ++++ .../0.40mm Quality @Prusa XL 5T 0.8.json | 71 +++++ .../0.55mm Draft @Prusa XL 5T 0.8.json | 71 +++++ .../Prusa/process/process_common_xl_5t.json | 11 + 54 files changed, 3481 insertions(+), 41 deletions(-) create mode 100644 resources/profiles/Prusa/filament/Prusa Generic ABS @XL 5T.json create mode 100644 resources/profiles/Prusa/filament/Prusa Generic PETG @XL 5T.json create mode 100644 resources/profiles/Prusa/filament/Prusa Generic PLA @XL 5T.json create mode 100644 resources/profiles/Prusa/filament/Prusament ASA @XL 5T.json create mode 100644 resources/profiles/Prusa/filament/Prusament PA-CF @XL 5T.json create mode 100644 resources/profiles/Prusa/filament/Prusament PC Blend @XL 5T.json create mode 100644 resources/profiles/Prusa/filament/Prusament PC-CF @XL 5T.json create mode 100644 resources/profiles/Prusa/filament/Prusament PETG @XL 5T.json create mode 100644 resources/profiles/Prusa/filament/Prusament PLA @XL 5T.json create mode 100644 resources/profiles/Prusa/filament/Prusament PVB @XL 5T.json create mode 100644 resources/profiles/Prusa/filament/Prusament rPLA @XL 5T.json create mode 100644 resources/profiles/Prusa/machine/Prusa XL 5T 0.25 nozzle.json create mode 100644 resources/profiles/Prusa/machine/Prusa XL 5T 0.3 nozzle.json create mode 100644 resources/profiles/Prusa/machine/Prusa XL 5T 0.4 nozzle.json create mode 100644 resources/profiles/Prusa/machine/Prusa XL 5T 0.5 nozzle.json create mode 100644 resources/profiles/Prusa/machine/Prusa XL 5T 0.6 nozzle.json create mode 100644 resources/profiles/Prusa/machine/Prusa XL 5T 0.8 nozzle.json create mode 100644 resources/profiles/Prusa/machine/Prusa XL 5T.json create mode 100644 resources/profiles/Prusa/machine/fdm_machine_common_xl.json create mode 100644 resources/profiles/Prusa/machine/fdm_machine_common_xl_5t.json create mode 100644 resources/profiles/Prusa/process/0.05mm Detail @Prusa XL 5T 0.25.json create mode 100644 resources/profiles/Prusa/process/0.07mm Detail @Prusa XL 5T 0.25.json create mode 100644 resources/profiles/Prusa/process/0.10mm FastDetail @Prusa XL 5T 0.4.json create mode 100644 resources/profiles/Prusa/process/0.10mm Structural @Prusa XL 5T 0.5.json create mode 100644 resources/profiles/Prusa/process/0.12mm Speed @Prusa XL 5T 0.25.json create mode 100644 resources/profiles/Prusa/process/0.12mm Structural @Prusa XL 5T 0.25.json create mode 100644 resources/profiles/Prusa/process/0.12mm Structural @Prusa XL 5T 0.3.json create mode 100644 resources/profiles/Prusa/process/0.15mm Speed @Prusa XL 5T 0.25.json create mode 100644 resources/profiles/Prusa/process/0.15mm Speed @Prusa XL 5T 0.4.json create mode 100644 resources/profiles/Prusa/process/0.15mm Structural @Prusa XL 5T 0.25.json create mode 100644 resources/profiles/Prusa/process/0.15mm Structural @Prusa XL 5T 0.4.json create mode 100644 resources/profiles/Prusa/process/0.15mm Structural @Prusa XL 5T 0.5.json create mode 100644 resources/profiles/Prusa/process/0.15mm Structural @Prusa XL 5T 0.6.json create mode 100644 resources/profiles/Prusa/process/0.16mm Speed @Prusa XL 5T 0.3.json create mode 100644 resources/profiles/Prusa/process/0.16mm Structural @Prusa XL 5T 0.3.json create mode 100644 resources/profiles/Prusa/process/0.20mm Speed @Prusa XL 5T 0.3.json create mode 100644 resources/profiles/Prusa/process/0.20mm Speed @Prusa XL 5T 0.4.json create mode 100644 resources/profiles/Prusa/process/0.20mm Speed @Prusa XL 5T 0.5.json create mode 100644 resources/profiles/Prusa/process/0.20mm Speed @Prusa XL 5T 0.6.json create mode 100644 resources/profiles/Prusa/process/0.20mm Structural @Prusa XL 5T 0.4.json create mode 100644 resources/profiles/Prusa/process/0.20mm Structural @Prusa XL 5T 0.5.json create mode 100644 resources/profiles/Prusa/process/0.20mm Structural @Prusa XL 5T 0.6.json create mode 100644 resources/profiles/Prusa/process/0.25mm Speed @Prusa XL 5T 0.5.json create mode 100644 resources/profiles/Prusa/process/0.25mm Speed @Prusa XL 5T 0.6.json create mode 100644 resources/profiles/Prusa/process/0.25mm Structural @Prusa XL 5T 0.4.json create mode 100644 resources/profiles/Prusa/process/0.25mm Structural @Prusa XL 5T 0.5.json create mode 100644 resources/profiles/Prusa/process/0.25mm Structural @Prusa XL 5T 0.6.json create mode 100644 resources/profiles/Prusa/process/0.30mm Detail @Prusa XL 5T 0.8.json create mode 100644 resources/profiles/Prusa/process/0.32mm Speed @Prusa XL 5T 0.6.json create mode 100644 resources/profiles/Prusa/process/0.32mm Structural @Prusa XL 5T 0.6.json create mode 100644 resources/profiles/Prusa/process/0.40mm Quality @Prusa XL 5T 0.8.json create mode 100644 resources/profiles/Prusa/process/0.55mm Draft @Prusa XL 5T 0.8.json create mode 100644 resources/profiles/Prusa/process/process_common_xl_5t.json diff --git a/resources/profiles/Prusa.json b/resources/profiles/Prusa.json index 1845bd173b..69e3e32e4e 100644 --- a/resources/profiles/Prusa.json +++ b/resources/profiles/Prusa.json @@ -1,6 +1,6 @@ { "name": "Prusa", - "version": "02.01.01.00", + "version": "02.01.01.10", "force_update": "0", "description": "Prusa configurations", "machine_model_list": [ @@ -23,6 +23,10 @@ { "name": "Prusa XL", "sub_path": "machine/Prusa XL.json" + }, + { + "name": "Prusa XL 5T", + "sub_path": "machine/Prusa XL 5T.json" } ], "process_list": [ @@ -54,6 +58,10 @@ "name": "process_common_xl", "sub_path": "process/process_common_xl.json" }, + { + "name": "process_common_xl_5t", + "sub_path": "process/process_common_xl_5t.json" + }, { "name": "0.20mm Standard @MINI 0.25", "sub_path": "process/0.20mm Standard @MINI 0.25.json" @@ -389,6 +397,134 @@ { "name": "0.30mm Detail @Prusa XL 0.8", "sub_path": "process/0.30mm Detail @Prusa XL 0.8.json" + }, + { + "name": "0.15mm Structural @Prusa XL 5T 0.25", + "sub_path": "process/0.15mm Structural @Prusa XL 5T 0.25.json" + }, + { + "name": "0.15mm Speed @Prusa XL 5T 0.25", + "sub_path": "process/0.15mm Speed @Prusa XL 5T 0.25.json" + }, + { + "name": "0.12mm Structural @Prusa XL 5T 0.25", + "sub_path": "process/0.12mm Structural @Prusa XL 5T 0.25.json" + }, + { + "name": "0.12mm Speed @Prusa XL 5T 0.25", + "sub_path": "process/0.12mm Speed @Prusa XL 5T 0.25.json" + }, + { + "name": "0.07mm Detail @Prusa XL 5T 0.25", + "sub_path": "process/0.07mm Detail @Prusa XL 5T 0.25.json" + }, + { + "name": "0.05mm Detail @Prusa XL 5T 0.25", + "sub_path": "process/0.05mm Detail @Prusa XL 5T 0.25.json" + }, + { + "name": "0.20mm Speed @Prusa XL 5T 0.3", + "sub_path": "process/0.20mm Speed @Prusa XL 5T 0.3.json" + }, + { + "name": "0.16mm Structural @Prusa XL 5T 0.3", + "sub_path": "process/0.16mm Structural @Prusa XL 5T 0.3.json" + }, + { + "name": "0.16mm Speed @Prusa XL 5T 0.3", + "sub_path": "process/0.16mm Speed @Prusa XL 5T 0.3.json" + }, + { + "name": "0.12mm Structural @Prusa XL 5T 0.3", + "sub_path": "process/0.12mm Structural @Prusa XL 5T 0.3.json" + }, + { + "name": "0.25mm Structural @Prusa XL 5T 0.4", + "sub_path": "process/0.25mm Structural @Prusa XL 5T 0.4.json" + }, + { + "name": "0.20mm Structural @Prusa XL 5T 0.4", + "sub_path": "process/0.20mm Structural @Prusa XL 5T 0.4.json" + }, + { + "name": "0.20mm Speed @Prusa XL 5T 0.4", + "sub_path": "process/0.20mm Speed @Prusa XL 5T 0.4.json" + }, + { + "name": "0.15mm Structural @Prusa XL 5T 0.4", + "sub_path": "process/0.15mm Structural @Prusa XL 5T 0.4.json" + }, + { + "name": "0.15mm Speed @Prusa XL 5T 0.4", + "sub_path": "process/0.15mm Speed @Prusa XL 5T 0.4.json" + }, + { + "name": "0.10mm FastDetail @Prusa XL 5T 0.4", + "sub_path": "process/0.10mm FastDetail @Prusa XL 5T 0.4.json" + }, + { + "name": "0.25mm Structural @Prusa XL 5T 0.5", + "sub_path": "process/0.25mm Structural @Prusa XL 5T 0.5.json" + }, + { + "name": "0.25mm Speed @Prusa XL 5T 0.5", + "sub_path": "process/0.25mm Speed @Prusa XL 5T 0.5.json" + }, + { + "name": "0.20mm Structural @Prusa XL 5T 0.5", + "sub_path": "process/0.20mm Structural @Prusa XL 5T 0.5.json" + }, + { + "name": "0.20mm Speed @Prusa XL 5T 0.5", + "sub_path": "process/0.20mm Speed @Prusa XL 5T 0.5.json" + }, + { + "name": "0.15mm Structural @Prusa XL 5T 0.5", + "sub_path": "process/0.15mm Structural @Prusa XL 5T 0.5.json" + }, + { + "name": "0.10mm Structural @Prusa XL 5T 0.5", + "sub_path": "process/0.10mm Structural @Prusa XL 5T 0.5.json" + }, + { + "name": "0.32mm Structural @Prusa XL 5T 0.6", + "sub_path": "process/0.32mm Structural @Prusa XL 5T 0.6.json" + }, + { + "name": "0.32mm Speed @Prusa XL 5T 0.6", + "sub_path": "process/0.32mm Speed @Prusa XL 5T 0.6.json" + }, + { + "name": "0.25mm Structural @Prusa XL 5T 0.6", + "sub_path": "process/0.25mm Structural @Prusa XL 5T 0.6.json" + }, + { + "name": "0.25mm Speed @Prusa XL 5T 0.6", + "sub_path": "process/0.25mm Speed @Prusa XL 5T 0.6.json" + }, + { + "name": "0.20mm Structural @Prusa XL 5T 0.6", + "sub_path": "process/0.20mm Structural @Prusa XL 5T 0.6.json" + }, + { + "name": "0.20mm Speed @Prusa XL 5T 0.6", + "sub_path": "process/0.20mm Speed @Prusa XL 5T 0.6.json" + }, + { + "name": "0.15mm Structural @Prusa XL 5T 0.6", + "sub_path": "process/0.15mm Structural @Prusa XL 5T 0.6.json" + }, + { + "name": "0.55mm Draft @Prusa XL 5T 0.8", + "sub_path": "process/0.55mm Draft @Prusa XL 5T 0.8.json" + }, + { + "name": "0.40mm Quality @Prusa XL 5T 0.8", + "sub_path": "process/0.40mm Quality @Prusa XL 5T 0.8.json" + }, + { + "name": "0.30mm Detail @Prusa XL 5T 0.8", + "sub_path": "process/0.30mm Detail @Prusa XL 5T 0.8.json" } ], "filament_list": [ @@ -464,18 +600,6 @@ "name": "Prusa Generic PLA @MINIIS", "sub_path": "filament/Prusa Generic PLA @MINIIS.json" }, - { - "name": "Prusa Generic PLA @XL", - "sub_path": "filament/Prusa Generic PLA @XL.json" - }, - { - "name": "Prusament PLA @XL", - "sub_path": "filament/Prusament PLA @XL.json" - }, - { - "name": "Prusament rPLA @XL", - "sub_path": "filament/Prusament rPLA @XL.json" - }, { "name": "Prusa Generic PLA-CF", "sub_path": "filament/Prusa Generic PLA-CF.json" @@ -520,14 +644,6 @@ "name": "Prusa Generic PETG @MINIIS 0.8", "sub_path": "filament/Prusa Generic PETG @MINIIS 0.8.json" }, - { - "name": "Prusa Generic PETG @XL", - "sub_path": "filament/Prusa Generic PETG @XL.json" - }, - { - "name": "Prusament PETG @XL", - "sub_path": "filament/Prusament PETG @XL.json" - }, { "name": "Prusa Generic ABS", "sub_path": "filament/Prusa Generic ABS.json" @@ -552,10 +668,6 @@ "name": "Prusa Generic ABS @MINIIS 0.8", "sub_path": "filament/Prusa Generic ABS @MINIIS 0.8.json" }, - { - "name": "Prusa Generic ABS @XL", - "sub_path": "filament/Prusa Generic ABS @XL.json" - }, { "name": "Prusa Generic TPU", "sub_path": "filament/Prusa Generic TPU.json" @@ -592,10 +704,6 @@ "name": "Prusa Generic ASA @MINIIS 0.8", "sub_path": "filament/Prusa Generic ASA @MINIIS 0.8.json" }, - { - "name": "Prusament ASA @XL", - "sub_path": "filament/Prusament ASA @XL.json" - }, { "name": "Prusa Generic PC", "sub_path": "filament/Prusa Generic PC.json" @@ -616,14 +724,6 @@ "name": "Prusa Generic PC @MINIIS 0.8", "sub_path": "filament/Prusa Generic PC @MINIIS 0.8.json" }, - { - "name": "Prusament PC Blend @XL", - "sub_path": "filament/Prusament PC Blend @XL.json" - }, - { - "name": "Prusament PC-CF @XL", - "sub_path": "filament/Prusament PC-CF @XL.json" - }, { "name": "Prusa Generic PVA", "sub_path": "filament/Prusa Generic PVA.json" @@ -644,10 +744,6 @@ "name": "Prusa Generic PVA @MINIIS 0.8", "sub_path": "filament/Prusa Generic PVA @MINIIS 0.8.json" }, - { - "name": "Prusament PVB @XL", - "sub_path": "filament/Prusament PVB @XL.json" - }, { "name": "Prusa Generic PA", "sub_path": "filament/Prusa Generic PA.json" @@ -688,15 +784,107 @@ "name": "Prusa Generic PA-CF @MINIIS 0.8", "sub_path": "filament/Prusa Generic PA-CF @MINIIS 0.8.json" }, + { + "name": "Prusa Generic PLA @XL", + "sub_path": "filament/Prusa Generic PLA @XL.json" + }, + { + "name": "Prusament PLA @XL", + "sub_path": "filament/Prusament PLA @XL.json" + }, + { + "name": "Prusament rPLA @XL", + "sub_path": "filament/Prusament rPLA @XL.json" + }, + { + "name": "Prusament PVB @XL", + "sub_path": "filament/Prusament PVB @XL.json" + }, + { + "name": "Prusament ASA @XL", + "sub_path": "filament/Prusament ASA @XL.json" + }, + { + "name": "Prusa Generic PETG @XL", + "sub_path": "filament/Prusa Generic PETG @XL.json" + }, + { + "name": "Prusament PETG @XL", + "sub_path": "filament/Prusament PETG @XL.json" + }, + { + "name": "Prusa Generic ABS @XL", + "sub_path": "filament/Prusa Generic ABS @XL.json" + }, + { + "name": "Prusament PC Blend @XL", + "sub_path": "filament/Prusament PC Blend @XL.json" + }, + { + "name": "Prusament PC-CF @XL", + "sub_path": "filament/Prusament PC-CF @XL.json" + }, { "name": "Prusament PA-CF @XL", "sub_path": "filament/Prusament PA-CF @XL.json" + }, + { + "name": "Prusa Generic PLA @XL 5T", + "sub_path": "filament/Prusa Generic PLA @XL 5T.json" + }, + { + "name": "Prusament PLA @XL 5T", + "sub_path": "filament/Prusament PLA @XL 5T.json" + }, + { + "name": "Prusament rPLA @XL 5T", + "sub_path": "filament/Prusament rPLA @XL 5T.json" + }, + { + "name": "Prusament PVB @XL 5T", + "sub_path": "filament/Prusament PVB @XL 5T.json" + }, + { + "name": "Prusament ASA @XL 5T", + "sub_path": "filament/Prusament ASA @XL 5T.json" + }, + { + "name": "Prusa Generic PETG @XL 5T", + "sub_path": "filament/Prusa Generic PETG @XL 5T.json" + }, + { + "name": "Prusament PETG @XL 5T", + "sub_path": "filament/Prusament PETG @XL 5T.json" + }, + { + "name": "Prusa Generic ABS @XL 5T", + "sub_path": "filament/Prusa Generic ABS @XL 5T.json" + }, + { + "name": "Prusament PC Blend @XL 5T", + "sub_path": "filament/Prusament PC Blend @XL 5T.json" + }, + { + "name": "Prusament PC-CF @XL 5T", + "sub_path": "filament/Prusament PC-CF @XL 5T.json" + }, + { + "name": "Prusament PA-CF @XL 5T", + "sub_path": "filament/Prusament PA-CF @XL 5T.json" } ], "machine_list": [ { "name": "fdm_machine_common", "sub_path": "machine/fdm_machine_common.json" + }, + { + "name": "fdm_machine_common_xl", + "sub_path": "machine/fdm_machine_common_xl.json" + }, + { + "name": "fdm_machine_common_xl_5t", + "sub_path": "machine/fdm_machine_common_xl_5t.json" }, { "name": "Prusa MK3S 0.25 nozzle", @@ -785,6 +973,30 @@ { "name": "Prusa XL 0.8 nozzle", "sub_path": "machine/Prusa XL 0.8 nozzle.json" + }, + { + "name": "Prusa XL 5T 0.25 nozzle", + "sub_path": "machine/Prusa XL 5T 0.25 nozzle.json" + }, + { + "name": "Prusa XL 5T 0.3 nozzle", + "sub_path": "machine/Prusa XL 5T 0.3 nozzle.json" + }, + { + "name": "Prusa XL 5T 0.4 nozzle", + "sub_path": "machine/Prusa XL 5T 0.4 nozzle.json" + }, + { + "name": "Prusa XL 5T 0.5 nozzle", + "sub_path": "machine/Prusa XL 5T 0.5 nozzle.json" + }, + { + "name": "Prusa XL 5T 0.6 nozzle", + "sub_path": "machine/Prusa XL 5T 0.6 nozzle.json" + }, + { + "name": "Prusa XL 5T 0.8 nozzle", + "sub_path": "machine/Prusa XL 5T 0.8 nozzle.json" } ] } diff --git a/resources/profiles/Prusa/filament/Prusa Generic ABS @XL 5T.json b/resources/profiles/Prusa/filament/Prusa Generic ABS @XL 5T.json new file mode 100644 index 0000000000..a299264967 --- /dev/null +++ b/resources/profiles/Prusa/filament/Prusa Generic ABS @XL 5T.json @@ -0,0 +1,69 @@ +{ + "type": "filament", + "filament_id": "GFB99_1", + "setting_id": "GFSA04", + "name": "Prusa Generic ABS @XL 5T", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_abs", + "nozzle_temperature_intial_layer": "255", + "nozzle_temperature": "255", + "hot_plate_temp_initial_layer": "100", + "hot_plate_temp": "105", + "slow_down_min_speed": "15", + "filament_flow_ratio": [ + "1" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "slow_down_layer_time": [ + "20" + ], + "fan_max_speed": [ + "15" + ], + "fan_min_speed": [ + "15" + ], + "overhang_fan_speed": [ + "25" + ], + "close_fan_the_first_x_layers": [ + "4" + ], + "filament_loading_speed_start": "19", + "filament_loading_speed": "14", + "filament_unloading_speed_start": "100", + "filament_unloading_speed": "20", + "filament_load_time": "15", + "filament_unload_time": "12", + "filament_cooling_moves": "5", + "filament_cooling_initial_speed": "10", + "filament_cooling_final_speed": "50", + "filament_retract_lift_below": "1.5", + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.04{elsif nozzle_diameter[0]==0.25}0.1{elsif nozzle_diameter[0]==0.3}0.06{elsif nozzle_diameter[0]==0.35}0.05{elsif nozzle_diameter[0]==0.5}0.03{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.02{elsif nozzle_diameter[0]==0.5}0.018{elsif nozzle_diameter[0]==0.6}0.012{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.25}0.09{elsif nozzle_diameter[0]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp", + "compatible_printers": [ + "Prusa XL 5T 0.25 nozzle", + "Prusa XL 5T 0.3 nozzle", + "Prusa XL 5T 0.4 nozzle", + "Prusa XL 5T 0.5 nozzle", + "Prusa XL 5T 0.6 nozzle", + "Prusa XL 5T 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/filament/Prusa Generic PETG @XL 5T.json b/resources/profiles/Prusa/filament/Prusa Generic PETG @XL 5T.json new file mode 100644 index 0000000000..5f26694dc5 --- /dev/null +++ b/resources/profiles/Prusa/filament/Prusa Generic PETG @XL 5T.json @@ -0,0 +1,72 @@ +{ + "type": "filament", + "filament_id": "GFL99_1", + "setting_id": "GFSA04", + "name": "Prusa Generic PETG @XL 5T", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pet", + "nozzle_temperature_intial_layer": "230", + "nozzle_temperature": "240", + "hot_plate_temp_initial_layer": "80", + "hot_plate_temp": "80", + "full_fan_speed_layer": "5", + "slow_down_min_speed": "15", + "filament_flow_ratio": [ + "1" + ], + "filament_max_volumetric_speed": [ + "9" + ], + "slow_down_layer_time": [ + "9" + ], + "fan_max_speed": [ + "50" + ], + "fan_min_speed": [ + "30" + ], + "overhang_fan_speed": [ + "50" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "filament_loading_speed_start": "50", + "filament_loading_speed": "10", + "filament_unloading_speed_start": "100", + "filament_unloading_speed": "100", + "filament_load_time": "10.5", + "filament_unload_time": "8.5", + "filament_cooling_moves": "3", + "filament_cooling_initial_speed": "5", + "filament_cooling_final_speed": "2.5", + "filament_retract_lift_below": "1.5", + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_wipe": "1", + "filament_retract_before_wipe": "20%", + "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.053{elsif nozzle_diameter[0]==0.5}0.042{elsif nozzle_diameter[0]==0.6}0.032{elsif nozzle_diameter[0]==0.8}0.018{elsif nozzle_diameter[0]==0.25}0.18{elsif nozzle_diameter[0]==0.3}0.1{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp", + "compatible_printers": [ + "Prusa XL 5T 0.25 nozzle", + "Prusa XL 5T 0.3 nozzle", + "Prusa XL 5T 0.4 nozzle", + "Prusa XL 5T 0.5 nozzle", + "Prusa XL 5T 0.6 nozzle", + "Prusa XL 5T 0.8 nozzle" + ] +} diff --git a/resources/profiles/Prusa/filament/Prusa Generic PLA @XL 5T.json b/resources/profiles/Prusa/filament/Prusa Generic PLA @XL 5T.json new file mode 100644 index 0000000000..ff37c0b691 --- /dev/null +++ b/resources/profiles/Prusa/filament/Prusa Generic PLA @XL 5T.json @@ -0,0 +1,67 @@ +{ + "type": "filament", + "filament_id": "GFL99_1", + "setting_id": "GFSA04", + "name": "Prusa Generic PLA @XL 5T", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pla", + "nozzle_temperature_intial_layer": "215", + "nozzle_temperature": "210", + "hot_plate_temp_initial_layer": "60", + "hot_plate_temp": "60", + "full_fan_speed_layer": "3", + "slow_down_min_speed": "15", + "filament_flow_ratio": [ + "1" + ], + "filament_max_volumetric_speed": [ + "15" + ], + "slow_down_layer_time": [ + "10" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "overhang_fan_speed": [ + "100" + ], + "filament_loading_speed_start": "50", + "filament_loading_speed": "10", + "filament_unloading_speed_start": "100", + "filament_unloading_speed": "100", + "filament_load_time": "10.5", + "filament_unload_time": "8.5", + "filament_cooling_moves": "2", + "filament_cooling_initial_speed": "10", + "filament_cooling_final_speed": "3.5", + "filament_retract_lift_below": "0.6", + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.036{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp", + "compatible_printers": [ + "Prusa XL 5T 0.25 nozzle", + "Prusa XL 5T 0.3 nozzle", + "Prusa XL 5T 0.4 nozzle", + "Prusa XL 5T 0.5 nozzle", + "Prusa XL 5T 0.6 nozzle", + "Prusa XL 5T 0.8 nozzle" + ] +} diff --git a/resources/profiles/Prusa/filament/Prusament ASA @XL 5T.json b/resources/profiles/Prusa/filament/Prusament ASA @XL 5T.json new file mode 100644 index 0000000000..2ec8efea09 --- /dev/null +++ b/resources/profiles/Prusa/filament/Prusament ASA @XL 5T.json @@ -0,0 +1,71 @@ +{ + "type": "filament", + "filament_id": "GFB98", + "setting_id": "GFSA04", + "name": "Prusament ASA @XL 5T", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_asa", + "nozzle_temperature_intial_layer": "260", + "nozzle_temperature": "260", + "hot_plate_temp_initial_layer": "100", + "hot_plate_temp": "105", + "filament_flow_ratio": [ + "1" + ], + "fan_max_speed": [ + "10" + ], + "fan_min_speed": [ + "10" + ], + "overhang_fan_speed": [ + "30" + ], + "close_fan_the_first_x_layers": [ + "4" + ], + "slow_down_min_speed": [ + "15" + ], + "slow_down_layer_time": [ + "15" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "filament_loading_speed_start": "19", + "filament_loading_speed": "14", + "filament_unloading_speed_start": "100", + "filament_unloading_speed": "20", + "filament_load_time": "15", + "filament_unload_time": "12", + "filament_cooling_moves": "5", + "filament_cooling_initial_speed": "10", + "filament_cooling_final_speed": "50", + "filament_retract_lift_below": "1.5", + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.04{elsif nozzle_diameter[0]==0.25}0.1{elsif nozzle_diameter[0]==0.3}0.06{elsif nozzle_diameter[0]==0.35}0.05{elsif nozzle_diameter[0]==0.5}0.03{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.02{elsif nozzle_diameter[0]==0.5}0.018{elsif nozzle_diameter[0]==0.6}0.012{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.25}0.09{elsif nozzle_diameter[0]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp", + "compatible_printers": [ + "Prusa XL 5T 0.25 nozzle", + "Prusa XL 5T 0.3 nozzle", + "Prusa XL 5T 0.4 nozzle", + "Prusa XL 5T 0.5 nozzle", + "Prusa XL 5T 0.6 nozzle", + "Prusa XL 5T 0.8 nozzle" + ] +} diff --git a/resources/profiles/Prusa/filament/Prusament PA-CF @XL 5T.json b/resources/profiles/Prusa/filament/Prusament PA-CF @XL 5T.json new file mode 100644 index 0000000000..ffd0f3cfe3 --- /dev/null +++ b/resources/profiles/Prusa/filament/Prusament PA-CF @XL 5T.json @@ -0,0 +1,71 @@ +{ + "type": "filament", + "filament_id": "GFN98", + "setting_id": "GFSA04", + "name": "Prusament PA-CF @XL 5T", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pa11cf", + "nozzle_temperature_intial_layer": "275", + "nozzle_temperature": "285", + "hot_plate_temp_initial_layer": "100", + "hot_plate_temp": "105", + "filament_flow_ratio": [ + "1.05" + ], + "fan_max_speed": [ + "20" + ], + "fan_min_speed": [ + "20" + ], + "overhang_fan_speed": [ + "30" + ], + "close_fan_the_first_x_layers": [ + "4" + ], + "slow_down_min_speed": [ + "15" + ], + "slow_down_layer_time": [ + "20" + ], + "filament_max_volumetric_speed": [ + "6.5" + ], + "filament_loading_speed_start": "19", + "filament_loading_speed": "14", + "filament_unloading_speed_start": "100", + "filament_unloading_speed": "20", + "filament_load_time": "15", + "filament_unload_time": "12", + "filament_cooling_moves": "5", + "filament_cooling_initial_speed": "10", + "filament_cooling_final_speed": "50", + "filament_retract_lift_below": "1.5", + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.6}0.025{elsif nozzle_diameter[0]==0.8}0.016{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp", + "compatible_printers": [ + "Prusa XL 5T 0.25 nozzle", + "Prusa XL 5T 0.3 nozzle", + "Prusa XL 5T 0.4 nozzle", + "Prusa XL 5T 0.5 nozzle", + "Prusa XL 5T 0.6 nozzle", + "Prusa XL 5T 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/filament/Prusament PC Blend @XL 5T.json b/resources/profiles/Prusa/filament/Prusament PC Blend @XL 5T.json new file mode 100644 index 0000000000..0b3077d471 --- /dev/null +++ b/resources/profiles/Prusa/filament/Prusament PC Blend @XL 5T.json @@ -0,0 +1,71 @@ +{ + "type": "filament", + "filament_id": "GFL99_1", + "setting_id": "GFSA04", + "name": "Prusament PC Blend @XL 5T", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pc", + "nozzle_temperature_intial_layer": "275", + "nozzle_temperature": "275", + "hot_plate_temp_initial_layer": "100", + "hot_plate_temp": "105", + "filament_flow_ratio": [ + "1" + ], + "fan_max_speed": [ + "10" + ], + "fan_min_speed": [ + "10" + ], + "overhang_fan_speed": [ + "30" + ], + "close_fan_the_first_x_layers": [ + "4" + ], + "slow_down_min_speed": [ + "15" + ], + "slow_down_layer_time": [ + "20" + ], + "filament_max_volumetric_speed": [ + "9" + ], + "filament_loading_speed_start": "19", + "filament_loading_speed": "14", + "filament_unloading_speed_start": "100", + "filament_unloading_speed": "20", + "filament_load_time": "15", + "filament_unload_time": "12", + "filament_cooling_moves": "5", + "filament_cooling_initial_speed": "10", + "filament_cooling_final_speed": "50", + "filament_retract_lift_below": "1.5", + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.6}0.025{elsif nozzle_diameter[0]==0.8}0.016{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp", + "compatible_printers": [ + "Prusa XL 5T 0.25 nozzle", + "Prusa XL 5T 0.3 nozzle", + "Prusa XL 5T 0.4 nozzle", + "Prusa XL 5T 0.5 nozzle", + "Prusa XL 5T 0.6 nozzle", + "Prusa XL 5T 0.8 nozzle" + ] +} diff --git a/resources/profiles/Prusa/filament/Prusament PC-CF @XL 5T.json b/resources/profiles/Prusa/filament/Prusament PC-CF @XL 5T.json new file mode 100644 index 0000000000..e82f40ba46 --- /dev/null +++ b/resources/profiles/Prusa/filament/Prusament PC-CF @XL 5T.json @@ -0,0 +1,71 @@ +{ + "type": "filament", + "filament_id": "GFL99_1", + "setting_id": "GFSA04", + "name": "Prusament PC-CF @XL 5T", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pccf", + "nozzle_temperature_intial_layer": "285", + "nozzle_temperature": "285", + "hot_plate_temp_initial_layer": "100", + "hot_plate_temp": "105", + "filament_flow_ratio": [ + "1.04" + ], + "fan_max_speed": [ + "10" + ], + "fan_min_speed": [ + "10" + ], + "overhang_fan_speed": [ + "30" + ], + "close_fan_the_first_x_layers": [ + "4" + ], + "slow_down_min_speed": [ + "15" + ], + "slow_down_layer_time": [ + "20" + ], + "filament_max_volumetric_speed": [ + "8" + ], + "filament_loading_speed_start": "19", + "filament_loading_speed": "14", + "filament_unloading_speed_start": "100", + "filament_unloading_speed": "20", + "filament_load_time": "15", + "filament_unload_time": "12", + "filament_cooling_moves": "5", + "filament_cooling_initial_speed": "10", + "filament_cooling_final_speed": "50", + "filament_retract_lift_below": "1.5", + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.6}0.025{elsif nozzle_diameter[0]==0.8}0.016{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp", + "compatible_printers": [ + "Prusa XL 5T 0.25 nozzle", + "Prusa XL 5T 0.3 nozzle", + "Prusa XL 5T 0.4 nozzle", + "Prusa XL 5T 0.5 nozzle", + "Prusa XL 5T 0.6 nozzle", + "Prusa XL 5T 0.8 nozzle" + ] +} diff --git a/resources/profiles/Prusa/filament/Prusament PETG @XL 5T.json b/resources/profiles/Prusa/filament/Prusament PETG @XL 5T.json new file mode 100644 index 0000000000..10856125da --- /dev/null +++ b/resources/profiles/Prusa/filament/Prusament PETG @XL 5T.json @@ -0,0 +1,72 @@ +{ + "type": "filament", + "filament_id": "GFL99_1", + "setting_id": "GFSA04", + "name": "Prusament PETG @XL 5T", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pet", + "nozzle_temperature_intial_layer": "240", + "nozzle_temperature": "250", + "hot_plate_temp_initial_layer": "80", + "hot_plate_temp": "80", + "full_fan_speed_layer": "5", + "slow_down_min_speed": "15", + "filament_flow_ratio": [ + "1" + ], + "filament_max_volumetric_speed": [ + "9.5" + ], + "slow_down_layer_time": [ + "9" + ], + "fan_max_speed": [ + "50" + ], + "fan_min_speed": [ + "30" + ], + "overhang_fan_speed": [ + "50" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "filament_loading_speed_start": "50", + "filament_loading_speed": "10", + "filament_unloading_speed_start": "100", + "filament_unloading_speed": "100", + "filament_load_time": "10.5", + "filament_unload_time": "8.5", + "filament_cooling_moves": "3", + "filament_cooling_initial_speed": "5", + "filament_cooling_final_speed": "2.5", + "filament_retract_lift_below": "1.5", + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_volume": [ + "10" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_wipe": "1", + "filament_retract_before_wipe": "20%", + "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.053{elsif nozzle_diameter[0]==0.5}0.042{elsif nozzle_diameter[0]==0.6}0.032{elsif nozzle_diameter[0]==0.8}0.018{elsif nozzle_diameter[0]==0.25}0.18{elsif nozzle_diameter[0]==0.3}0.1{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp", + "compatible_printers": [ + "Prusa XL 5T 0.25 nozzle", + "Prusa XL 5T 0.3 nozzle", + "Prusa XL 5T 0.4 nozzle", + "Prusa XL 5T 0.5 nozzle", + "Prusa XL 5T 0.6 nozzle", + "Prusa XL 5T 0.8 nozzle" + ] +} diff --git a/resources/profiles/Prusa/filament/Prusament PLA @XL 5T.json b/resources/profiles/Prusa/filament/Prusament PLA @XL 5T.json new file mode 100644 index 0000000000..ede4ce5755 --- /dev/null +++ b/resources/profiles/Prusa/filament/Prusament PLA @XL 5T.json @@ -0,0 +1,67 @@ +{ + "type": "filament", + "filament_id": "GFL99_1", + "setting_id": "GFSA04", + "name": "Prusament PLA @XL 5T", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pla", + "nozzle_temperature_intial_layer": "215", + "nozzle_temperature": "215", + "hot_plate_temp_initial_layer": "60", + "hot_plate_temp": "60", + "full_fan_speed_layer": "3", + "slow_down_min_speed": "15", + "filament_flow_ratio": [ + "1" + ], + "filament_max_volumetric_speed": [ + "15" + ], + "slow_down_layer_time": [ + "10" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "overhang_fan_speed": [ + "100" + ], + "filament_loading_speed_start": "50", + "filament_loading_speed": "10", + "filament_unloading_speed_start": "100", + "filament_unloading_speed": "100", + "filament_load_time": "10.5", + "filament_unload_time": "8.5", + "filament_cooling_moves": "2", + "filament_cooling_initial_speed": "10", + "filament_cooling_final_speed": "3.5", + "filament_retract_lift_below": "0.6", + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.036{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp", + "compatible_printers": [ + "Prusa XL 5T 0.25 nozzle", + "Prusa XL 5T 0.3 nozzle", + "Prusa XL 5T 0.4 nozzle", + "Prusa XL 5T 0.5 nozzle", + "Prusa XL 5T 0.6 nozzle", + "Prusa XL 5T 0.8 nozzle" + ] +} diff --git a/resources/profiles/Prusa/filament/Prusament PVB @XL 5T.json b/resources/profiles/Prusa/filament/Prusament PVB @XL 5T.json new file mode 100644 index 0000000000..f7d360fdb7 --- /dev/null +++ b/resources/profiles/Prusa/filament/Prusament PVB @XL 5T.json @@ -0,0 +1,72 @@ +{ + "type": "filament", + "filament_id": "GFS99", + "setting_id": "GFSA04", + "name": "Prusament PVB @XL 5T", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pvb", + "nozzle_temperature_intial_layer": "215", + "nozzle_temperature": "215", + "hot_plate_temp_initial_layer": "75", + "hot_plate_temp": "75", + "slow_down_min_speed": "15", + "filament_flow_ratio": [ + "1" + ], + "filament_max_volumetric_speed": [ + "8" + ], + "slow_down_layer_time": [ + "10" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "overhang_fan_speed": [ + "100" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "full_fan_speed_layer": [ + "3" + ], + "filament_loading_speed_start": "50", + "filament_loading_speed": "10", + "filament_unloading_speed_start": "100", + "filament_unloading_speed": "100", + "filament_load_time": "10.5", + "filament_unload_time": "8.5", + "filament_cooling_moves": "2", + "filament_cooling_initial_speed": "10", + "filament_cooling_final_speed": "3.5", + "filament_retract_lift_below": "0.6", + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.036{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp", + "compatible_printers": [ + "Prusa XL 5T 0.25 nozzle", + "Prusa XL 5T 0.3 nozzle", + "Prusa XL 5T 0.4 nozzle", + "Prusa XL 5T 0.5 nozzle", + "Prusa XL 5T 0.6 nozzle", + "Prusa XL 5T 0.8 nozzle" + ] +} diff --git a/resources/profiles/Prusa/filament/Prusament rPLA @XL 5T.json b/resources/profiles/Prusa/filament/Prusament rPLA @XL 5T.json new file mode 100644 index 0000000000..af36626c3f --- /dev/null +++ b/resources/profiles/Prusa/filament/Prusament rPLA @XL 5T.json @@ -0,0 +1,70 @@ +{ + "type": "filament", + "filament_id": "GFL99_1", + "setting_id": "GFSA04", + "name": "Prusament rPLA @XL 5T", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pla", + "nozzle_temperature_intial_layer": "205", + "nozzle_temperature": "205", + "hot_plate_temp_initial_layer": "60", + "hot_plate_temp": "60", + "full_fan_speed_layer": "3", + "slow_down_min_speed": "15", + "filament_flow_ratio": [ + "1" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "slow_down_layer_time": [ + "10" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "overhang_fan_speed": [ + "100" + ], + "filament_max_volumetric_speed": [ + "10" + ], + "filament_loading_speed_start": "50", + "filament_loading_speed": "10", + "filament_unloading_speed_start": "100", + "filament_unloading_speed": "100", + "filament_load_time": "10.5", + "filament_unload_time": "8.5", + "filament_cooling_moves": "2", + "filament_cooling_initial_speed": "10", + "filament_cooling_final_speed": "3.5", + "filament_retract_lift_below": "0.6", + "filament_multitool_ramming": [ + "1" + ], + "filament_multitool_ramming_volume": [ + "5" + ], + "filament_multitool_ramming_flow": [ + "40" + ], + "filament_stamping_distance": [ + "45" + ], + "filament_stamping_loading_speed": [ + "29" + ], + "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.036{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp", + "compatible_printers": [ + "Prusa XL 5T 0.25 nozzle", + "Prusa XL 5T 0.3 nozzle", + "Prusa XL 5T 0.4 nozzle", + "Prusa XL 5T 0.5 nozzle", + "Prusa XL 5T 0.6 nozzle", + "Prusa XL 5T 0.8 nozzle" + ] +} diff --git a/resources/profiles/Prusa/machine/Prusa XL 5T 0.25 nozzle.json b/resources/profiles/Prusa/machine/Prusa XL 5T 0.25 nozzle.json new file mode 100644 index 0000000000..52343e9ed1 --- /dev/null +++ b/resources/profiles/Prusa/machine/Prusa XL 5T 0.25 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "machine", + "setting_id": "GM003", + "name": "Prusa XL 5T 0.25 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_machine_common_xl_5t", + "gcode_flavor": "marlin2", + "printer_model": "Prusa XL 5T", + "default_filament_profile": "Prusa Generic PLA @XL 5T", + "default_print_profile": "0.15mm Speed @Prusa XL 5T 0.25", + "printer_variant": "0.25", + "nozzle_diameter": [ + "0.25", + "0.25", + "0.25", + "0.25", + "0.25" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/machine/Prusa XL 5T 0.3 nozzle.json b/resources/profiles/Prusa/machine/Prusa XL 5T 0.3 nozzle.json new file mode 100644 index 0000000000..3dc0db1532 --- /dev/null +++ b/resources/profiles/Prusa/machine/Prusa XL 5T 0.3 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "machine", + "setting_id": "GM003", + "name": "Prusa XL 5T 0.3 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_machine_common_xl_5t", + "gcode_flavor": "marlin2", + "printer_model": "Prusa XL 5T", + "default_filament_profile": "Prusa Generic PLA @XL 5T", + "default_print_profile": "0.20mm Speed @Prusa XL 5T 0.3", + "printer_variant": "0.3", + "nozzle_diameter": [ + "0.3", + "0.3", + "0.3", + "0.3", + "0.3" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/machine/Prusa XL 5T 0.4 nozzle.json b/resources/profiles/Prusa/machine/Prusa XL 5T 0.4 nozzle.json new file mode 100644 index 0000000000..5e7f21ed7e --- /dev/null +++ b/resources/profiles/Prusa/machine/Prusa XL 5T 0.4 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "machine", + "setting_id": "GM003", + "name": "Prusa XL 5T 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_machine_common_xl_5t", + "gcode_flavor": "marlin2", + "printer_model": "Prusa XL 5T", + "default_filament_profile": "Prusa Generic PLA @XL 5T", + "default_print_profile": "0.20mm Speed @Prusa XL 5T 0.4", + "printer_variant": "0.4", + "nozzle_diameter": [ + "0.4", + "0.4", + "0.4", + "0.4", + "0.4" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/machine/Prusa XL 5T 0.5 nozzle.json b/resources/profiles/Prusa/machine/Prusa XL 5T 0.5 nozzle.json new file mode 100644 index 0000000000..9360cfcd8f --- /dev/null +++ b/resources/profiles/Prusa/machine/Prusa XL 5T 0.5 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "machine", + "setting_id": "GM003", + "name": "Prusa XL 5T 0.5 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_machine_common_xl_5t", + "gcode_flavor": "marlin2", + "printer_model": "Prusa XL 5T", + "default_filament_profile": "Prusa Generic PLA @XL 5T", + "default_print_profile": "0.25mm Speed @Prusa XL 5T 0.5", + "printer_variant": "0.5", + "nozzle_diameter": [ + "0.5", + "0.5", + "0.5", + "0.5", + "0.5" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/machine/Prusa XL 5T 0.6 nozzle.json b/resources/profiles/Prusa/machine/Prusa XL 5T 0.6 nozzle.json new file mode 100644 index 0000000000..bc63b52a5e --- /dev/null +++ b/resources/profiles/Prusa/machine/Prusa XL 5T 0.6 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "machine", + "setting_id": "GM003", + "name": "Prusa XL 5T 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_machine_common_xl_5t", + "gcode_flavor": "marlin2", + "printer_model": "Prusa XL 5T", + "default_filament_profile": "Prusa Generic PLA @XL 5T", + "default_print_profile": "0.32mm Speed @Prusa XL 5T 0.6", + "printer_variant": "0.6", + "nozzle_diameter": [ + "0.6", + "0.6", + "0.6", + "0.6", + "0.6" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/machine/Prusa XL 5T 0.8 nozzle.json b/resources/profiles/Prusa/machine/Prusa XL 5T 0.8 nozzle.json new file mode 100644 index 0000000000..1928a6c73e --- /dev/null +++ b/resources/profiles/Prusa/machine/Prusa XL 5T 0.8 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "machine", + "setting_id": "GM003", + "name": "Prusa XL 5T 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_machine_common_xl_5t", + "gcode_flavor": "marlin2", + "printer_model": "Prusa XL 5T", + "default_filament_profile": "Prusa Generic PLA @XL 5T", + "default_print_profile": "0.40mm Quality @Prusa XL 5T 0.8", + "printer_variant": "0.8", + "nozzle_diameter": [ + "0.8", + "0.8", + "0.8", + "0.8", + "0.8" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/machine/Prusa XL 5T.json b/resources/profiles/Prusa/machine/Prusa XL 5T.json new file mode 100644 index 0000000000..ed1084e3ba --- /dev/null +++ b/resources/profiles/Prusa/machine/Prusa XL 5T.json @@ -0,0 +1,12 @@ +{ + "type": "machine_model", + "name": "Prusa XL 5T", + "model_id": "Prusa XL 5T", + "nozzle_diameter": "0.25;0.3;0.4;0.5;0.6;0.8", + "machine_tech": "FFF", + "family": "Prusa", + "bed_model": "Prusa XL_bed.stl", + "bed_texture": "Prusa XL 5T.svg", + "hotend_model": "", + "default_materials": "Prusa Generic PLA @XL 5T;Prusament PLA @XL 5T;Prusament rPLA @XL 5T;Prusa Generic PETG @XL 5T;Prusament PETG @XL 5T;Prusa Generic ABS @XL 5T;Prusament ASA @XL 5T;Prusament PC Blend @XL 5T;Prusament PC-CF @XL 5T;Prusament PVB @XL 5T;Prusament PA-CF @XL 5T" +} diff --git a/resources/profiles/Prusa/machine/fdm_machine_common_xl.json b/resources/profiles/Prusa/machine/fdm_machine_common_xl.json new file mode 100644 index 0000000000..7c917d151a --- /dev/null +++ b/resources/profiles/Prusa/machine/fdm_machine_common_xl.json @@ -0,0 +1,114 @@ +{ + "type": "machine", + "name": "fdm_machine_common_xl", + "from": "system", + "inherits": "fdm_machine_common", + "instantiation": "false", + "gcode_flavor": "marlin2", + "extruder_clearance_radius": "67", + "extruder_clearance_height_to_rod": "21", + "extruder_clearance_height_to_lid": "21", + "printer_variant": "0.4", + "nozzle_diameter": [ + "0.4" + ], + "max_layer_height": "0.3", + "min_layer_height": "0.07", + "bed_exclude_area": [ + "0x0" + ], + "printable_area": [ + "0x0", + "360x0", + "360x360", + "0x360" + ], + "machine_max_acceleration_e": [ + "2500", + "2500" + ], + "machine_max_acceleration_extruding": [ + "4000", + "4000" + ], + "machine_max_acceleration_retracting": [ + "1200", + "1200" + ], + "machine_max_acceleration_x": [ + "7000", + "7000" + ], + "machine_max_acceleration_y": [ + "7000", + "7000" + ], + "machine_max_acceleration_z": [ + "200", + "200" + ], + "machine_max_acceleration_travel": [ + "5000", + "5000" + ], + "machine_max_speed_e": [ + "100", + "100" + ], + "machine_max_speed_x": [ + "400", + "400" + ], + "machine_max_speed_y": [ + "400", + "400" + ], + "machine_max_speed_z": [ + "12", + "12" + ], + "machine_max_jerk_e": [ + "10", + "10" + ], + "machine_max_jerk_x": [ + "8", + "8" + ], + "machine_max_jerk_y": [ + "8", + "8" + ], + "machine_max_jerk_z": [ + "2", + "2" + ], + "retraction_length": "0.8", + "retraction_speed": "35", + "detraction_speed": "25", + "retraction_minimum_travel": "1.5", + "retract_when_changing_layer": "1", + "wipe": "1", + "retract_before_wipe": "80%", + "retract_lift_below": "1.5", + "z_hop_types": "Auto Lift", + "host_type": "prusalink", + "printable_height": "360", + "machine_end_gcode": "{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F720{endif} ; Move bed down\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X6 Y350 F6000 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+100, max_print_height)} F300{endif} ; Move bed down\nM900 K0 ; reset LA\nM142 S36 ; reset heatbreak target temp\nM221 S100 ; reset flow percentage\nM84 ; disable motors\n; max_layer_z = [max_layer_z]", + "machine_pause_gcode": "M601", + "machine_start_gcode": "M17 ; enable steppers\nM862.3 P \"XL\" ; printer model check\nM115 U6.0.1+14848\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\n; set print area\nM555 X{first_layer_print_min[0]} Y{first_layer_print_min[1]} W{(first_layer_print_max[0]) - (first_layer_print_min[0])} H{(first_layer_print_max[1]) - (first_layer_print_min[1])}\n; inform about nozzle diameter\nM862.1 P[nozzle_diameter]\n; set & wait for bed and extruder temp for MBL\nM140 S[first_layer_bed_temperature] ; set bed temp\nM104 T0 S{((filament_notes[0]=~/.*HT_MBL10.*/) ? (first_layer_temperature[0] - 10) : (filament_type[0] == \"PC\" or filament_type[0] == \"PA\") ? (first_layer_temperature[0] - 25) : (filament_type[0] == \"FLEX\") ? 210 : (filament_type[0]=~/.*PET.*/) ? 175 : 170)} ; set extruder temp for bed leveling\nM109 T0 R{((filament_notes[0]=~/.*HT_MBL10.*/) ? (first_layer_temperature[0] - 10) : (filament_type[0] == \"PC\" or filament_type[0] == \"PA\") ? (first_layer_temperature[0] - 25) : (filament_type[0] == \"FLEX\") ? 210 : (filament_type[0]=~/.*PET.*/) ? 175 : 170)} ; wait for temp\n; home carriage, pick tool, home all\nG28 XY\nM84 E ; turn off E motor\nG28 Z\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nG29 G ; absorb heat\n; move to the nozzle cleanup area\nG1 X{(min(((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32))), first_layer_print_min[0])) + 32} Y{(min((first_layer_print_min[1] - 7), first_layer_print_min[1]))} Z{5} F4800\nM302 S160 ; lower cold extrusion limit to 160C\nG1 E{-(filament_type[0] == \"FLEX\" ? 4 : 2)} F2400 ; retraction for nozzle cleanup\n; nozzle cleanup\nM84 E ; turn off E motor\nG29 P9 X{((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)))} Y{(first_layer_print_min[1] - 7)} W{32} H{7}\nG0 Z10 F480 ; move away in Z\n{if first_layer_bed_temperature[0] > 60}\nG0 Z70 F480 ; move away (a bit more) in Z\nG0 X30 Y{print_bed_min[1]} F6000 ; move away in X/Y for higher bed temperatures\n{endif}\nM106 S100 ; cool off the nozzle\nM107 ; stop cooling off the nozzle - turn off the fan\n; MBL\nM84 E ; turn off E motor\nG29 P1 ; invalidate mbl & probe print area\nG29 P1 X30 Y0 W50 H20 C ; probe near purge place\nG29 P3.2 ; interpolate mbl probes\nG29 P3.13 ; extrapolate mbl outside probe area\nG29 A ; activate mbl\nM104 S[first_layer_temperature] ; set extruder temp\nG1 Z10 F720 ; move away in Z\nG0 X30 Y-8 F6000 ; move next to the sheet\n; wait for extruder temp\nM109 T0 S{first_layer_temperature[0]}\n;\n; purge\n;\nG92 E0 ; reset extruder position\nG0 X{(0 == 0 ? 30 : (0 == 1 ? 150 : (0 == 2 ? 210 : 330)))} Y{(0 < 4 ? -8 : -5.5)} ; move close to the sheet's edge\nG1 E{(filament_type[0] == \"FLEX\" ? 4 : 2)} F2400 ; deretraction after the initial one before nozzle cleaning\nG0 E10 X40 Z0.2 F500 ; purge\nG0 X70 E9 F800 ; purge\nG0 X{70 + 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{70 + 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG92 E0 ; reset extruder position", + "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\nG92 E0.0\n;[layer_z]", + "change_filament_gcode": "M600\nG1 E0.3 F1500 ; prime after color change", + "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", + "printer_notes": "Don't remove the following keywords! These keywords are used in the \"compatible printer\" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_MODEL_XLIS\nPG\nINPUT_SHAPER", + "scan_first_layer": "0", + "nozzle_type": "hardened_steel", + "auxiliary_fan": "0", + "thumbnails": [ + "16x16/QOI", + "313x173/QOI", + "440x240/QOI", + "480x240/QOI", + "640x480/PNG" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/machine/fdm_machine_common_xl_5t.json b/resources/profiles/Prusa/machine/fdm_machine_common_xl_5t.json new file mode 100644 index 0000000000..587d416602 --- /dev/null +++ b/resources/profiles/Prusa/machine/fdm_machine_common_xl_5t.json @@ -0,0 +1,22 @@ +{ + "type": "machine", + "name": "fdm_machine_common_xl_5t", + "from": "system", + "inherits": "fdm_machine_common_xl", + "instantiation": "false", + "gcode_flavor": "marlin2", + "purge_in_prime_tower": "0", + "single_extruder_multi_material": "0", + "extruder_clearance_radius": "67", + "extruder_clearance_height_to_rod": "21", + "extruder_clearance_height_to_lid": "21", + "printer_variant": "0.4", + "machine_end_gcode": "{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F720{endif} ; Move bed down\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X6 Y350 F6000 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+100, max_print_height)} F300{endif} ; Move bed down\nM900 K0 ; reset LA\nM142 S36 ; reset heatbreak target temp\nM221 S100 ; reset flow percentage\nM84 ; disable motors\n; max_layer_z = [max_layer_z]", + "machine_pause_gcode": "M601", + "machine_start_gcode": "M17 ; enable steppers\nM862.3 P \"XL\" ; printer model check\nM115 U6.0.1+14848\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\n; set print area\nM555 X{first_layer_print_min[0]} Y{first_layer_print_min[1]} W{(first_layer_print_max[0]) - (first_layer_print_min[0])} H{(first_layer_print_max[1]) - (first_layer_print_min[1])}\n; inform about nozzle diameter\nM862.1 P[nozzle_diameter]\n; set & wait for bed and extruder temp for MBL\nM140 S[first_layer_bed_temperature] ; set bed temp\nM104 T0 S{((filament_notes[0]=~/.*HT_MBL10.*/) ? (first_layer_temperature[0] - 10) : (filament_type[0] == \"PC\" or filament_type[0] == \"PA\") ? (first_layer_temperature[0] - 25) : (filament_type[0] == \"FLEX\") ? 210 : (filament_type[0]=~/.*PET.*/) ? 175 : 170)} ; set extruder temp for bed leveling\nM109 T0 R{((filament_notes[0]=~/.*HT_MBL10.*/) ? (first_layer_temperature[0] - 10) : (filament_type[0] == \"PC\" or filament_type[0] == \"PA\") ? (first_layer_temperature[0] - 25) : (filament_type[0] == \"FLEX\") ? 210 : (filament_type[0]=~/.*PET.*/) ? 175 : 170)} ; wait for temp\n; home carriage, pick tool, home all\nG28 XY\nM84 E ; turn off E motor\nG28 Z\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nG29 G ; absorb heat\n; move to the nozzle cleanup area\nG1 X{(min(((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32))), first_layer_print_min[0])) + 32} Y{(min((first_layer_print_min[1] - 7), first_layer_print_min[1]))} Z{5} F4800\nM302 S160 ; lower cold extrusion limit to 160C\nG1 E{-(filament_type[0] == \"FLEX\" ? 4 : 2)} F2400 ; retraction for nozzle cleanup\n; nozzle cleanup\nM84 E ; turn off E motor\nG29 P9 X{((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)))} Y{(first_layer_print_min[1] - 7)} W{32} H{7}\nG0 Z10 F480 ; move away in Z\n{if first_layer_bed_temperature[0] > 60}\nG0 Z70 F480 ; move away (a bit more) in Z\nG0 X30 Y{print_bed_min[1]} F6000 ; move away in X/Y for higher bed temperatures\n{endif}\nM106 S100 ; cool off the nozzle\nM107 ; stop cooling off the nozzle - turn off the fan\n; MBL\nM84 E ; turn off E motor\nG29 P1 ; invalidate mbl & probe print area\nG29 P1 X30 Y0 W50 H20 C ; probe near purge place\nG29 P3.2 ; interpolate mbl probes\nG29 P3.13 ; extrapolate mbl outside probe area\nG29 A ; activate mbl\nM104 S[first_layer_temperature] ; set extruder temp\nG1 Z10 F720 ; move away in Z\nG0 X30 Y-8 F6000 ; move next to the sheet\n; wait for extruder temp\nM109 T0 S{first_layer_temperature[0]}\n;\n; purge\n;\nG92 E0 ; reset extruder position\nG0 X{(0 == 0 ? 30 : (0 == 1 ? 150 : (0 == 2 ? 210 : 330)))} Y{(0 < 4 ? -8 : -5.5)} ; move close to the sheet's edge\nG1 E{(filament_type[0] == \"FLEX\" ? 4 : 2)} F2400 ; deretraction after the initial one before nozzle cleaning\nG0 E10 X40 Z0.2 F500 ; purge\nG0 X70 E9 F800 ; purge\nG0 X{70 + 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{70 + 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG92 E0 ; reset extruder position", + "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\nG92 E0.0\n;[layer_z]", + "change_filament_gcode": "M600\nG1 E0.3 F1500 ; prime after color change", + "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", + "printer_notes": "Don't remove the following keywords! These keywords are used in the \"compatible printer\" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_MODEL_XLIS\nPG\nINPUT_SHAPER" + +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.05mm Detail @Prusa XL 5T 0.25.json b/resources/profiles/Prusa/process/0.05mm Detail @Prusa XL 5T 0.25.json new file mode 100644 index 0000000000..3eac921d29 --- /dev/null +++ b/resources/profiles/Prusa/process/0.05mm Detail @Prusa XL 5T 0.25.json @@ -0,0 +1,67 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.05mm Detail @Prusa XL 5T 0.25", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.05", + "wall_loops": "3", + "top_shell_layers": "13", + "bottom_shell_layers": "10", + "top_shell_thickness": "0.7", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "1", + "brim_object_gap": "0", + "support_threshold_angle": "40", + "raft_first_layer_density": "95%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.1", + "support_top_z_distance": "0.1", + "support_bottom_z_distance": "0.1", + "support_base_pattern_spacing": "1", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.2", + "support_object_xy_distance": "150%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "65", + "small_perimeter_speed": "40", + "outer_wall_speed": "40", + "sparse_infill_speed": "100", + "internal_solid_infill_speed": "100", + "top_surface_speed": "60", + "support_speed": "70", + "support_interface_speed": "75%", + "bridge_speed": "25", + "gap_infill_speed": "40", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "80%", + "default_acceleration": "1500", + "outer_wall_acceleration": "800", + "inner_wall_acceleration": "1200", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "2000", + "sparse_infill_acceleration": "2500", + "bridge_acceleration": "1000", + "initial_layer_acceleration": "500", + "travel_acceleration": "4000", + "line_width": "0.27", + "initial_layer_line_width": "0.32", + "inner_wall_line_width": "0.25", + "outer_wall_line_width": "0.25", + "sparse_infill_line_width": "0.25", + "internal_solid_infill_line_width": "0.25", + "top_surface_line_width": "0.27", + "support_line_width": "0.25", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0", + "compatible_printers": [ + "Prusa XL 5T 0.25 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.07mm Detail @Prusa XL 5T 0.25.json b/resources/profiles/Prusa/process/0.07mm Detail @Prusa XL 5T 0.25.json new file mode 100644 index 0000000000..b30595bd93 --- /dev/null +++ b/resources/profiles/Prusa/process/0.07mm Detail @Prusa XL 5T 0.25.json @@ -0,0 +1,67 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.07mm Detail @Prusa XL 5T 0.25", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.07", + "wall_loops": "3", + "top_shell_layers": "11", + "bottom_shell_layers": "9", + "top_shell_thickness": "0.7", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "1", + "brim_object_gap": "0", + "support_threshold_angle": "40", + "raft_first_layer_density": "95%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.1", + "support_top_z_distance": "0.09", + "support_bottom_z_distance": "0.09", + "support_base_pattern_spacing": "1", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.2", + "support_object_xy_distance": "150%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "65", + "small_perimeter_speed": "40", + "outer_wall_speed": "40", + "sparse_infill_speed": "100", + "internal_solid_infill_speed": "140", + "top_surface_speed": "70", + "support_speed": "70", + "support_interface_speed": "75%", + "bridge_speed": "30", + "gap_infill_speed": "40", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "80%", + "default_acceleration": "1500", + "outer_wall_acceleration": "800", + "inner_wall_acceleration": "1200", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "2000", + "sparse_infill_acceleration": "2500", + "bridge_acceleration": "1000", + "initial_layer_acceleration": "500", + "travel_acceleration": "4000", + "line_width": "0.27", + "initial_layer_line_width": "0.32", + "inner_wall_line_width": "0.25", + "outer_wall_line_width": "0.25", + "sparse_infill_line_width": "0.25", + "internal_solid_infill_line_width": "0.25", + "top_surface_line_width": "0.27", + "support_line_width": "0.25", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0", + "compatible_printers": [ + "Prusa XL 5T 0.25 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.10mm FastDetail @Prusa XL 5T 0.4.json b/resources/profiles/Prusa/process/0.10mm FastDetail @Prusa XL 5T 0.4.json new file mode 100644 index 0000000000..e1149bb214 --- /dev/null +++ b/resources/profiles/Prusa/process/0.10mm FastDetail @Prusa XL 5T 0.4.json @@ -0,0 +1,67 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.10mm FastDetail @Prusa XL 5T 0.4", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.1", + "wall_loops": "3", + "top_shell_layers": "8", + "bottom_shell_layers": "7", + "top_shell_thickness": "0.7", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "2", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.15", + "support_top_z_distance": "0.17", + "support_bottom_z_distance": "0.17", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.2", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "140", + "small_perimeter_speed": "140", + "outer_wall_speed": "140", + "sparse_infill_speed": "140", + "internal_solid_infill_speed": "200", + "top_surface_speed": "100", + "support_speed": "120", + "support_interface_speed": "50", + "bridge_speed": "40", + "gap_infill_speed": "120", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "80%", + "default_acceleration": "2500", + "outer_wall_acceleration": "2000", + "inner_wall_acceleration": "2000", + "top_surface_acceleration": "1500", + "internal_solid_infill_acceleration": "2500", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1500", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.45", + "initial_layer_line_width": "0.5", + "inner_wall_line_width": "0.45", + "outer_wall_line_width": "0.45", + "sparse_infill_line_width": "0.45", + "internal_solid_infill_line_width": "0.45", + "top_surface_line_width": "0.4", + "support_line_width": "0.36", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.4 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.10mm Structural @Prusa XL 5T 0.5.json b/resources/profiles/Prusa/process/0.10mm Structural @Prusa XL 5T 0.5.json new file mode 100644 index 0000000000..4c463eaa2e --- /dev/null +++ b/resources/profiles/Prusa/process/0.10mm Structural @Prusa XL 5T 0.5.json @@ -0,0 +1,68 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.10mm Structural @Prusa XL 5T 0.5", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.1", + "wall_loops": "2", + "top_shell_layers": "8", + "bottom_shell_layers": "7", + "top_shell_thickness": "0.7", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "2", + "infill_anchor_max": "15", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.25", + "support_top_z_distance": "0.2", + "support_bottom_z_distance": "0.2", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.22", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "70", + "small_perimeter_speed": "40", + "outer_wall_speed": "40", + "sparse_infill_speed": "200", + "internal_solid_infill_speed": "200", + "top_surface_speed": "70", + "support_speed": "75", + "support_interface_speed": "75%", + "bridge_speed": "30", + "gap_infill_speed": "40", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "80%", + "default_acceleration": "2000", + "outer_wall_acceleration": "1500", + "inner_wall_acceleration": "2000", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "2500", + "sparse_infill_acceleration": "3000", + "bridge_acceleration": "1000", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.55", + "initial_layer_line_width": "0.55", + "inner_wall_line_width": "0.5", + "outer_wall_line_width": "0.5", + "sparse_infill_line_width": "0.5", + "internal_solid_infill_line_width": "0.5", + "top_surface_line_width": "0.45", + "support_line_width": "0.4", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.5 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.12mm Speed @Prusa XL 5T 0.25.json b/resources/profiles/Prusa/process/0.12mm Speed @Prusa XL 5T 0.25.json new file mode 100644 index 0000000000..171c4eb15d --- /dev/null +++ b/resources/profiles/Prusa/process/0.12mm Speed @Prusa XL 5T 0.25.json @@ -0,0 +1,67 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.12mm Speed @Prusa XL 5T 0.25", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.12", + "wall_loops": "3", + "top_shell_layers": "9", + "bottom_shell_layers": "6", + "top_shell_thickness": "0.6", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "1", + "brim_object_gap": "0", + "support_threshold_angle": "40", + "raft_first_layer_density": "95%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.08", + "support_top_z_distance": "0.09", + "support_bottom_z_distance": "0.09", + "support_base_pattern_spacing": "1", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.2", + "support_object_xy_distance": "150%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "120", + "small_perimeter_speed": "120", + "outer_wall_speed": "120", + "sparse_infill_speed": "100", + "internal_solid_infill_speed": "140", + "top_surface_speed": "60", + "support_speed": "70", + "support_interface_speed": "75%", + "bridge_speed": "30", + "gap_infill_speed": "50", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "80%", + "default_acceleration": "2000", + "outer_wall_acceleration": "1500", + "inner_wall_acceleration": "2000", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "2500", + "sparse_infill_acceleration": "3000", + "bridge_acceleration": "1500", + "initial_layer_acceleration": "500", + "travel_acceleration": "4000", + "line_width": "0.27", + "initial_layer_line_width": "0.32", + "inner_wall_line_width": "0.27", + "outer_wall_line_width": "0.27", + "sparse_infill_line_width": "0.27", + "internal_solid_infill_line_width": "0.27", + "top_surface_line_width": "0.27", + "support_line_width": "0.25", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0", + "compatible_printers": [ + "Prusa XL 5T 0.25 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.12mm Structural @Prusa XL 5T 0.25.json b/resources/profiles/Prusa/process/0.12mm Structural @Prusa XL 5T 0.25.json new file mode 100644 index 0000000000..d1cbccfcde --- /dev/null +++ b/resources/profiles/Prusa/process/0.12mm Structural @Prusa XL 5T 0.25.json @@ -0,0 +1,67 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.12mm Structural @Prusa XL 5T 0.25", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.12", + "wall_loops": "3", + "top_shell_layers": "9", + "bottom_shell_layers": "7", + "top_shell_thickness": "0.6", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "1", + "brim_object_gap": "0", + "support_threshold_angle": "40", + "raft_first_layer_density": "95%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.08", + "support_top_z_distance": "0.09", + "support_bottom_z_distance": "0.09", + "support_base_pattern_spacing": "1", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.2", + "support_object_xy_distance": "150%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "70", + "small_perimeter_speed": "40", + "outer_wall_speed": "40", + "sparse_infill_speed": "100", + "internal_solid_infill_speed": "140", + "top_surface_speed": "60", + "support_speed": "70", + "support_interface_speed": "75%", + "bridge_speed": "30", + "gap_infill_speed": "50", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "80%", + "default_acceleration": "2000", + "outer_wall_acceleration": "1000", + "inner_wall_acceleration": "1500", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "2500", + "sparse_infill_acceleration": "2500", + "bridge_acceleration": "1500", + "initial_layer_acceleration": "500", + "travel_acceleration": "4000", + "line_width": "0.27", + "initial_layer_line_width": "0.32", + "inner_wall_line_width": "0.27", + "outer_wall_line_width": "0.27", + "sparse_infill_line_width": "0.27", + "internal_solid_infill_line_width": "0.27", + "top_surface_line_width": "0.27", + "support_line_width": "0.25", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0", + "compatible_printers": [ + "Prusa XL 5T 0.25 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.12mm Structural @Prusa XL 5T 0.3.json b/resources/profiles/Prusa/process/0.12mm Structural @Prusa XL 5T 0.3.json new file mode 100644 index 0000000000..57ce297d8c --- /dev/null +++ b/resources/profiles/Prusa/process/0.12mm Structural @Prusa XL 5T 0.3.json @@ -0,0 +1,67 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.12mm Structural @Prusa XL 5T 0.3", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.12", + "wall_loops": "3", + "top_shell_layers": "7", + "bottom_shell_layers": "6", + "top_shell_thickness": "0.7", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "1", + "brim_object_gap": "0", + "support_threshold_angle": "40", + "raft_first_layer_density": "90%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.12", + "support_top_z_distance": "0.12", + "support_bottom_z_distance": "0.12", + "support_base_pattern_spacing": "1", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.2", + "support_object_xy_distance": "100%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "80", + "small_perimeter_speed": "40", + "outer_wall_speed": "40", + "sparse_infill_speed": "100", + "internal_solid_infill_speed": "200", + "top_surface_speed": "40", + "support_speed": "70", + "support_interface_speed": "75%", + "bridge_speed": "30", + "gap_infill_speed": "50", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "80%", + "default_acceleration": "1500", + "outer_wall_acceleration": "1200", + "inner_wall_acceleration": "1500", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "2500", + "sparse_infill_acceleration": "3000", + "bridge_acceleration": "1000", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.34", + "initial_layer_line_width": "0.4", + "inner_wall_line_width": "0.34", + "outer_wall_line_width": "0.34", + "sparse_infill_line_width": "0.34", + "internal_solid_infill_line_width": "0.34", + "top_surface_line_width": "0.3", + "support_line_width": "0.3", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0", + "compatible_printers": [ + "Prusa XL 5T 0.3 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.15mm Speed @Prusa XL 5T 0.25.json b/resources/profiles/Prusa/process/0.15mm Speed @Prusa XL 5T 0.25.json new file mode 100644 index 0000000000..1f99efe994 --- /dev/null +++ b/resources/profiles/Prusa/process/0.15mm Speed @Prusa XL 5T 0.25.json @@ -0,0 +1,67 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.15mm Speed @Prusa XL 5T 0.25", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.15", + "wall_loops": "3", + "top_shell_layers": "6", + "bottom_shell_layers": "7", + "top_shell_thickness": "0.7", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "1", + "brim_object_gap": "0", + "support_threshold_angle": "40", + "raft_first_layer_density": "95%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.08", + "support_top_z_distance": "0.09", + "support_bottom_z_distance": "0.09", + "support_base_pattern_spacing": "1", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.2", + "support_object_xy_distance": "150%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "120", + "small_perimeter_speed": "120", + "outer_wall_speed": "120", + "sparse_infill_speed": "100", + "internal_solid_infill_speed": "140", + "top_surface_speed": "60", + "support_speed": "70", + "support_interface_speed": "75%", + "bridge_speed": "30", + "gap_infill_speed": "50", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "80%", + "default_acceleration": "2000", + "outer_wall_acceleration": "1500", + "inner_wall_acceleration": "2000", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "2500", + "sparse_infill_acceleration": "3000", + "bridge_acceleration": "1500", + "initial_layer_acceleration": "500", + "travel_acceleration": "4000", + "line_width": "0.27", + "initial_layer_line_width": "0.32", + "inner_wall_line_width": "0.27", + "outer_wall_line_width": "0.27", + "sparse_infill_line_width": "0.27", + "internal_solid_infill_line_width": "0.27", + "top_surface_line_width": "0.27", + "support_line_width": "0.25", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0", + "compatible_printers": [ + "Prusa XL 5T 0.25 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.15mm Speed @Prusa XL 5T 0.4.json b/resources/profiles/Prusa/process/0.15mm Speed @Prusa XL 5T 0.4.json new file mode 100644 index 0000000000..b371e07e86 --- /dev/null +++ b/resources/profiles/Prusa/process/0.15mm Speed @Prusa XL 5T 0.4.json @@ -0,0 +1,67 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.15mm Speed @Prusa XL 5T 0.4", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.15", + "wall_loops": "2", + "top_shell_layers": "6", + "bottom_shell_layers": "5", + "top_shell_thickness": "0.7", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "2", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.15", + "support_top_z_distance": "0.17", + "support_bottom_z_distance": "0.17", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.2", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "170", + "small_perimeter_speed": "170", + "outer_wall_speed": "170", + "sparse_infill_speed": "200", + "internal_solid_infill_speed": "200", + "top_surface_speed": "100", + "support_speed": "120", + "support_interface_speed": "50", + "bridge_speed": "45", + "gap_infill_speed": "120", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "80%", + "default_acceleration": "2500", + "outer_wall_acceleration": "2500", + "inner_wall_acceleration": "3000", + "top_surface_acceleration": "1500", + "internal_solid_infill_acceleration": "3500", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1500", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.45", + "initial_layer_line_width": "0.5", + "inner_wall_line_width": "0.45", + "outer_wall_line_width": "0.45", + "sparse_infill_line_width": "0.45", + "internal_solid_infill_line_width": "0.45", + "top_surface_line_width": "0.42", + "support_line_width": "0.36", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.4 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.15mm Structural @Prusa XL 5T 0.25.json b/resources/profiles/Prusa/process/0.15mm Structural @Prusa XL 5T 0.25.json new file mode 100644 index 0000000000..9b7cbf961d --- /dev/null +++ b/resources/profiles/Prusa/process/0.15mm Structural @Prusa XL 5T 0.25.json @@ -0,0 +1,67 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.15mm Structural @Prusa XL 5T 0.25", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.15", + "wall_loops": "3", + "top_shell_layers": "6", + "bottom_shell_layers": "5", + "top_shell_thickness": "0.7", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "1", + "brim_object_gap": "0", + "support_threshold_angle": "40", + "raft_first_layer_density": "95%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.08", + "support_top_z_distance": "0.09", + "support_bottom_z_distance": "0.09", + "support_base_pattern_spacing": "1", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.2", + "support_object_xy_distance": "150%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "70", + "small_perimeter_speed": "40", + "outer_wall_speed": "40", + "sparse_infill_speed": "100", + "internal_solid_infill_speed": "140", + "top_surface_speed": "60", + "support_speed": "70", + "support_interface_speed": "75%", + "bridge_speed": "30", + "gap_infill_speed": "50", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "80%", + "default_acceleration": "2000", + "outer_wall_acceleration": "1000", + "inner_wall_acceleration": "1500", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "2500", + "sparse_infill_acceleration": "3000", + "bridge_acceleration": "1500", + "initial_layer_acceleration": "500", + "travel_acceleration": "4000", + "line_width": "0.27", + "initial_layer_line_width": "0.32", + "inner_wall_line_width": "0.27", + "outer_wall_line_width": "0.27", + "sparse_infill_line_width": "0.27", + "internal_solid_infill_line_width": "0.27", + "top_surface_line_width": "0.27", + "support_line_width": "0.25", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0", + "compatible_printers": [ + "Prusa XL 5T 0.25 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.15mm Structural @Prusa XL 5T 0.4.json b/resources/profiles/Prusa/process/0.15mm Structural @Prusa XL 5T 0.4.json new file mode 100644 index 0000000000..69ad3b4487 --- /dev/null +++ b/resources/profiles/Prusa/process/0.15mm Structural @Prusa XL 5T 0.4.json @@ -0,0 +1,67 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.15mm Structural @Prusa XL 5T 0.4", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.15", + "wall_loops": "2", + "top_shell_layers": "6", + "bottom_shell_layers": "5", + "top_shell_thickness": "0.7", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "2", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.15", + "support_top_z_distance": "0.17", + "support_bottom_z_distance": "0.17", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.2", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "80", + "small_perimeter_speed": "45", + "outer_wall_speed": "45", + "sparse_infill_speed": "110", + "internal_solid_infill_speed": "140", + "top_surface_speed": "75", + "support_speed": "120", + "support_interface_speed": "50", + "bridge_speed": "45", + "gap_infill_speed": "65", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "90%", + "default_acceleration": "2500", + "outer_wall_acceleration": "1500", + "inner_wall_acceleration": "2500", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "3000", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1500", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.45", + "initial_layer_line_width": "0.5", + "inner_wall_line_width": "0.45", + "outer_wall_line_width": "0.45", + "sparse_infill_line_width": "0.45", + "internal_solid_infill_line_width": "0.45", + "top_surface_line_width": "0.42", + "support_line_width": "0.36", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.4 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.15mm Structural @Prusa XL 5T 0.5.json b/resources/profiles/Prusa/process/0.15mm Structural @Prusa XL 5T 0.5.json new file mode 100644 index 0000000000..fb209d319c --- /dev/null +++ b/resources/profiles/Prusa/process/0.15mm Structural @Prusa XL 5T 0.5.json @@ -0,0 +1,68 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.15mm Structural @Prusa XL 5T 0.5", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.15", + "wall_loops": "2", + "top_shell_layers": "6", + "bottom_shell_layers": "5", + "top_shell_thickness": "0.7", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "2", + "infill_anchor_max": "15", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.25", + "support_top_z_distance": "0.2", + "support_bottom_z_distance": "0.2", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.22", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "80", + "small_perimeter_speed": "45", + "outer_wall_speed": "45", + "sparse_infill_speed": "200", + "internal_solid_infill_speed": "180", + "top_surface_speed": "70", + "support_speed": "75", + "support_interface_speed": "75%", + "bridge_speed": "40", + "gap_infill_speed": "50", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "80%", + "default_acceleration": "2000", + "outer_wall_acceleration": "1500", + "inner_wall_acceleration": "2000", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "2500", + "sparse_infill_acceleration": "3000", + "bridge_acceleration": "1000", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.55", + "initial_layer_line_width": "0.55", + "inner_wall_line_width": "0.55", + "outer_wall_line_width": "0.55", + "sparse_infill_line_width": "0.55", + "internal_solid_infill_line_width": "0.55", + "top_surface_line_width": "0.5", + "support_line_width": "0.4", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.5 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.15mm Structural @Prusa XL 5T 0.6.json b/resources/profiles/Prusa/process/0.15mm Structural @Prusa XL 5T 0.6.json new file mode 100644 index 0000000000..24b3b29311 --- /dev/null +++ b/resources/profiles/Prusa/process/0.15mm Structural @Prusa XL 5T 0.6.json @@ -0,0 +1,69 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.15mm Structural @Prusa XL 5T 0.6", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.15", + "wall_loops": "2", + "top_shell_layers": "6", + "bottom_shell_layers": "5", + "top_shell_thickness": "0.9", + "bottom_shell_thickness": "0.6", + "sparse_infill_density": "20%", + "infill_anchor": "2.5", + "infill_anchor_max": "20", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.25", + "support_top_z_distance": "0.22", + "support_bottom_z_distance": "0.22", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.25", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_branch_diameter_double_wall": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "80", + "small_perimeter_speed": "45", + "outer_wall_speed": "45", + "sparse_infill_speed": "105", + "internal_solid_infill_speed": "160", + "top_surface_speed": "70", + "support_speed": "110", + "support_interface_speed": "75%", + "bridge_speed": "40", + "gap_infill_speed": "75", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "20", + "overhang_3_4_speed": "25", + "overhang_4_4_speed": "90%", + "default_acceleration": "2500", + "outer_wall_acceleration": "1500", + "inner_wall_acceleration": "2500", + "top_surface_acceleration": "1500", + "internal_solid_infill_acceleration": "2500", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1500", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.68", + "initial_layer_line_width": "0.68", + "inner_wall_line_width": "0.6", + "outer_wall_line_width": "0.6", + "sparse_infill_line_width": "0.6", + "internal_solid_infill_line_width": "0.6", + "top_surface_line_width": "0.5", + "support_line_width": "0.55", + "infill_wall_overlap": "15%", + "resolution": "0.0125", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.6 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.16mm Speed @Prusa XL 5T 0.3.json b/resources/profiles/Prusa/process/0.16mm Speed @Prusa XL 5T 0.3.json new file mode 100644 index 0000000000..e076cd44fa --- /dev/null +++ b/resources/profiles/Prusa/process/0.16mm Speed @Prusa XL 5T 0.3.json @@ -0,0 +1,67 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.16mm Speed @Prusa XL 5T 0.3", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.16", + "wall_loops": "3", + "top_shell_layers": "6", + "bottom_shell_layers": "5", + "top_shell_thickness": "0.7", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "1", + "brim_object_gap": "0", + "support_threshold_angle": "40", + "raft_first_layer_density": "90%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.12", + "support_top_z_distance": "0.12", + "support_bottom_z_distance": "0.12", + "support_base_pattern_spacing": "1", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.2", + "support_object_xy_distance": "100%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "140", + "small_perimeter_speed": "120", + "outer_wall_speed": "120", + "sparse_infill_speed": "120", + "internal_solid_infill_speed": "200", + "top_surface_speed": "50", + "support_speed": "100", + "support_interface_speed": "45%", + "bridge_speed": "30", + "gap_infill_speed": "50", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "80%", + "default_acceleration": "2000", + "outer_wall_acceleration": "2500", + "inner_wall_acceleration": "2500", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "3000", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1000", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.34", + "initial_layer_line_width": "0.4", + "inner_wall_line_width": "0.34", + "outer_wall_line_width": "0.34", + "sparse_infill_line_width": "0.34", + "internal_solid_infill_line_width": "0.34", + "top_surface_line_width": "0.3", + "support_line_width": "0.3", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0", + "compatible_printers": [ + "Prusa XL 5T 0.3 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.16mm Structural @Prusa XL 5T 0.3.json b/resources/profiles/Prusa/process/0.16mm Structural @Prusa XL 5T 0.3.json new file mode 100644 index 0000000000..c87fd0fbb6 --- /dev/null +++ b/resources/profiles/Prusa/process/0.16mm Structural @Prusa XL 5T 0.3.json @@ -0,0 +1,67 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.16mm Structural @Prusa XL 5T 0.3", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.16", + "wall_loops": "3", + "top_shell_layers": "6", + "bottom_shell_layers": "5", + "top_shell_thickness": "0.7", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "1", + "brim_object_gap": "0", + "support_threshold_angle": "40", + "raft_first_layer_density": "90%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.12", + "support_top_z_distance": "0.12", + "support_bottom_z_distance": "0.12", + "support_base_pattern_spacing": "1", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.2", + "support_object_xy_distance": "100%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "80", + "small_perimeter_speed": "45", + "outer_wall_speed": "45", + "sparse_infill_speed": "120", + "internal_solid_infill_speed": "200", + "top_surface_speed": "50", + "support_speed": "70", + "support_interface_speed": "75%", + "bridge_speed": "30", + "gap_infill_speed": "50", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "80%", + "default_acceleration": "2000", + "outer_wall_acceleration": "1500", + "inner_wall_acceleration": "2000", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "2500", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1000", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.34", + "initial_layer_line_width": "0.4", + "inner_wall_line_width": "0.34", + "outer_wall_line_width": "0.34", + "sparse_infill_line_width": "0.34", + "internal_solid_infill_line_width": "0.34", + "top_surface_line_width": "0.3", + "support_line_width": "0.3", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0", + "compatible_printers": [ + "Prusa XL 5T 0.3 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.20mm Speed @Prusa XL 5T 0.3.json b/resources/profiles/Prusa/process/0.20mm Speed @Prusa XL 5T 0.3.json new file mode 100644 index 0000000000..429f8d2c07 --- /dev/null +++ b/resources/profiles/Prusa/process/0.20mm Speed @Prusa XL 5T 0.3.json @@ -0,0 +1,67 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.20mm Speed @Prusa XL 5T 0.3", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.2", + "wall_loops": "3", + "top_shell_layers": "5", + "bottom_shell_layers": "4", + "top_shell_thickness": "0.7", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "1", + "brim_object_gap": "0", + "support_threshold_angle": "40", + "raft_first_layer_density": "90%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.12", + "support_top_z_distance": "0.12", + "support_bottom_z_distance": "0.12", + "support_base_pattern_spacing": "1", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.2", + "support_object_xy_distance": "100%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "140", + "small_perimeter_speed": "120", + "outer_wall_speed": "120", + "sparse_infill_speed": "120", + "internal_solid_infill_speed": "200", + "top_surface_speed": "50", + "support_speed": "100", + "support_interface_speed": "45%", + "bridge_speed": "30", + "gap_infill_speed": "50", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "80%", + "default_acceleration": "2000", + "outer_wall_acceleration": "2500", + "inner_wall_acceleration": "2500", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "3000", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1000", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.34", + "initial_layer_line_width": "0.4", + "inner_wall_line_width": "0.34", + "outer_wall_line_width": "0.34", + "sparse_infill_line_width": "0.34", + "internal_solid_infill_line_width": "0.34", + "top_surface_line_width": "0.3", + "support_line_width": "0.3", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0", + "compatible_printers": [ + "Prusa XL 5T 0.3 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.20mm Speed @Prusa XL 5T 0.4.json b/resources/profiles/Prusa/process/0.20mm Speed @Prusa XL 5T 0.4.json new file mode 100644 index 0000000000..d6e23c2a08 --- /dev/null +++ b/resources/profiles/Prusa/process/0.20mm Speed @Prusa XL 5T 0.4.json @@ -0,0 +1,67 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.20mm Speed @Prusa XL 5T 0.4", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.2", + "wall_loops": "2", + "top_shell_layers": "5", + "bottom_shell_layers": "4", + "top_shell_thickness": "0.7", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "2", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.15", + "support_top_z_distance": "0.2", + "support_bottom_z_distance": "0.2", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.2", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "170", + "small_perimeter_speed": "170", + "outer_wall_speed": "170", + "sparse_infill_speed": "200", + "internal_solid_infill_speed": "200", + "top_surface_speed": "100", + "support_speed": "110", + "support_interface_speed": "50%", + "bridge_speed": "50", + "gap_infill_speed": "120", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "90%", + "default_acceleration": "2500", + "outer_wall_acceleration": "2500", + "inner_wall_acceleration": "3000", + "top_surface_acceleration": "1500", + "internal_solid_infill_acceleration": "4000", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1500", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.45", + "initial_layer_line_width": "0.5", + "inner_wall_line_width": "0.45", + "outer_wall_line_width": "0.45", + "sparse_infill_line_width": "0.45", + "internal_solid_infill_line_width": "0.45", + "top_surface_line_width": "0.42", + "support_line_width": "0.36", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.4 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.20mm Speed @Prusa XL 5T 0.5.json b/resources/profiles/Prusa/process/0.20mm Speed @Prusa XL 5T 0.5.json new file mode 100644 index 0000000000..01e10672ef --- /dev/null +++ b/resources/profiles/Prusa/process/0.20mm Speed @Prusa XL 5T 0.5.json @@ -0,0 +1,68 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.20mm Speed @Prusa XL 5T 0.5", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.2", + "wall_loops": "2", + "top_shell_layers": "5", + "bottom_shell_layers": "4", + "top_shell_thickness": "0.7", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "2", + "infill_anchor_max": "15", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.25", + "support_top_z_distance": "0.2", + "support_bottom_z_distance": "0.2", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.22", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "140", + "small_perimeter_speed": "140", + "outer_wall_speed": "140", + "sparse_infill_speed": "200", + "internal_solid_infill_speed": "135", + "top_surface_speed": "70", + "support_speed": "120", + "support_interface_speed": "75%", + "bridge_speed": "40", + "gap_infill_speed": "70", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "80%", + "default_acceleration": "2500", + "outer_wall_acceleration": "2500", + "inner_wall_acceleration": "3000", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "3000", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1000", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.55", + "initial_layer_line_width": "0.55", + "inner_wall_line_width": "0.55", + "outer_wall_line_width": "0.55", + "sparse_infill_line_width": "0.55", + "internal_solid_infill_line_width": "0.55", + "top_surface_line_width": "0.5", + "support_line_width": "0.4", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.5 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.20mm Speed @Prusa XL 5T 0.6.json b/resources/profiles/Prusa/process/0.20mm Speed @Prusa XL 5T 0.6.json new file mode 100644 index 0000000000..e44f3cb46b --- /dev/null +++ b/resources/profiles/Prusa/process/0.20mm Speed @Prusa XL 5T 0.6.json @@ -0,0 +1,69 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.20mm Speed @Prusa XL 5T 0.6", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.2", + "wall_loops": "2", + "top_shell_layers": "5", + "bottom_shell_layers": "4", + "top_shell_thickness": "0.9", + "bottom_shell_thickness": "0.6", + "sparse_infill_density": "20%", + "infill_anchor": "2.5", + "infill_anchor_max": "20", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.25", + "support_top_z_distance": "0.22", + "support_bottom_z_distance": "0.22", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.25", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_branch_diameter_double_wall": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "120", + "small_perimeter_speed": "120", + "outer_wall_speed": "120", + "sparse_infill_speed": "120", + "internal_solid_infill_speed": "110", + "top_surface_speed": "70", + "support_speed": "110", + "support_interface_speed": "75%", + "bridge_speed": "40", + "gap_infill_speed": "75", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "20", + "overhang_3_4_speed": "25", + "overhang_4_4_speed": "50", + "default_acceleration": "2500", + "outer_wall_acceleration": "2500", + "inner_wall_acceleration": "3000", + "top_surface_acceleration": "1500", + "internal_solid_infill_acceleration": "3000", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1500", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.68", + "initial_layer_line_width": "0.68", + "inner_wall_line_width": "0.62", + "outer_wall_line_width": "0.62", + "sparse_infill_line_width": "0.62", + "internal_solid_infill_line_width": "0.62", + "top_surface_line_width": "0.5", + "support_line_width": "0.55", + "infill_wall_overlap": "15%", + "resolution": "0.0125", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.6 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.20mm Structural @Prusa XL 5T 0.4.json b/resources/profiles/Prusa/process/0.20mm Structural @Prusa XL 5T 0.4.json new file mode 100644 index 0000000000..147386cef3 --- /dev/null +++ b/resources/profiles/Prusa/process/0.20mm Structural @Prusa XL 5T 0.4.json @@ -0,0 +1,67 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.20mm Structural @Prusa XL 5T 0.4", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.2", + "wall_loops": "2", + "top_shell_layers": "5", + "bottom_shell_layers": "4", + "top_shell_thickness": "0.7", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "2", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.15", + "support_top_z_distance": "0.2", + "support_bottom_z_distance": "0.2", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.2", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "80", + "small_perimeter_speed": "45", + "outer_wall_speed": "45", + "sparse_infill_speed": "120", + "internal_solid_infill_speed": "140", + "top_surface_speed": "75", + "support_speed": "120", + "support_interface_speed": "50", + "bridge_speed": "50", + "gap_infill_speed": "65", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "90%", + "default_acceleration": "2500", + "outer_wall_acceleration": "1500", + "inner_wall_acceleration": "2500", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "3000", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1500", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.45", + "initial_layer_line_width": "0.5", + "inner_wall_line_width": "0.45", + "outer_wall_line_width": "0.45", + "sparse_infill_line_width": "0.45", + "internal_solid_infill_line_width": "0.45", + "top_surface_line_width": "0.42", + "support_line_width": "0.36", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.4 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.20mm Structural @Prusa XL 5T 0.5.json b/resources/profiles/Prusa/process/0.20mm Structural @Prusa XL 5T 0.5.json new file mode 100644 index 0000000000..f761f98424 --- /dev/null +++ b/resources/profiles/Prusa/process/0.20mm Structural @Prusa XL 5T 0.5.json @@ -0,0 +1,68 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.20mm Structural @Prusa XL 5T 0.5", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.2", + "wall_loops": "2", + "top_shell_layers": "5", + "bottom_shell_layers": "4", + "top_shell_thickness": "0.7", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "2", + "infill_anchor_max": "15", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.25", + "support_top_z_distance": "0.2", + "support_bottom_z_distance": "0.2", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.22", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "80", + "small_perimeter_speed": "45", + "outer_wall_speed": "45", + "sparse_infill_speed": "200", + "internal_solid_infill_speed": "120", + "top_surface_speed": "70", + "support_speed": "75", + "support_interface_speed": "75%", + "bridge_speed": "40", + "gap_infill_speed": "70", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "80%", + "default_acceleration": "2500", + "outer_wall_acceleration": "1500", + "inner_wall_acceleration": "2000", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "2500", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1000", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.55", + "initial_layer_line_width": "0.55", + "inner_wall_line_width": "0.55", + "outer_wall_line_width": "0.55", + "sparse_infill_line_width": "0.55", + "internal_solid_infill_line_width": "0.55", + "top_surface_line_width": "0.5", + "support_line_width": "0.4", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.5 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.20mm Structural @Prusa XL 5T 0.6.json b/resources/profiles/Prusa/process/0.20mm Structural @Prusa XL 5T 0.6.json new file mode 100644 index 0000000000..a9951b4632 --- /dev/null +++ b/resources/profiles/Prusa/process/0.20mm Structural @Prusa XL 5T 0.6.json @@ -0,0 +1,69 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.20mm Structural @Prusa XL 5T 0.6", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.2", + "wall_loops": "2", + "top_shell_layers": "5", + "bottom_shell_layers": "4", + "top_shell_thickness": "0.9", + "bottom_shell_thickness": "0.6", + "sparse_infill_density": "20%", + "infill_anchor": "2.5", + "infill_anchor_max": "20", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.25", + "support_top_z_distance": "0.22", + "support_bottom_z_distance": "0.22", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.25", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_branch_diameter_double_wall": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "80", + "small_perimeter_speed": "45", + "outer_wall_speed": "45", + "sparse_infill_speed": "120", + "internal_solid_infill_speed": "110", + "top_surface_speed": "70", + "support_speed": "110", + "support_interface_speed": "75%", + "bridge_speed": "40", + "gap_infill_speed": "75", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "20", + "overhang_3_4_speed": "25", + "overhang_4_4_speed": "90%", + "default_acceleration": "2500", + "outer_wall_acceleration": "1500", + "inner_wall_acceleration": "2500", + "top_surface_acceleration": "1500", + "internal_solid_infill_acceleration": "2500", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1500", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.68", + "initial_layer_line_width": "0.68", + "inner_wall_line_width": "0.6", + "outer_wall_line_width": "0.6", + "sparse_infill_line_width": "0.6", + "internal_solid_infill_line_width": "0.6", + "top_surface_line_width": "0.5", + "support_line_width": "0.55", + "infill_wall_overlap": "15%", + "resolution": "0.0125", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.6 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.25mm Speed @Prusa XL 5T 0.5.json b/resources/profiles/Prusa/process/0.25mm Speed @Prusa XL 5T 0.5.json new file mode 100644 index 0000000000..f55bd6d6d8 --- /dev/null +++ b/resources/profiles/Prusa/process/0.25mm Speed @Prusa XL 5T 0.5.json @@ -0,0 +1,68 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.25mm Speed @Prusa XL 5T 0.5", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.25", + "wall_loops": "2", + "top_shell_layers": "4", + "bottom_shell_layers": "3", + "top_shell_thickness": "0.7", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "2", + "infill_anchor_max": "15", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.25", + "support_top_z_distance": "0.25", + "support_bottom_z_distance": "0.25", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.22", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "140", + "small_perimeter_speed": "140", + "outer_wall_speed": "140", + "sparse_infill_speed": "200", + "internal_solid_infill_speed": "110", + "top_surface_speed": "70", + "support_speed": "120", + "support_interface_speed": "75%", + "bridge_speed": "40", + "gap_infill_speed": "70", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "80%", + "default_acceleration": "2500", + "outer_wall_acceleration": "2500", + "inner_wall_acceleration": "3000", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "3000", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1000", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.55", + "initial_layer_line_width": "0.55", + "inner_wall_line_width": "0.55", + "outer_wall_line_width": "0.55", + "sparse_infill_line_width": "0.55", + "internal_solid_infill_line_width": "0.55", + "top_surface_line_width": "0.5", + "support_line_width": "0.4", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.5 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.25mm Speed @Prusa XL 5T 0.6.json b/resources/profiles/Prusa/process/0.25mm Speed @Prusa XL 5T 0.6.json new file mode 100644 index 0000000000..678d72f718 --- /dev/null +++ b/resources/profiles/Prusa/process/0.25mm Speed @Prusa XL 5T 0.6.json @@ -0,0 +1,69 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.25mm Speed @Prusa XL 5T 0.6", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.25", + "wall_loops": "2", + "top_shell_layers": "4", + "bottom_shell_layers": "3", + "top_shell_thickness": "0.9", + "bottom_shell_thickness": "0.6", + "sparse_infill_density": "20%", + "infill_anchor": "2.5", + "infill_anchor_max": "20", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.25", + "support_top_z_distance": "0.25", + "support_bottom_z_distance": "0.25", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.25", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_branch_diameter_double_wall": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "80", + "small_perimeter_speed": "80", + "outer_wall_speed": "80", + "sparse_infill_speed": "100", + "internal_solid_infill_speed": "90", + "top_surface_speed": "60", + "support_speed": "80", + "support_interface_speed": "75%", + "bridge_speed": "40", + "gap_infill_speed": "70", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "20", + "overhang_3_4_speed": "25", + "overhang_4_4_speed": "50", + "default_acceleration": "2500", + "outer_wall_acceleration": "2500", + "inner_wall_acceleration": "3000", + "top_surface_acceleration": "1500", + "internal_solid_infill_acceleration": "3000", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1500", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.68", + "initial_layer_line_width": "0.68", + "inner_wall_line_width": "0.68", + "outer_wall_line_width": "0.68", + "sparse_infill_line_width": "0.68", + "internal_solid_infill_line_width": "0.68", + "top_surface_line_width": "0.55", + "support_line_width": "0.55", + "infill_wall_overlap": "15%", + "resolution": "0.0125", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.6 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.25mm Structural @Prusa XL 5T 0.4.json b/resources/profiles/Prusa/process/0.25mm Structural @Prusa XL 5T 0.4.json new file mode 100644 index 0000000000..a5d0d3eef0 --- /dev/null +++ b/resources/profiles/Prusa/process/0.25mm Structural @Prusa XL 5T 0.4.json @@ -0,0 +1,67 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.25mm Structural @Prusa XL 5T 0.4", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.25", + "wall_loops": "2", + "top_shell_layers": "4", + "bottom_shell_layers": "3", + "top_shell_thickness": "0.7", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "2", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.15", + "support_top_z_distance": "0.2", + "support_bottom_z_distance": "0.2", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.2", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "80", + "small_perimeter_speed": "45", + "outer_wall_speed": "45", + "sparse_infill_speed": "120", + "internal_solid_infill_speed": "140", + "top_surface_speed": "75", + "support_speed": "120", + "support_interface_speed": "50", + "bridge_speed": "50", + "gap_infill_speed": "65", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "90%", + "default_acceleration": "2500", + "outer_wall_acceleration": "1500", + "inner_wall_acceleration": "2500", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "3000", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1500", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.45", + "initial_layer_line_width": "0.5", + "inner_wall_line_width": "0.45", + "outer_wall_line_width": "0.45", + "sparse_infill_line_width": "0.45", + "internal_solid_infill_line_width": "0.45", + "top_surface_line_width": "0.42", + "support_line_width": "0.36", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.4 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.25mm Structural @Prusa XL 5T 0.5.json b/resources/profiles/Prusa/process/0.25mm Structural @Prusa XL 5T 0.5.json new file mode 100644 index 0000000000..3d39489dd7 --- /dev/null +++ b/resources/profiles/Prusa/process/0.25mm Structural @Prusa XL 5T 0.5.json @@ -0,0 +1,68 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.25mm Structural @Prusa XL 5T 0.5", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.25", + "wall_loops": "2", + "top_shell_layers": "4", + "bottom_shell_layers": "3", + "top_shell_thickness": "0.7", + "bottom_shell_thickness": "0.5", + "sparse_infill_density": "15%", + "infill_anchor": "2", + "infill_anchor_max": "15", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.25", + "support_top_z_distance": "0.25", + "support_bottom_z_distance": "0.25", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.22", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "80", + "small_perimeter_speed": "45", + "outer_wall_speed": "45", + "sparse_infill_speed": "200", + "internal_solid_infill_speed": "110", + "top_surface_speed": "70", + "support_speed": "75", + "support_interface_speed": "75%", + "bridge_speed": "40", + "gap_infill_speed": "70", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "25", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "80%", + "default_acceleration": "2500", + "outer_wall_acceleration": "1500", + "inner_wall_acceleration": "2000", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "2500", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1000", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.55", + "initial_layer_line_width": "0.55", + "inner_wall_line_width": "0.55", + "outer_wall_line_width": "0.55", + "sparse_infill_line_width": "0.55", + "internal_solid_infill_line_width": "0.55", + "top_surface_line_width": "0.5", + "support_line_width": "0.4", + "infill_wall_overlap": "15%", + "resolution": "0.008", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.5 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.25mm Structural @Prusa XL 5T 0.6.json b/resources/profiles/Prusa/process/0.25mm Structural @Prusa XL 5T 0.6.json new file mode 100644 index 0000000000..44e36b1d88 --- /dev/null +++ b/resources/profiles/Prusa/process/0.25mm Structural @Prusa XL 5T 0.6.json @@ -0,0 +1,69 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.25mm Structural @Prusa XL 5T 0.6", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.25", + "wall_loops": "2", + "top_shell_layers": "4", + "bottom_shell_layers": "3", + "top_shell_thickness": "0.9", + "bottom_shell_thickness": "0.6", + "sparse_infill_density": "20%", + "infill_anchor": "2.5", + "infill_anchor_max": "20", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.25", + "support_top_z_distance": "0.25", + "support_bottom_z_distance": "0.25", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.25", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_branch_diameter_double_wall": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "80", + "small_perimeter_speed": "45", + "outer_wall_speed": "45", + "sparse_infill_speed": "100", + "internal_solid_infill_speed": "95", + "top_surface_speed": "70", + "support_speed": "80", + "support_interface_speed": "75%", + "bridge_speed": "40", + "gap_infill_speed": "70", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "20", + "overhang_3_4_speed": "25", + "overhang_4_4_speed": "90%", + "default_acceleration": "2500", + "outer_wall_acceleration": "1500", + "inner_wall_acceleration": "2500", + "top_surface_acceleration": "1500", + "internal_solid_infill_acceleration": "3000", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1500", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.68", + "initial_layer_line_width": "0.68", + "inner_wall_line_width": "0.68", + "outer_wall_line_width": "0.68", + "sparse_infill_line_width": "0.68", + "internal_solid_infill_line_width": "0.68", + "top_surface_line_width": "0.55", + "support_line_width": "0.55", + "infill_wall_overlap": "15%", + "resolution": "0.0125", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.6 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.30mm Detail @Prusa XL 5T 0.8.json b/resources/profiles/Prusa/process/0.30mm Detail @Prusa XL 5T 0.8.json new file mode 100644 index 0000000000..70c48a8b27 --- /dev/null +++ b/resources/profiles/Prusa/process/0.30mm Detail @Prusa XL 5T 0.8.json @@ -0,0 +1,71 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.30mm Detail @Prusa XL 5T 0.8", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.3", + "wall_loops": "2", + "top_shell_layers": "4", + "bottom_shell_layers": "3", + "top_shell_thickness": "1.2", + "bottom_shell_thickness": "0.8", + "thick_bridges": "1", + "seam_position": "nearest", + "sparse_infill_density": "15%", + "sparse_infill_pattern": "crosshatch", + "infill_anchor": "2.5", + "infill_anchor_max": "20", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.2", + "support_top_z_distance": "0.25", + "support_bottom_z_distance": "0.25", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.35", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "70", + "small_perimeter_speed": "45", + "outer_wall_speed": "45", + "sparse_infill_speed": "100", + "internal_solid_infill_speed": "50", + "top_surface_speed": "35", + "support_speed": "65", + "support_interface_speed": "85%", + "bridge_speed": "22", + "gap_infill_speed": "40", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "20", + "overhang_3_4_speed": "25", + "overhang_4_4_speed": "80%", + "default_acceleration": "2000", + "outer_wall_acceleration": "1500", + "inner_wall_acceleration": "2000", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "3000", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1000", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.9", + "initial_layer_line_width": "1", + "inner_wall_line_width": "0.9", + "outer_wall_line_width": "0.9", + "sparse_infill_line_width": "0.9", + "internal_solid_infill_line_width": "0.9", + "top_surface_line_width": "0.7", + "support_line_width": "0.65", + "infill_wall_overlap": "15%", + "resolution": "0.0125", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.32mm Speed @Prusa XL 5T 0.6.json b/resources/profiles/Prusa/process/0.32mm Speed @Prusa XL 5T 0.6.json new file mode 100644 index 0000000000..bd6799243e --- /dev/null +++ b/resources/profiles/Prusa/process/0.32mm Speed @Prusa XL 5T 0.6.json @@ -0,0 +1,69 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.32mm Speed @Prusa XL 5T 0.6", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.32", + "wall_loops": "2", + "top_shell_layers": "4", + "bottom_shell_layers": "3", + "top_shell_thickness": "0.9", + "bottom_shell_thickness": "0.6", + "sparse_infill_density": "20%", + "infill_anchor": "2.5", + "infill_anchor_max": "20", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.25", + "support_top_z_distance": "0.25", + "support_bottom_z_distance": "0.25", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.25", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_branch_diameter_double_wall": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "70", + "small_perimeter_speed": "70", + "outer_wall_speed": "70", + "sparse_infill_speed": "100", + "internal_solid_infill_speed": "70", + "top_surface_speed": "60", + "support_speed": "70", + "support_interface_speed": "75%", + "bridge_speed": "40", + "gap_infill_speed": "65", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "20", + "overhang_3_4_speed": "25", + "overhang_4_4_speed": "50", + "default_acceleration": "2500", + "outer_wall_acceleration": "2500", + "inner_wall_acceleration": "3000", + "top_surface_acceleration": "1500", + "internal_solid_infill_acceleration": "3000", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1500", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.68", + "initial_layer_line_width": "0.68", + "inner_wall_line_width": "0.68", + "outer_wall_line_width": "0.68", + "sparse_infill_line_width": "0.68", + "internal_solid_infill_line_width": "0.68", + "top_surface_line_width": "0.55", + "support_line_width": "0.55", + "infill_wall_overlap": "15%", + "resolution": "0.0125", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.6 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.32mm Structural @Prusa XL 5T 0.6.json b/resources/profiles/Prusa/process/0.32mm Structural @Prusa XL 5T 0.6.json new file mode 100644 index 0000000000..78980e2136 --- /dev/null +++ b/resources/profiles/Prusa/process/0.32mm Structural @Prusa XL 5T 0.6.json @@ -0,0 +1,69 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.32mm Structural @Prusa XL 5T 0.6", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.32", + "wall_loops": "2", + "top_shell_layers": "5", + "bottom_shell_layers": "4", + "top_shell_thickness": "0.9", + "bottom_shell_thickness": "0.6", + "sparse_infill_density": "20%", + "infill_anchor": "2.5", + "infill_anchor_max": "20", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.25", + "support_top_z_distance": "0.25", + "support_bottom_z_distance": "0.25", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.25", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_branch_diameter_double_wall": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "70", + "small_perimeter_speed": "45", + "outer_wall_speed": "45", + "sparse_infill_speed": "70", + "internal_solid_infill_speed": "70", + "top_surface_speed": "70", + "support_speed": "80", + "support_interface_speed": "75%", + "bridge_speed": "40", + "gap_infill_speed": "70", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "20", + "overhang_3_4_speed": "25", + "overhang_4_4_speed": "90%", + "default_acceleration": "2500", + "outer_wall_acceleration": "1500", + "inner_wall_acceleration": "2500", + "top_surface_acceleration": "1500", + "internal_solid_infill_acceleration": "3000", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1500", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.68", + "initial_layer_line_width": "0.68", + "inner_wall_line_width": "0.68", + "outer_wall_line_width": "0.68", + "sparse_infill_line_width": "0.68", + "internal_solid_infill_line_width": "0.68", + "top_surface_line_width": "0.55", + "support_line_width": "0.55", + "infill_wall_overlap": "15%", + "resolution": "0.0125", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.6 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.40mm Quality @Prusa XL 5T 0.8.json b/resources/profiles/Prusa/process/0.40mm Quality @Prusa XL 5T 0.8.json new file mode 100644 index 0000000000..7e407ebb9a --- /dev/null +++ b/resources/profiles/Prusa/process/0.40mm Quality @Prusa XL 5T 0.8.json @@ -0,0 +1,71 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.40mm Quality @Prusa XL 5T 0.8", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.4", + "wall_loops": "2", + "top_shell_layers": "4", + "bottom_shell_layers": "3", + "top_shell_thickness": "1.2", + "bottom_shell_thickness": "0.8", + "thick_bridges": "1", + "seam_position": "nearest", + "sparse_infill_density": "15%", + "sparse_infill_pattern": "crosshatch", + "infill_anchor": "2.5", + "infill_anchor_max": "20", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.2", + "support_top_z_distance": "0.25", + "support_bottom_z_distance": "0.25", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.35", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "50", + "small_perimeter_speed": "45", + "outer_wall_speed": "45", + "sparse_infill_speed": "90", + "internal_solid_infill_speed": "45", + "top_surface_speed": "35", + "support_speed": "50", + "support_interface_speed": "85%", + "bridge_speed": "22", + "gap_infill_speed": "35", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "20", + "overhang_3_4_speed": "25", + "overhang_4_4_speed": "80%", + "default_acceleration": "2000", + "outer_wall_acceleration": "1500", + "inner_wall_acceleration": "2000", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "3000", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1000", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.9", + "initial_layer_line_width": "1", + "inner_wall_line_width": "0.9", + "outer_wall_line_width": "0.9", + "sparse_infill_line_width": "0.9", + "internal_solid_infill_line_width": "0.9", + "top_surface_line_width": "0.75", + "support_line_width": "0.65", + "infill_wall_overlap": "15%", + "resolution": "0.0125", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/0.55mm Draft @Prusa XL 5T 0.8.json b/resources/profiles/Prusa/process/0.55mm Draft @Prusa XL 5T 0.8.json new file mode 100644 index 0000000000..0e51ca2592 --- /dev/null +++ b/resources/profiles/Prusa/process/0.55mm Draft @Prusa XL 5T 0.8.json @@ -0,0 +1,71 @@ +{ + "type": "process", + "setting_id": "GP004", + "name": "0.55mm Draft @Prusa XL 5T 0.8", + "from": "system", + "instantiation": "true", + "inherits": "process_common_xl_5t", + "inital_layer_height": "0.2", + "layer_height": "0.55", + "wall_loops": "2", + "top_shell_layers": "4", + "bottom_shell_layers": "3", + "top_shell_thickness": "1.2", + "bottom_shell_thickness": "0.8", + "thick_bridges": "1", + "seam_position": "nearest", + "sparse_infill_density": "15%", + "sparse_infill_pattern": "crosshatch", + "infill_anchor": "2.5", + "infill_anchor_max": "20", + "brim_object_gap": "0.1", + "support_threshold_angle": "40", + "raft_first_layer_density": "80%", + "raft_first_layer_expansion": "3.5", + "raft_contact_distance": "0.2", + "support_top_z_distance": "0.25", + "support_bottom_z_distance": "0.25", + "support_base_pattern_spacing": "2", + "support_interface_top_layers": "5", + "support_interface_spacing": "0.35", + "support_object_xy_distance": "80%", + "tree_support_bramch_diameter_angle": "5", + "tree_support_tip_diameter": "0.8", + "inner_wall_speed": "40", + "small_perimeter_speed": "35", + "outer_wall_speed": "35", + "sparse_infill_speed": "55", + "internal_solid_infill_speed": "35", + "top_surface_speed": "30", + "support_speed": "35", + "support_interface_speed": "85%", + "bridge_speed": "22", + "gap_infill_speed": "30", + "overhang_1_4_speed": "15", + "overhang_2_4_speed": "20", + "overhang_3_4_speed": "25", + "overhang_4_4_speed": "80%", + "default_acceleration": "2000", + "outer_wall_acceleration": "1500", + "inner_wall_acceleration": "2000", + "top_surface_acceleration": "1000", + "internal_solid_infill_acceleration": "3000", + "sparse_infill_acceleration": "4000", + "bridge_acceleration": "1000", + "initial_layer_acceleration": "500", + "travel_acceleration": "5000", + "line_width": "0.9", + "initial_layer_line_width": "1", + "inner_wall_line_width": "1", + "outer_wall_line_width": "1", + "sparse_infill_line_width": "0.9", + "internal_solid_infill_line_width": "0.9", + "top_surface_line_width": "0.75", + "support_line_width": "0.65", + "infill_wall_overlap": "15%", + "resolution": "0.0125", + "elefant_foot_compensation": "0.2", + "compatible_printers": [ + "Prusa XL 5T 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/Prusa/process/process_common_xl_5t.json b/resources/profiles/Prusa/process/process_common_xl_5t.json new file mode 100644 index 0000000000..abcc096c6c --- /dev/null +++ b/resources/profiles/Prusa/process/process_common_xl_5t.json @@ -0,0 +1,11 @@ +{ + "type": "process", + "name": "process_common_xl_5t", + "from": "system", + "instantiation": "false", + "inherits": "process_common_xl", + "enable_prime_tower": "1", + "wipe_tower_cone_angle": "25", + "wipe_tower_extra_spacing": "150%", + "wipe_tower_rotation_angle": "90" +} \ No newline at end of file From 0b8515ed20c8817dc1d137c33cbc7f5fd211856d Mon Sep 17 00:00:00 2001 From: SoftFever Date: Sat, 13 Jul 2024 16:35:36 +0800 Subject: [PATCH 15/32] support Prusa XL --- src/libslic3r/GCode.cpp | 18 +++++++++--------- src/libslic3r/PrintConfig.cpp | 6 +++--- src/libslic3r/libslic3r.h | 3 +++ src/slic3r/GUI/Plater.cpp | 11 +++++------ src/slic3r/GUI/Tab.cpp | 2 +- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 0236125186..4deaa2671f 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1105,14 +1105,14 @@ void GCode::PlaceholderParserIntegration::init(const GCodeWriter &writer) const std::vector &extruders = writer.extruders(); if (! extruders.empty()) { this->num_extruders = extruders.back().id() + 1; - this->e_retracted.assign(num_extruders, 0); - this->e_restart_extra.assign(num_extruders, 0); + this->e_retracted.assign(MAXIMUM_EXTRUDER_NUMBER, 0); + this->e_restart_extra.assign(MAXIMUM_EXTRUDER_NUMBER, 0); this->opt_e_retracted = new ConfigOptionFloats(e_retracted); this->opt_e_restart_extra = new ConfigOptionFloats(e_restart_extra); this->output_config.set_key_value("e_retracted", this->opt_e_retracted); this->output_config.set_key_value("e_restart_extra", this->opt_e_restart_extra); if (! writer.config.use_relative_e_distances) { - e_position.assign(num_extruders, 0); + e_position.assign(MAXIMUM_EXTRUDER_NUMBER, 0); opt_e_position = new ConfigOptionFloats(e_position); this->output_config.set_key_value("e_position", opt_e_position); } @@ -1144,8 +1144,8 @@ void GCode::PlaceholderParserIntegration::update_from_gcodewriter(const GCodeWri if (this->num_extruders > 0) { const std::vector &extruders = writer.extruders(); assert(! extruders.empty() && num_extruders == extruders.back().id() + 1); - this->e_retracted.assign(num_extruders, 0); - this->e_restart_extra.assign(num_extruders, 0); + this->e_retracted.assign(MAXIMUM_EXTRUDER_NUMBER, 0); + this->e_restart_extra.assign(MAXIMUM_EXTRUDER_NUMBER, 0); this->opt_extruded_volume->values.assign(num_extruders, 0); this->opt_extruded_weight->values.assign(num_extruders, 0); double total_volume = 0.; @@ -1165,7 +1165,7 @@ void GCode::PlaceholderParserIntegration::update_from_gcodewriter(const GCodeWri opt_e_retracted->values = this->e_retracted; opt_e_restart_extra->values = this->e_restart_extra; if (! writer.config.use_relative_e_distances) { - this->e_position.assign(num_extruders, 0); + this->e_position.assign(MAXIMUM_EXTRUDER_NUMBER, 0); for (const Extruder &e : extruders) this->e_position[e.id()] = e.position(); this->opt_e_position->values = this->e_position; @@ -1179,11 +1179,11 @@ void GCode::PlaceholderParserIntegration::validate_output_vector_variables() if (this->opt_position->values.size() != 3) throw Slic3r::RuntimeError("\"position\" output variable must not be resized by the script."); if (this->num_extruders > 0) { - if (this->opt_e_position && this->opt_e_position->values.size() != this->num_extruders) + if (this->opt_e_position && this->opt_e_position->values.size() != MAXIMUM_EXTRUDER_NUMBER) throw Slic3r::RuntimeError("\"e_position\" output variable must not be resized by the script."); - if (this->opt_e_retracted->values.size() != this->num_extruders) + if (this->opt_e_retracted->values.size() != MAXIMUM_EXTRUDER_NUMBER) throw Slic3r::RuntimeError("\"e_retracted\" output variable must not be resized by the script."); - if (this->opt_e_restart_extra->values.size() != this->num_extruders) + if (this->opt_e_restart_extra->values.size() != MAXIMUM_EXTRUDER_NUMBER) throw Slic3r::RuntimeError("\"e_restart_extra\" output variable must not be resized by the script."); } } diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index d6f5cd278c..e738625f43 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -7310,9 +7310,9 @@ OtherSlicingStatesConfigDef::OtherSlicingStatesConfigDef() // def->label = L("Initial filament type"); // def->tooltip = L("String containing filament type of the first used extruder."); - // def = this->add("has_single_extruder_multi_material_priming", coBool); - // def->label = L("Has single extruder MM priming"); - // def->tooltip = L("Are the extra multi-material priming regions used in this print?"); + def = this->add("has_single_extruder_multi_material_priming", coBool); + def->label = L("Has single extruder MM priming"); + def->tooltip = L("Are the extra multi-material priming regions used in this print?"); new_def("initial_no_support_extruder", coInt, "Initial no support extruder", "Zero-based index of the first extruder used for printing without support. Same as initial_no_support_tool."); new_def("in_head_wrap_detect_zone", coBool, "In head wrap detect zone", "Indicates if the first layer overlaps with the head wrap zone."); diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h index 3e71ada5ab..798ea77d76 100644 --- a/src/libslic3r/libslic3r.h +++ b/src/libslic3r/libslic3r.h @@ -61,6 +61,9 @@ static constexpr double SCALING_FACTOR_INTERNAL = 0.000001; static constexpr double SCALING_FACTOR_INTERNAL_LARGE_PRINTER = 0.00001; static constexpr double LARGE_BED_THRESHOLD = 2147; +// Orca: maximum number of extruders is 64. For SEMM printers, it defines maximum filament number. +static constexpr size_t MAXIMUM_EXTRUDER_NUMBER = 64; + extern double SCALING_FACTOR; // for creating circles (for brim_ear) #define POLY_SIDES 24 diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 09e91840a2..2a8c729fcb 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -942,8 +942,8 @@ Sidebar::Sidebar(Plater *parent) ScalableButton* add_btn = new ScalableButton(p->m_panel_filament_title, wxID_ANY, "add_filament"); add_btn->SetToolTip(_L("Add one filament")); add_btn->Bind(wxEVT_BUTTON, [this, scrolled_sizer](wxCommandEvent& e){ - // Orca: limit filament choices to 64 - if (p->combos_filament.size() >= 64) + // Orca: limit filament choices to MAXIMUM_EXTRUDER_NUMBER + if (p->combos_filament.size() >= MAXIMUM_EXTRUDER_NUMBER) return; int filament_count = p->combos_filament.size() + 1; @@ -1642,8 +1642,7 @@ void Sidebar::on_filaments_change(size_t num_filaments) } void Sidebar::add_filament() { - // BBS: limit filament choices to 16 - if (p->combos_filament.size() >= 16) return; + if (p->combos_filament.size() >= MAXIMUM_EXTRUDER_NUMBER) return; wxColour new_col = Plater::get_next_color_for_filament(); add_custom_filament(new_col); } @@ -1667,7 +1666,7 @@ void Sidebar::delete_filament() { } void Sidebar::add_custom_filament(wxColour new_col) { - if (p->combos_filament.size() >= 16) return; + if (p->combos_filament.size() >= MAXIMUM_EXTRUDER_NUMBER) return; int filament_count = p->combos_filament.size() + 1; std::string new_color = new_col.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(); @@ -3763,7 +3762,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ int size = extruderIds.size() == 0 ? 0 : *(extruderIds.rbegin()); int filament_size = sidebar->combos_filament().size(); - while (filament_size < 16 && filament_size < size) { + while (filament_size < MAXIMUM_EXTRUDER_NUMBER && filament_size < size) { int filament_count = filament_size + 1; wxColour new_col = Plater::get_next_color_for_filament(); std::string new_color = new_col.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 0942714fac..fab5980700 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -4100,7 +4100,7 @@ if (is_marlin_flavor) def.label = L("Extruders"); def.tooltip = L("Number of extruders of the printer."); def.min = 1; - def.max = 256; + def.max = MAXIMUM_EXTRUDER_NUMBER; def.mode = comAdvanced; Option option(def, "extruders_count"); optgroup->append_single_option_line(option); From aec1a40795018082d7adfa91ba1ce10e3baca65e Mon Sep 17 00:00:00 2001 From: SoftFever Date: Sat, 13 Jul 2024 22:17:47 +0800 Subject: [PATCH 16/32] update/refactor/fix XL profiles --- resources/profiles/Prusa.json | 2 +- .../profiles/Prusa/Prusa XL 5T_cover.png | Bin 0 -> 88220 bytes .../Prusa/filament/fdm_filament_abs.json | 15 +- .../Prusa/filament/fdm_filament_asa.json | 1 + .../Prusa/filament/fdm_filament_pa.json | 1 + .../Prusa/filament/fdm_filament_pa11cf.json | 1 + .../Prusa/filament/fdm_filament_pc.json | 1 + .../Prusa/filament/fdm_filament_pccf.json | 1 + .../Prusa/filament/fdm_filament_pet.json | 1 + .../Prusa/filament/fdm_filament_pla.json | 1 + .../Prusa/filament/fdm_filament_pva.json | 1 + .../Prusa/filament/fdm_filament_pvb.json | 1 + .../Prusa/filament/fdm_filament_tpu.json | 1 + .../Prusa/machine/Prusa XL 0.25 nozzle.json | 101 +------------ .../Prusa/machine/Prusa XL 0.3 nozzle.json | 137 +++--------------- .../Prusa/machine/Prusa XL 0.4 nozzle.json | 135 +++-------------- .../Prusa/machine/Prusa XL 0.5 nozzle.json | 135 +++-------------- .../Prusa/machine/Prusa XL 0.6 nozzle.json | 135 +++-------------- .../Prusa/machine/Prusa XL 0.8 nozzle.json | 101 +------------ .../machine/Prusa XL 5T 0.25 nozzle.json | 2 +- .../Prusa/machine/Prusa XL 5T 0.3 nozzle.json | 2 +- .../Prusa/machine/Prusa XL 5T 0.4 nozzle.json | 2 +- .../Prusa/machine/Prusa XL 5T 0.5 nozzle.json | 2 +- .../Prusa/machine/Prusa XL 5T 0.6 nozzle.json | 2 +- .../Prusa/machine/Prusa XL 5T 0.8 nozzle.json | 2 +- .../profiles/Prusa/machine/Prusa XL 5T.json | 4 +- .../machine/fdm_machine_common_xl_5t.json | 11 +- .../Prusa/process/process_common_xl.json | 4 +- .../Prusa/process/process_common_xl_5t.json | 5 +- 29 files changed, 117 insertions(+), 690 deletions(-) create mode 100644 resources/profiles/Prusa/Prusa XL 5T_cover.png diff --git a/resources/profiles/Prusa.json b/resources/profiles/Prusa.json index 69e3e32e4e..62af7c6fa9 100644 --- a/resources/profiles/Prusa.json +++ b/resources/profiles/Prusa.json @@ -1,6 +1,6 @@ { "name": "Prusa", - "version": "02.01.01.10", + "version": "02.01.01.20", "force_update": "0", "description": "Prusa configurations", "machine_model_list": [ diff --git a/resources/profiles/Prusa/Prusa XL 5T_cover.png b/resources/profiles/Prusa/Prusa XL 5T_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..2a302857e610880246218c4f14a9a6bf0a052076 GIT binary patch literal 88220 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 60}\nG0 Z70 F480 ; move away (a bit more) in Z\nG0 X30 Y{print_bed_min[1]} F6000 ; move away in X/Y for higher bed temperatures\n{endif}\nM106 S100 ; cool off the nozzle\nM107 ; stop cooling off the nozzle - turn off the fan\n; MBL\nM84 E ; turn off E motor\nG29 P1 ; invalidate mbl & probe print area\nG29 P1 X30 Y0 W50 H20 C ; probe near purge place\nG29 P3.2 ; interpolate mbl probes\nG29 P3.13 ; extrapolate mbl outside probe area\nG29 A ; activate mbl\nM104 S[first_layer_temperature] ; set extruder temp\nG1 Z10 F720 ; move away in Z\nG0 X30 Y-8 F6000 ; move next to the sheet\n; wait for extruder temp\nM109 T0 S{first_layer_temperature[0]}\n;\n; purge\n;\nG92 E0 ; reset extruder position\nG0 X{(0 == 0 ? 30 : (0 == 1 ? 150 : (0 == 2 ? 210 : 330)))} Y{(0 < 4 ? -8 : -5.5)} ; move close to the sheet's edge\nG1 E{(filament_type[0] == \"FLEX\" ? 4 : 2)} F2400 ; deretraction after the initial one before nozzle cleaning\nG0 E10 X40 Z0.2 F500 ; purge\nG0 X70 E9 F800 ; purge\nG0 X{70 + 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{70 + 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG92 E0 ; reset extruder position", - "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\nG92 E0.0\n;[layer_z]", - "change_filament_gcode": "M600\nG1 E0.3 F1500 ; prime after color change", - "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", - "printer_notes": "Don't remove the following keywords! These keywords are used in the \"compatible printer\" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_MODEL_XLIS\nPG\nINPUT_SHAPER", - "scan_first_layer": "0", - "nozzle_type": "hardened_steel", - "auxiliary_fan": "0", - "thumbnails": [ - "16x16/QOI", - "313x173/QOI", - "440x240/QOI", - "480x240/QOI", - "640x480/PNG" - ] + "detraction_speed": "25" } diff --git a/resources/profiles/Prusa/machine/Prusa XL 0.3 nozzle.json b/resources/profiles/Prusa/machine/Prusa XL 0.3 nozzle.json index e83f1871a1..b678114c03 100644 --- a/resources/profiles/Prusa/machine/Prusa XL 0.3 nozzle.json +++ b/resources/profiles/Prusa/machine/Prusa XL 0.3 nozzle.json @@ -1,118 +1,21 @@ { - "type": "machine", - "setting_id": "GM003", - "name": "Prusa XL 0.3 nozzle", - "from": "system", - "instantiation": "true", - "inherits": "fdm_machine_common", - "gcode_flavor": "marlin2", - "printer_model": "Prusa XL", - "default_filament_profile": "Prusa Generic PLA @XL", - "default_print_profile": "0.20mm Speed @Prusa XL 0.3", - "extruder_clearance_radius": "67", - "extruder_clearance_height_to_rod": "21", - "extruder_clearance_height_to_lid": "21", - "printer_variant": "0.3", - "nozzle_diameter": [ - "0.3" - ], - "max_layer_height": "0.22", - "min_layer_height": "0.05", - "bed_exclude_area": [ - "0x0" - ], - "printable_area": [ - "0x0", - "360x0", - "360x360", - "0x360" - ], - "machine_max_acceleration_e": [ - "2500", - "2500" - ], - "machine_max_acceleration_extruding": [ - "4000", - "4000" - ], - "machine_max_acceleration_retracting": [ - "1200", - "1200" - ], - "machine_max_acceleration_x": [ - "7000", - "7000" - ], - "machine_max_acceleration_y": [ - "7000", - "7000" - ], - "machine_max_acceleration_z": [ - "200", - "200" - ], - "machine_max_acceleration_travel": [ - "3000", - "3000" - ], - "machine_max_speed_e": [ - "100", - "100" - ], - "machine_max_speed_x": [ - "400", - "400" - ], - "machine_max_speed_y": [ - "400", - "400" - ], - "machine_max_speed_z": [ - "12", - "12" - ], - "machine_max_jerk_e": [ - "10", - "10" - ], - "machine_max_jerk_x": [ - "8", - "8" - ], - "machine_max_jerk_y": [ - "8", - "8" - ], - "machine_max_jerk_z": [ - "2", - "2" - ], - "retraction_length": "0.7", - "retraction_speed": "35", - "detraction_speed": "25", - "retraction_minimum_travel": "1.5", - "retract_when_changing_layer": "1", - "wipe": "1", - "retract_before_wipe": "80%", - "retract_lift_below": "1.5", - "z_hop_types": "Auto Lift", - "host_type": "prusalink", - "printable_height": "360", - "machine_end_gcode": "{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F720{endif} ; Move bed down\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X6 Y350 F6000 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+100, max_print_height)} F300{endif} ; Move bed down\nM900 K0 ; reset LA\nM142 S36 ; reset heatbreak target temp\nM221 S100 ; reset flow percentage\nM84 ; disable motors\n; max_layer_z = [max_layer_z]", - "machine_pause_gcode": "M601", - "machine_start_gcode": "M17 ; enable steppers\nM862.3 P \"XL\" ; printer model check\nM115 U6.0.1+14848\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\n; set print area\nM555 X{first_layer_print_min[0]} Y{first_layer_print_min[1]} W{(first_layer_print_max[0]) - (first_layer_print_min[0])} H{(first_layer_print_max[1]) - (first_layer_print_min[1])}\n; inform about nozzle diameter\nM862.1 P[nozzle_diameter]\n; set & wait for bed and extruder temp for MBL\nM140 S[first_layer_bed_temperature] ; set bed temp\nM104 T0 S{((filament_notes[0]=~/.*HT_MBL10.*/) ? (first_layer_temperature[0] - 10) : (filament_type[0] == \"PC\" or filament_type[0] == \"PA\") ? (first_layer_temperature[0] - 25) : (filament_type[0] == \"FLEX\") ? 210 : (filament_type[0]=~/.*PET.*/) ? 175 : 170)} ; set extruder temp for bed leveling\nM109 T0 R{((filament_notes[0]=~/.*HT_MBL10.*/) ? (first_layer_temperature[0] - 10) : (filament_type[0] == \"PC\" or filament_type[0] == \"PA\") ? (first_layer_temperature[0] - 25) : (filament_type[0] == \"FLEX\") ? 210 : (filament_type[0]=~/.*PET.*/) ? 175 : 170)} ; wait for temp\n; home carriage, pick tool, home all\nG28 XY\nM84 E ; turn off E motor\nG28 Z\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nG29 G ; absorb heat\n; move to the nozzle cleanup area\nG1 X{(min(((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32))), first_layer_print_min[0])) + 32} Y{(min((first_layer_print_min[1] - 7), first_layer_print_min[1]))} Z{5} F4800\nM302 S160 ; lower cold extrusion limit to 160C\nG1 E{-(filament_type[0] == \"FLEX\" ? 4 : 2)} F2400 ; retraction for nozzle cleanup\n; nozzle cleanup\nM84 E ; turn off E motor\nG29 P9 X{((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)))} Y{(first_layer_print_min[1] - 7)} W{32} H{7}\nG0 Z10 F480 ; move away in Z\n{if first_layer_bed_temperature[0] > 60}\nG0 Z70 F480 ; move away (a bit more) in Z\nG0 X30 Y{print_bed_min[1]} F6000 ; move away in X/Y for higher bed temperatures\n{endif}\nM106 S100 ; cool off the nozzle\nM107 ; stop cooling off the nozzle - turn off the fan\n; MBL\nM84 E ; turn off E motor\nG29 P1 ; invalidate mbl & probe print area\nG29 P1 X30 Y0 W50 H20 C ; probe near purge place\nG29 P3.2 ; interpolate mbl probes\nG29 P3.13 ; extrapolate mbl outside probe area\nG29 A ; activate mbl\nM104 S[first_layer_temperature] ; set extruder temp\nG1 Z10 F720 ; move away in Z\nG0 X30 Y-8 F6000 ; move next to the sheet\n; wait for extruder temp\nM109 T0 S{first_layer_temperature[0]}\n;\n; purge\n;\nG92 E0 ; reset extruder position\nG0 X{(0 == 0 ? 30 : (0 == 1 ? 150 : (0 == 2 ? 210 : 330)))} Y{(0 < 4 ? -8 : -5.5)} ; move close to the sheet's edge\nG1 E{(filament_type[0] == \"FLEX\" ? 4 : 2)} F2400 ; deretraction after the initial one before nozzle cleaning\nG0 E10 X40 Z0.2 F500 ; purge\nG0 X70 E9 F800 ; purge\nG0 X{70 + 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{70 + 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG92 E0 ; reset extruder position", - "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\nG92 E0.0\n;[layer_z]", - "change_filament_gcode": "M600\nG1 E0.3 F1500 ; prime after color change", - "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", - "printer_notes": "Don't remove the following keywords! These keywords are used in the \"compatible printer\" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_MODEL_XLIS\nPG\nINPUT_SHAPER", - "scan_first_layer": "0", - "nozzle_type": "hardened_steel", - "auxiliary_fan": "0", - "thumbnails": [ - "16x16/QOI", - "313x173/QOI", - "440x240/QOI", - "480x240/QOI", - "640x480/PNG" - ] -} + "type": "machine", + "setting_id": "GM003", + "name": "Prusa XL 0.3 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_machine_common", + "gcode_flavor": "marlin2", + "printer_model": "Prusa XL", + "default_filament_profile": "Prusa Generic PLA @XL", + "default_print_profile": "0.20mm Speed @Prusa XL 0.3", + "printer_variant": "0.3", + "nozzle_diameter": [ + "0.3" + ], + "max_layer_height": "0.22", + "min_layer_height": "0.05", + "retraction_length": "0.7", + "retraction_speed": "35", + "detraction_speed": "25" +} \ No newline at end of file diff --git a/resources/profiles/Prusa/machine/Prusa XL 0.4 nozzle.json b/resources/profiles/Prusa/machine/Prusa XL 0.4 nozzle.json index cbb286aa5b..3bf1b6fa02 100644 --- a/resources/profiles/Prusa/machine/Prusa XL 0.4 nozzle.json +++ b/resources/profiles/Prusa/machine/Prusa XL 0.4 nozzle.json @@ -1,118 +1,19 @@ { - "type": "machine", - "setting_id": "GM003", - "name": "Prusa XL 0.4 nozzle", - "from": "system", - "instantiation": "true", - "inherits": "fdm_machine_common", - "gcode_flavor": "marlin2", - "printer_model": "Prusa XL", - "default_filament_profile": "Prusa Generic PLA @XL", - "default_print_profile": "0.20mm Speed @Prusa XL 0.4", - "extruder_clearance_radius": "67", - "extruder_clearance_height_to_rod": "21", - "extruder_clearance_height_to_lid": "21", - "printer_variant": "0.4", - "nozzle_diameter": [ - "0.4" - ], - "max_layer_height": "0.3", - "min_layer_height": "0.07", - "bed_exclude_area": [ - "0x0" - ], - "printable_area": [ - "0x0", - "360x0", - "360x360", - "0x360" - ], - "machine_max_acceleration_e": [ - "2500", - "2500" - ], - "machine_max_acceleration_extruding": [ - "4000", - "4000" - ], - "machine_max_acceleration_retracting": [ - "1200", - "1200" - ], - "machine_max_acceleration_x": [ - "7000", - "7000" - ], - "machine_max_acceleration_y": [ - "7000", - "7000" - ], - "machine_max_acceleration_z": [ - "200", - "200" - ], - "machine_max_acceleration_travel": [ - "5000", - "5000" - ], - "machine_max_speed_e": [ - "100", - "100" - ], - "machine_max_speed_x": [ - "400", - "400" - ], - "machine_max_speed_y": [ - "400", - "400" - ], - "machine_max_speed_z": [ - "12", - "12" - ], - "machine_max_jerk_e": [ - "10", - "10" - ], - "machine_max_jerk_x": [ - "8", - "8" - ], - "machine_max_jerk_y": [ - "8", - "8" - ], - "machine_max_jerk_z": [ - "2", - "2" - ], - "retraction_length": "0.8", - "retraction_speed": "35", - "detraction_speed": "25", - "retraction_minimum_travel": "1.5", - "retract_when_changing_layer": "1", - "wipe": "1", - "retract_before_wipe": "80%", - "retract_lift_below": "1.5", - "z_hop_types": "Auto Lift", - "host_type": "prusalink", - "printable_height": "360", - "machine_end_gcode": "{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F720{endif} ; Move bed down\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X6 Y350 F6000 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+100, max_print_height)} F300{endif} ; Move bed down\nM900 K0 ; reset LA\nM142 S36 ; reset heatbreak target temp\nM221 S100 ; reset flow percentage\nM84 ; disable motors\n; max_layer_z = [max_layer_z]", - "machine_pause_gcode": "M601", - "machine_start_gcode": "M17 ; enable steppers\nM862.3 P \"XL\" ; printer model check\nM115 U6.0.1+14848\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\n; set print area\nM555 X{first_layer_print_min[0]} Y{first_layer_print_min[1]} W{(first_layer_print_max[0]) - (first_layer_print_min[0])} H{(first_layer_print_max[1]) - (first_layer_print_min[1])}\n; inform about nozzle diameter\nM862.1 P[nozzle_diameter]\n; set & wait for bed and extruder temp for MBL\nM140 S[first_layer_bed_temperature] ; set bed temp\nM104 T0 S{((filament_notes[0]=~/.*HT_MBL10.*/) ? (first_layer_temperature[0] - 10) : (filament_type[0] == \"PC\" or filament_type[0] == \"PA\") ? (first_layer_temperature[0] - 25) : (filament_type[0] == \"FLEX\") ? 210 : (filament_type[0]=~/.*PET.*/) ? 175 : 170)} ; set extruder temp for bed leveling\nM109 T0 R{((filament_notes[0]=~/.*HT_MBL10.*/) ? (first_layer_temperature[0] - 10) : (filament_type[0] == \"PC\" or filament_type[0] == \"PA\") ? (first_layer_temperature[0] - 25) : (filament_type[0] == \"FLEX\") ? 210 : (filament_type[0]=~/.*PET.*/) ? 175 : 170)} ; wait for temp\n; home carriage, pick tool, home all\nG28 XY\nM84 E ; turn off E motor\nG28 Z\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nG29 G ; absorb heat\n; move to the nozzle cleanup area\nG1 X{(min(((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32))), first_layer_print_min[0])) + 32} Y{(min((first_layer_print_min[1] - 7), first_layer_print_min[1]))} Z{5} F4800\nM302 S160 ; lower cold extrusion limit to 160C\nG1 E{-(filament_type[0] == \"FLEX\" ? 4 : 2)} F2400 ; retraction for nozzle cleanup\n; nozzle cleanup\nM84 E ; turn off E motor\nG29 P9 X{((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)))} Y{(first_layer_print_min[1] - 7)} W{32} H{7}\nG0 Z10 F480 ; move away in Z\n{if first_layer_bed_temperature[0] > 60}\nG0 Z70 F480 ; move away (a bit more) in Z\nG0 X30 Y{print_bed_min[1]} F6000 ; move away in X/Y for higher bed temperatures\n{endif}\nM106 S100 ; cool off the nozzle\nM107 ; stop cooling off the nozzle - turn off the fan\n; MBL\nM84 E ; turn off E motor\nG29 P1 ; invalidate mbl & probe print area\nG29 P1 X30 Y0 W50 H20 C ; probe near purge place\nG29 P3.2 ; interpolate mbl probes\nG29 P3.13 ; extrapolate mbl outside probe area\nG29 A ; activate mbl\nM104 S[first_layer_temperature] ; set extruder temp\nG1 Z10 F720 ; move away in Z\nG0 X30 Y-8 F6000 ; move next to the sheet\n; wait for extruder temp\nM109 T0 S{first_layer_temperature[0]}\n;\n; purge\n;\nG92 E0 ; reset extruder position\nG0 X{(0 == 0 ? 30 : (0 == 1 ? 150 : (0 == 2 ? 210 : 330)))} Y{(0 < 4 ? -8 : -5.5)} ; move close to the sheet's edge\nG1 E{(filament_type[0] == \"FLEX\" ? 4 : 2)} F2400 ; deretraction after the initial one before nozzle cleaning\nG0 E10 X40 Z0.2 F500 ; purge\nG0 X70 E9 F800 ; purge\nG0 X{70 + 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{70 + 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG92 E0 ; reset extruder position", - "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\nG92 E0.0\n;[layer_z]", - "change_filament_gcode": "M600\nG1 E0.3 F1500 ; prime after color change", - "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", - "printer_notes": "Don't remove the following keywords! These keywords are used in the \"compatible printer\" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_MODEL_XLIS\nPG\nINPUT_SHAPER", - "scan_first_layer": "0", - "nozzle_type": "hardened_steel", - "auxiliary_fan": "0", - "thumbnails": [ - "16x16/QOI", - "313x173/QOI", - "440x240/QOI", - "480x240/QOI", - "640x480/PNG" - ] -} + "type": "machine", + "setting_id": "GM003", + "name": "Prusa XL 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_machine_common_xl", + "gcode_flavor": "marlin2", + "printer_model": "Prusa XL", + "default_filament_profile": "Prusa Generic PLA @XL", + "default_print_profile": "0.20mm Speed @Prusa XL 0.4", + "printer_variant": "0.4", + "nozzle_diameter": [ + "0.4" + ], + "max_layer_height": "0.3", + "min_layer_height": "0.07", + "retraction_length": "0.8" +} \ No newline at end of file diff --git a/resources/profiles/Prusa/machine/Prusa XL 0.5 nozzle.json b/resources/profiles/Prusa/machine/Prusa XL 0.5 nozzle.json index 937e88f016..3f65ffc759 100644 --- a/resources/profiles/Prusa/machine/Prusa XL 0.5 nozzle.json +++ b/resources/profiles/Prusa/machine/Prusa XL 0.5 nozzle.json @@ -1,118 +1,19 @@ { - "type": "machine", - "setting_id": "GM003", - "name": "Prusa XL 0.5 nozzle", - "from": "system", - "instantiation": "true", - "inherits": "fdm_machine_common", - "gcode_flavor": "marlin2", - "printer_model": "Prusa XL", - "default_filament_profile": "Prusa Generic PLA @XL", - "default_print_profile": "0.25mm Speed @Prusa XL 0.5", - "extruder_clearance_radius": "67", - "extruder_clearance_height_to_rod": "21", - "extruder_clearance_height_to_lid": "21", - "printer_variant": "0.5", - "nozzle_diameter": [ - "0.5" - ], - "max_layer_height": "0.32", - "min_layer_height": "0.07", - "bed_exclude_area": [ - "0x0" - ], - "printable_area": [ - "0x0", - "360x0", - "360x360", - "0x360" - ], - "machine_max_acceleration_e": [ - "2500", - "2500" - ], - "machine_max_acceleration_extruding": [ - "4000", - "4000" - ], - "machine_max_acceleration_retracting": [ - "1200", - "1200" - ], - "machine_max_acceleration_x": [ - "7000", - "7000" - ], - "machine_max_acceleration_y": [ - "7000", - "7000" - ], - "machine_max_acceleration_z": [ - "200", - "200" - ], - "machine_max_acceleration_travel": [ - "5000", - "5000" - ], - "machine_max_speed_e": [ - "100", - "100" - ], - "machine_max_speed_x": [ - "400", - "400" - ], - "machine_max_speed_y": [ - "400", - "400" - ], - "machine_max_speed_z": [ - "12", - "12" - ], - "machine_max_jerk_e": [ - "10", - "10" - ], - "machine_max_jerk_x": [ - "8", - "8" - ], - "machine_max_jerk_y": [ - "8", - "8" - ], - "machine_max_jerk_z": [ - "2", - "2" - ], - "retraction_length": "0.7", - "retraction_speed": "35", - "detraction_speed": "25", - "retraction_minimum_travel": "1.5", - "retract_when_changing_layer": "1", - "wipe": "1", - "retract_before_wipe": "80%", - "retract_lift_below": "1.5", - "z_hop_types": "Auto Lift", - "host_type": "prusalink", - "printable_height": "360", - "machine_end_gcode": "{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F720{endif} ; Move bed down\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X6 Y350 F6000 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+100, max_print_height)} F300{endif} ; Move bed down\nM900 K0 ; reset LA\nM142 S36 ; reset heatbreak target temp\nM221 S100 ; reset flow percentage\nM84 ; disable motors\n; max_layer_z = [max_layer_z]", - "machine_pause_gcode": "M601", - "machine_start_gcode": "M17 ; enable steppers\nM862.3 P \"XL\" ; printer model check\nM115 U6.0.1+14848\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\n; set print area\nM555 X{first_layer_print_min[0]} Y{first_layer_print_min[1]} W{(first_layer_print_max[0]) - (first_layer_print_min[0])} H{(first_layer_print_max[1]) - (first_layer_print_min[1])}\n; inform about nozzle diameter\nM862.1 P[nozzle_diameter]\n; set & wait for bed and extruder temp for MBL\nM140 S[first_layer_bed_temperature] ; set bed temp\nM104 T0 S{((filament_notes[0]=~/.*HT_MBL10.*/) ? (first_layer_temperature[0] - 10) : (filament_type[0] == \"PC\" or filament_type[0] == \"PA\") ? (first_layer_temperature[0] - 25) : (filament_type[0] == \"FLEX\") ? 210 : (filament_type[0]=~/.*PET.*/) ? 175 : 170)} ; set extruder temp for bed leveling\nM109 T0 R{((filament_notes[0]=~/.*HT_MBL10.*/) ? (first_layer_temperature[0] - 10) : (filament_type[0] == \"PC\" or filament_type[0] == \"PA\") ? (first_layer_temperature[0] - 25) : (filament_type[0] == \"FLEX\") ? 210 : (filament_type[0]=~/.*PET.*/) ? 175 : 170)} ; wait for temp\n; home carriage, pick tool, home all\nG28 XY\nM84 E ; turn off E motor\nG28 Z\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nG29 G ; absorb heat\n; move to the nozzle cleanup area\nG1 X{(min(((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32))), first_layer_print_min[0])) + 32} Y{(min((first_layer_print_min[1] - 7), first_layer_print_min[1]))} Z{5} F4800\nM302 S160 ; lower cold extrusion limit to 160C\nG1 E{-(filament_type[0] == \"FLEX\" ? 4 : 2)} F2400 ; retraction for nozzle cleanup\n; nozzle cleanup\nM84 E ; turn off E motor\nG29 P9 X{((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)))} Y{(first_layer_print_min[1] - 7)} W{32} H{7}\nG0 Z10 F480 ; move away in Z\n{if first_layer_bed_temperature[0] > 60}\nG0 Z70 F480 ; move away (a bit more) in Z\nG0 X30 Y{print_bed_min[1]} F6000 ; move away in X/Y for higher bed temperatures\n{endif}\nM106 S100 ; cool off the nozzle\nM107 ; stop cooling off the nozzle - turn off the fan\n; MBL\nM84 E ; turn off E motor\nG29 P1 ; invalidate mbl & probe print area\nG29 P1 X30 Y0 W50 H20 C ; probe near purge place\nG29 P3.2 ; interpolate mbl probes\nG29 P3.13 ; extrapolate mbl outside probe area\nG29 A ; activate mbl\nM104 S[first_layer_temperature] ; set extruder temp\nG1 Z10 F720 ; move away in Z\nG0 X30 Y-8 F6000 ; move next to the sheet\n; wait for extruder temp\nM109 T0 S{first_layer_temperature[0]}\n;\n; purge\n;\nG92 E0 ; reset extruder position\nG0 X{(0 == 0 ? 30 : (0 == 1 ? 150 : (0 == 2 ? 210 : 330)))} Y{(0 < 4 ? -8 : -5.5)} ; move close to the sheet's edge\nG1 E{(filament_type[0] == \"FLEX\" ? 4 : 2)} F2400 ; deretraction after the initial one before nozzle cleaning\nG0 E10 X40 Z0.2 F500 ; purge\nG0 X70 E9 F800 ; purge\nG0 X{70 + 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{70 + 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG92 E0 ; reset extruder position", - "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\nG92 E0.0\n;[layer_z]", - "change_filament_gcode": "M600\nG1 E0.3 F1500 ; prime after color change", - "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", - "printer_notes": "Don't remove the following keywords! These keywords are used in the \"compatible printer\" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_MODEL_XLIS\nPG\nINPUT_SHAPER", - "scan_first_layer": "0", - "nozzle_type": "hardened_steel", - "auxiliary_fan": "0", - "thumbnails": [ - "16x16/QOI", - "313x173/QOI", - "440x240/QOI", - "480x240/QOI", - "640x480/PNG" - ] -} + "type": "machine", + "setting_id": "GM003", + "name": "Prusa XL 0.5 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_machine_common_xl", + "gcode_flavor": "marlin2", + "printer_model": "Prusa XL", + "default_filament_profile": "Prusa Generic PLA @XL", + "default_print_profile": "0.25mm Speed @Prusa XL 0.5", + "printer_variant": "0.5", + "nozzle_diameter": [ + "0.5" + ], + "max_layer_height": "0.32", + "min_layer_height": "0.07", + "retraction_length": "0.7" +} \ No newline at end of file diff --git a/resources/profiles/Prusa/machine/Prusa XL 0.6 nozzle.json b/resources/profiles/Prusa/machine/Prusa XL 0.6 nozzle.json index e0d47b46c6..1239ddb447 100644 --- a/resources/profiles/Prusa/machine/Prusa XL 0.6 nozzle.json +++ b/resources/profiles/Prusa/machine/Prusa XL 0.6 nozzle.json @@ -1,118 +1,19 @@ { - "type": "machine", - "setting_id": "GM003", - "name": "Prusa XL 0.6 nozzle", - "from": "system", - "instantiation": "true", - "inherits": "fdm_machine_common", - "gcode_flavor": "marlin2", - "printer_model": "Prusa XL", - "default_filament_profile": "Prusa Generic PLA @XL", - "default_print_profile": "0.32mm Speed @Prusa XL 0.6", - "extruder_clearance_radius": "67", - "extruder_clearance_height_to_rod": "21", - "extruder_clearance_height_to_lid": "21", - "printer_variant": "0.6", - "nozzle_diameter": [ - "0.6" - ], - "max_layer_height": "0.4", - "min_layer_height": "0.15", - "bed_exclude_area": [ - "0x0" - ], - "printable_area": [ - "0x0", - "360x0", - "360x360", - "0x360" - ], - "machine_max_acceleration_e": [ - "2500", - "2500" - ], - "machine_max_acceleration_extruding": [ - "4000", - "4000" - ], - "machine_max_acceleration_retracting": [ - "1200", - "1200" - ], - "machine_max_acceleration_x": [ - "7000", - "7000" - ], - "machine_max_acceleration_y": [ - "7000", - "7000" - ], - "machine_max_acceleration_z": [ - "200", - "200" - ], - "machine_max_acceleration_travel": [ - "5000", - "5000" - ], - "machine_max_speed_e": [ - "100", - "100" - ], - "machine_max_speed_x": [ - "400", - "400" - ], - "machine_max_speed_y": [ - "400", - "400" - ], - "machine_max_speed_z": [ - "12", - "12" - ], - "machine_max_jerk_e": [ - "10", - "10" - ], - "machine_max_jerk_x": [ - "8", - "8" - ], - "machine_max_jerk_y": [ - "8", - "8" - ], - "machine_max_jerk_z": [ - "2", - "2" - ], - "retraction_length": "0.7", - "retraction_speed": "35", - "detraction_speed": "25", - "retraction_minimum_travel": "1.5", - "retract_when_changing_layer": "1", - "wipe": "1", - "retract_before_wipe": "0%", - "retract_lift_below": "1.5", - "z_hop_types": "Auto Lift", - "host_type": "prusalink", - "printable_height": "360", - "machine_end_gcode": "{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F720{endif} ; Move bed down\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X6 Y350 F6000 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+100, max_print_height)} F300{endif} ; Move bed down\nM900 K0 ; reset LA\nM142 S36 ; reset heatbreak target temp\nM221 S100 ; reset flow percentage\nM84 ; disable motors\n; max_layer_z = [max_layer_z]", - "machine_pause_gcode": "M601", - "machine_start_gcode": "M17 ; enable steppers\nM862.3 P \"XL\" ; printer model check\nM115 U6.0.1+14848\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\n; set print area\nM555 X{first_layer_print_min[0]} Y{first_layer_print_min[1]} W{(first_layer_print_max[0]) - (first_layer_print_min[0])} H{(first_layer_print_max[1]) - (first_layer_print_min[1])}\n; inform about nozzle diameter\nM862.1 P[nozzle_diameter]\n; set & wait for bed and extruder temp for MBL\nM140 S[first_layer_bed_temperature] ; set bed temp\nM104 T0 S{((filament_notes[0]=~/.*HT_MBL10.*/) ? (first_layer_temperature[0] - 10) : (filament_type[0] == \"PC\" or filament_type[0] == \"PA\") ? (first_layer_temperature[0] - 25) : (filament_type[0] == \"FLEX\") ? 210 : (filament_type[0]=~/.*PET.*/) ? 175 : 170)} ; set extruder temp for bed leveling\nM109 T0 R{((filament_notes[0]=~/.*HT_MBL10.*/) ? (first_layer_temperature[0] - 10) : (filament_type[0] == \"PC\" or filament_type[0] == \"PA\") ? (first_layer_temperature[0] - 25) : (filament_type[0] == \"FLEX\") ? 210 : (filament_type[0]=~/.*PET.*/) ? 175 : 170)} ; wait for temp\n; home carriage, pick tool, home all\nG28 XY\nM84 E ; turn off E motor\nG28 Z\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nG29 G ; absorb heat\n; move to the nozzle cleanup area\nG1 X{(min(((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32))), first_layer_print_min[0])) + 32} Y{(min((first_layer_print_min[1] - 7), first_layer_print_min[1]))} Z{5} F4800\nM302 S160 ; lower cold extrusion limit to 160C\nG1 E{-(filament_type[0] == \"FLEX\" ? 4 : 2)} F2400 ; retraction for nozzle cleanup\n; nozzle cleanup\nM84 E ; turn off E motor\nG29 P9 X{((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)))} Y{(first_layer_print_min[1] - 7)} W{32} H{7}\nG0 Z10 F480 ; move away in Z\n{if first_layer_bed_temperature[0] > 60}\nG0 Z70 F480 ; move away (a bit more) in Z\nG0 X30 Y{print_bed_min[1]} F6000 ; move away in X/Y for higher bed temperatures\n{endif}\nM106 S100 ; cool off the nozzle\nM107 ; stop cooling off the nozzle - turn off the fan\n; MBL\nM84 E ; turn off E motor\nG29 P1 ; invalidate mbl & probe print area\nG29 P1 X30 Y0 W50 H20 C ; probe near purge place\nG29 P3.2 ; interpolate mbl probes\nG29 P3.13 ; extrapolate mbl outside probe area\nG29 A ; activate mbl\nM104 S[first_layer_temperature] ; set extruder temp\nG1 Z10 F720 ; move away in Z\nG0 X30 Y-8 F6000 ; move next to the sheet\n; wait for extruder temp\nM109 T0 S{first_layer_temperature[0]}\n;\n; purge\n;\nG92 E0 ; reset extruder position\nG0 X{(0 == 0 ? 30 : (0 == 1 ? 150 : (0 == 2 ? 210 : 330)))} Y{(0 < 4 ? -8 : -5.5)} ; move close to the sheet's edge\nG1 E{(filament_type[0] == \"FLEX\" ? 4 : 2)} F2400 ; deretraction after the initial one before nozzle cleaning\nG0 E10 X40 Z0.2 F500 ; purge\nG0 X70 E9 F800 ; purge\nG0 X{70 + 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{70 + 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG92 E0 ; reset extruder position", - "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\nG92 E0.0\n;[layer_z]", - "change_filament_gcode": "M600\nG1 E0.3 F1500 ; prime after color change", - "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", - "printer_notes": "Don't remove the following keywords! These keywords are used in the \"compatible printer\" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_MODEL_XLIS\nPG\nINPUT_SHAPER", - "scan_first_layer": "0", - "nozzle_type": "hardened_steel", - "auxiliary_fan": "0", - "thumbnails": [ - "16x16/QOI", - "313x173/QOI", - "440x240/QOI", - "480x240/QOI", - "640x480/PNG" - ] -} + "type": "machine", + "setting_id": "GM003", + "name": "Prusa XL 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_machine_common_xl", + "gcode_flavor": "marlin2", + "printer_model": "Prusa XL", + "default_filament_profile": "Prusa Generic PLA @XL", + "default_print_profile": "0.32mm Speed @Prusa XL 0.6", + "printer_variant": "0.6", + "nozzle_diameter": [ + "0.6" + ], + "max_layer_height": "0.4", + "min_layer_height": "0.15", + "retraction_length": "0.7" +} \ No newline at end of file diff --git a/resources/profiles/Prusa/machine/Prusa XL 0.8 nozzle.json b/resources/profiles/Prusa/machine/Prusa XL 0.8 nozzle.json index 85c1631bcb..b0a2468a68 100644 --- a/resources/profiles/Prusa/machine/Prusa XL 0.8 nozzle.json +++ b/resources/profiles/Prusa/machine/Prusa XL 0.8 nozzle.json @@ -4,115 +4,18 @@ "name": "Prusa XL 0.8 nozzle", "from": "system", "instantiation": "true", - "inherits": "fdm_machine_common", + "inherits": "fdm_machine_common_xl", "gcode_flavor": "marlin2", "printer_model": "Prusa XL", "default_filament_profile": "Prusa Generic PLA @XL", "default_print_profile": "0.40mm Quality @Prusa XL 0.8", - "extruder_clearance_radius": "67", - "extruder_clearance_height_to_rod": "21", - "extruder_clearance_height_to_lid": "21", "printer_variant": "0.8", "nozzle_diameter": [ "0.8" ], "max_layer_height": "0.6", "min_layer_height": "0.2", - "bed_exclude_area": [ - "0x0" - ], - "printable_area": [ - "0x0", - "360x0", - "360x360", - "0x360" - ], - "machine_max_acceleration_e": [ - "2500", - "2500" - ], - "machine_max_acceleration_extruding": [ - "4000", - "4000" - ], - "machine_max_acceleration_retracting": [ - "1200", - "1200" - ], - "machine_max_acceleration_x": [ - "7000", - "7000" - ], - "machine_max_acceleration_y": [ - "7000", - "7000" - ], - "machine_max_acceleration_z": [ - "200", - "200" - ], - "machine_max_acceleration_travel": [ - "5000", - "5000" - ], - "machine_max_speed_e": [ - "100", - "100" - ], - "machine_max_speed_x": [ - "400", - "400" - ], - "machine_max_speed_y": [ - "400", - "400" - ], - "machine_max_speed_z": [ - "12", - "12" - ], - "machine_max_jerk_e": [ - "10", - "10" - ], - "machine_max_jerk_x": [ - "8", - "8" - ], - "machine_max_jerk_y": [ - "8", - "8" - ], - "machine_max_jerk_z": [ - "2", - "2" - ], "retraction_length": "0.6", "retraction_speed": "25", - "detraction_speed": "15", - "retraction_minimum_travel": "1.5", - "retract_when_changing_layer": "1", - "wipe": "1", - "retract_before_wipe": "50%", - "retract_lift_below": "1.5", - "z_hop_types": "Auto Lift", - "host_type": "prusalink", - "printable_height": "360", - "machine_end_gcode": "{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F720{endif} ; Move bed down\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X6 Y350 F6000 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+100, max_print_height)} F300{endif} ; Move bed down\nM900 K0 ; reset LA\nM142 S36 ; reset heatbreak target temp\nM221 S100 ; reset flow percentage\nM84 ; disable motors\n; max_layer_z = [max_layer_z]", - "machine_pause_gcode": "M601", - "machine_start_gcode": "M17 ; enable steppers\nM862.3 P \"XL\" ; printer model check\nM115 U6.0.1+14848\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\n; set print area\nM555 X{first_layer_print_min[0]} Y{first_layer_print_min[1]} W{(first_layer_print_max[0]) - (first_layer_print_min[0])} H{(first_layer_print_max[1]) - (first_layer_print_min[1])}\n; inform about nozzle diameter\nM862.1 P[nozzle_diameter]\n; set & wait for bed and extruder temp for MBL\nM140 S[first_layer_bed_temperature] ; set bed temp\nM104 T0 S{((filament_notes[0]=~/.*HT_MBL10.*/) ? (first_layer_temperature[0] - 10) : (filament_type[0] == \"PC\" or filament_type[0] == \"PA\") ? (first_layer_temperature[0] - 25) : (filament_type[0] == \"FLEX\") ? 210 : (filament_type[0]=~/.*PET.*/) ? 175 : 170)} ; set extruder temp for bed leveling\nM109 T0 R{((filament_notes[0]=~/.*HT_MBL10.*/) ? (first_layer_temperature[0] - 10) : (filament_type[0] == \"PC\" or filament_type[0] == \"PA\") ? (first_layer_temperature[0] - 25) : (filament_type[0] == \"FLEX\") ? 210 : (filament_type[0]=~/.*PET.*/) ? 175 : 170)} ; wait for temp\n; home carriage, pick tool, home all\nG28 XY\nM84 E ; turn off E motor\nG28 Z\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nG29 G ; absorb heat\n; move to the nozzle cleanup area\nG1 X{(min(((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32))), first_layer_print_min[0])) + 32} Y{(min((first_layer_print_min[1] - 7), first_layer_print_min[1]))} Z{5} F4800\nM302 S160 ; lower cold extrusion limit to 160C\nG1 E{-(filament_type[0] == \"FLEX\" ? 4 : 2)} F2400 ; retraction for nozzle cleanup\n; nozzle cleanup\nM84 E ; turn off E motor\nG29 P9 X{((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)))} Y{(first_layer_print_min[1] - 7)} W{32} H{7}\nG0 Z10 F480 ; move away in Z\n{if first_layer_bed_temperature[0] > 60}\nG0 Z70 F480 ; move away (a bit more) in Z\nG0 X30 Y{print_bed_min[1]} F6000 ; move away in X/Y for higher bed temperatures\n{endif}\nM106 S100 ; cool off the nozzle\nM107 ; stop cooling off the nozzle - turn off the fan\n; MBL\nM84 E ; turn off E motor\nG29 P1 ; invalidate mbl & probe print area\nG29 P1 X30 Y0 W50 H20 C ; probe near purge place\nG29 P3.2 ; interpolate mbl probes\nG29 P3.13 ; extrapolate mbl outside probe area\nG29 A ; activate mbl\nM104 S[first_layer_temperature] ; set extruder temp\nG1 Z10 F720 ; move away in Z\nG0 X30 Y-8 F6000 ; move next to the sheet\n; wait for extruder temp\nM109 T0 S{first_layer_temperature[0]}\n;\n; purge\n;\nG92 E0 ; reset extruder position\nG0 X{(0 == 0 ? 30 : (0 == 1 ? 150 : (0 == 2 ? 210 : 330)))} Y{(0 < 4 ? -8 : -5.5)} ; move close to the sheet's edge\nG1 E{(filament_type[0] == \"FLEX\" ? 4 : 2)} F2400 ; deretraction after the initial one before nozzle cleaning\nG0 E10 X40 Z0.2 F500 ; purge\nG0 X70 E9 F800 ; purge\nG0 X{70 + 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{70 + 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG92 E0 ; reset extruder position", - "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\nG92 E0.0\n;[layer_z]", - "change_filament_gcode": "M600\nG1 E0.3 F1500 ; prime after color change", - "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", - "printer_notes": "Don't remove the following keywords! These keywords are used in the \"compatible printer\" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_MODEL_XLIS\nPG\nINPUT_SHAPER", - "scan_first_layer": "0", - "nozzle_type": "hardened_steel", - "auxiliary_fan": "0", - "thumbnails": [ - "16x16/QOI", - "313x173/QOI", - "440x240/QOI", - "480x240/QOI", - "640x480/PNG" - ] + "detraction_speed": "15" } diff --git a/resources/profiles/Prusa/machine/Prusa XL 5T 0.25 nozzle.json b/resources/profiles/Prusa/machine/Prusa XL 5T 0.25 nozzle.json index 52343e9ed1..2fc6b341b5 100644 --- a/resources/profiles/Prusa/machine/Prusa XL 5T 0.25 nozzle.json +++ b/resources/profiles/Prusa/machine/Prusa XL 5T 0.25 nozzle.json @@ -1,6 +1,6 @@ { "type": "machine", - "setting_id": "GM003", + "setting_id": "GM_PRUSA_007", "name": "Prusa XL 5T 0.25 nozzle", "from": "system", "instantiation": "true", diff --git a/resources/profiles/Prusa/machine/Prusa XL 5T 0.3 nozzle.json b/resources/profiles/Prusa/machine/Prusa XL 5T 0.3 nozzle.json index 3dc0db1532..a495d26349 100644 --- a/resources/profiles/Prusa/machine/Prusa XL 5T 0.3 nozzle.json +++ b/resources/profiles/Prusa/machine/Prusa XL 5T 0.3 nozzle.json @@ -1,6 +1,6 @@ { "type": "machine", - "setting_id": "GM003", + "setting_id": "GM_PRUSA_001", "name": "Prusa XL 5T 0.3 nozzle", "from": "system", "instantiation": "true", diff --git a/resources/profiles/Prusa/machine/Prusa XL 5T 0.4 nozzle.json b/resources/profiles/Prusa/machine/Prusa XL 5T 0.4 nozzle.json index 5e7f21ed7e..4dbd7d9b22 100644 --- a/resources/profiles/Prusa/machine/Prusa XL 5T 0.4 nozzle.json +++ b/resources/profiles/Prusa/machine/Prusa XL 5T 0.4 nozzle.json @@ -1,6 +1,6 @@ { "type": "machine", - "setting_id": "GM003", + "setting_id": "GM_PRUSA_002", "name": "Prusa XL 5T 0.4 nozzle", "from": "system", "instantiation": "true", diff --git a/resources/profiles/Prusa/machine/Prusa XL 5T 0.5 nozzle.json b/resources/profiles/Prusa/machine/Prusa XL 5T 0.5 nozzle.json index 9360cfcd8f..69e355ea2f 100644 --- a/resources/profiles/Prusa/machine/Prusa XL 5T 0.5 nozzle.json +++ b/resources/profiles/Prusa/machine/Prusa XL 5T 0.5 nozzle.json @@ -1,6 +1,6 @@ { "type": "machine", - "setting_id": "GM003", + "setting_id": "GM_PRUSA_004", "name": "Prusa XL 5T 0.5 nozzle", "from": "system", "instantiation": "true", diff --git a/resources/profiles/Prusa/machine/Prusa XL 5T 0.6 nozzle.json b/resources/profiles/Prusa/machine/Prusa XL 5T 0.6 nozzle.json index bc63b52a5e..03ef5d97ff 100644 --- a/resources/profiles/Prusa/machine/Prusa XL 5T 0.6 nozzle.json +++ b/resources/profiles/Prusa/machine/Prusa XL 5T 0.6 nozzle.json @@ -1,6 +1,6 @@ { "type": "machine", - "setting_id": "GM003", + "setting_id": "GM_PRUSA_005", "name": "Prusa XL 5T 0.6 nozzle", "from": "system", "instantiation": "true", diff --git a/resources/profiles/Prusa/machine/Prusa XL 5T 0.8 nozzle.json b/resources/profiles/Prusa/machine/Prusa XL 5T 0.8 nozzle.json index 1928a6c73e..27656c4072 100644 --- a/resources/profiles/Prusa/machine/Prusa XL 5T 0.8 nozzle.json +++ b/resources/profiles/Prusa/machine/Prusa XL 5T 0.8 nozzle.json @@ -1,6 +1,6 @@ { "type": "machine", - "setting_id": "GM003", + "setting_id": "GM_PRUSA_006", "name": "Prusa XL 5T 0.8 nozzle", "from": "system", "instantiation": "true", diff --git a/resources/profiles/Prusa/machine/Prusa XL 5T.json b/resources/profiles/Prusa/machine/Prusa XL 5T.json index ed1084e3ba..81486d711a 100644 --- a/resources/profiles/Prusa/machine/Prusa XL 5T.json +++ b/resources/profiles/Prusa/machine/Prusa XL 5T.json @@ -1,12 +1,12 @@ { "type": "machine_model", "name": "Prusa XL 5T", - "model_id": "Prusa XL 5T", + "model_id": "prusa_xl_5t_01", "nozzle_diameter": "0.25;0.3;0.4;0.5;0.6;0.8", "machine_tech": "FFF", "family": "Prusa", "bed_model": "Prusa XL_bed.stl", - "bed_texture": "Prusa XL 5T.svg", + "bed_texture": "Prusa XL.svg", "hotend_model": "", "default_materials": "Prusa Generic PLA @XL 5T;Prusament PLA @XL 5T;Prusament rPLA @XL 5T;Prusa Generic PETG @XL 5T;Prusament PETG @XL 5T;Prusa Generic ABS @XL 5T;Prusament ASA @XL 5T;Prusament PC Blend @XL 5T;Prusament PC-CF @XL 5T;Prusament PVB @XL 5T;Prusament PA-CF @XL 5T" } diff --git a/resources/profiles/Prusa/machine/fdm_machine_common_xl_5t.json b/resources/profiles/Prusa/machine/fdm_machine_common_xl_5t.json index 587d416602..ff3cabed2b 100644 --- a/resources/profiles/Prusa/machine/fdm_machine_common_xl_5t.json +++ b/resources/profiles/Prusa/machine/fdm_machine_common_xl_5t.json @@ -11,12 +11,11 @@ "extruder_clearance_height_to_rod": "21", "extruder_clearance_height_to_lid": "21", "printer_variant": "0.4", - "machine_end_gcode": "{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F720{endif} ; Move bed down\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X6 Y350 F6000 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+100, max_print_height)} F300{endif} ; Move bed down\nM900 K0 ; reset LA\nM142 S36 ; reset heatbreak target temp\nM221 S100 ; reset flow percentage\nM84 ; disable motors\n; max_layer_z = [max_layer_z]", "machine_pause_gcode": "M601", - "machine_start_gcode": "M17 ; enable steppers\nM862.3 P \"XL\" ; printer model check\nM115 U6.0.1+14848\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\n; set print area\nM555 X{first_layer_print_min[0]} Y{first_layer_print_min[1]} W{(first_layer_print_max[0]) - (first_layer_print_min[0])} H{(first_layer_print_max[1]) - (first_layer_print_min[1])}\n; inform about nozzle diameter\nM862.1 P[nozzle_diameter]\n; set & wait for bed and extruder temp for MBL\nM140 S[first_layer_bed_temperature] ; set bed temp\nM104 T0 S{((filament_notes[0]=~/.*HT_MBL10.*/) ? (first_layer_temperature[0] - 10) : (filament_type[0] == \"PC\" or filament_type[0] == \"PA\") ? (first_layer_temperature[0] - 25) : (filament_type[0] == \"FLEX\") ? 210 : (filament_type[0]=~/.*PET.*/) ? 175 : 170)} ; set extruder temp for bed leveling\nM109 T0 R{((filament_notes[0]=~/.*HT_MBL10.*/) ? (first_layer_temperature[0] - 10) : (filament_type[0] == \"PC\" or filament_type[0] == \"PA\") ? (first_layer_temperature[0] - 25) : (filament_type[0] == \"FLEX\") ? 210 : (filament_type[0]=~/.*PET.*/) ? 175 : 170)} ; wait for temp\n; home carriage, pick tool, home all\nG28 XY\nM84 E ; turn off E motor\nG28 Z\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nG29 G ; absorb heat\n; move to the nozzle cleanup area\nG1 X{(min(((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32))), first_layer_print_min[0])) + 32} Y{(min((first_layer_print_min[1] - 7), first_layer_print_min[1]))} Z{5} F4800\nM302 S160 ; lower cold extrusion limit to 160C\nG1 E{-(filament_type[0] == \"FLEX\" ? 4 : 2)} F2400 ; retraction for nozzle cleanup\n; nozzle cleanup\nM84 E ; turn off E motor\nG29 P9 X{((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)))} Y{(first_layer_print_min[1] - 7)} W{32} H{7}\nG0 Z10 F480 ; move away in Z\n{if first_layer_bed_temperature[0] > 60}\nG0 Z70 F480 ; move away (a bit more) in Z\nG0 X30 Y{print_bed_min[1]} F6000 ; move away in X/Y for higher bed temperatures\n{endif}\nM106 S100 ; cool off the nozzle\nM107 ; stop cooling off the nozzle - turn off the fan\n; MBL\nM84 E ; turn off E motor\nG29 P1 ; invalidate mbl & probe print area\nG29 P1 X30 Y0 W50 H20 C ; probe near purge place\nG29 P3.2 ; interpolate mbl probes\nG29 P3.13 ; extrapolate mbl outside probe area\nG29 A ; activate mbl\nM104 S[first_layer_temperature] ; set extruder temp\nG1 Z10 F720 ; move away in Z\nG0 X30 Y-8 F6000 ; move next to the sheet\n; wait for extruder temp\nM109 T0 S{first_layer_temperature[0]}\n;\n; purge\n;\nG92 E0 ; reset extruder position\nG0 X{(0 == 0 ? 30 : (0 == 1 ? 150 : (0 == 2 ? 210 : 330)))} Y{(0 < 4 ? -8 : -5.5)} ; move close to the sheet's edge\nG1 E{(filament_type[0] == \"FLEX\" ? 4 : 2)} F2400 ; deretraction after the initial one before nozzle cleaning\nG0 E10 X40 Z0.2 F500 ; purge\nG0 X70 E9 F800 ; purge\nG0 X{70 + 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{70 + 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG92 E0 ; reset extruder position", - "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\nG92 E0.0\n;[layer_z]", - "change_filament_gcode": "M600\nG1 E0.3 F1500 ; prime after color change", + "machine_start_gcode": "M17 ; enable steppers\nM862.3 P \"XL\" ; printer model check\nM862.5 P2 ; g-code level check\nM862.6 P\"Input shaper\" ; FW feature check\nM115 U6.0.3+14902\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\n; set print area\nM555 X{first_layer_print_min[0]} Y{first_layer_print_min[1]} W{(first_layer_print_max[0]) - (first_layer_print_min[0])} H{(first_layer_print_max[1]) - (first_layer_print_min[1])}\n; inform about nozzle diameter\n{if (is_extruder_used[0])}M862.1 T0 P{nozzle_diameter[0]}{endif}\n{if (is_extruder_used[1])}M862.1 T1 P{nozzle_diameter[1]}{endif}\n{if (is_extruder_used[2])}M862.1 T2 P{nozzle_diameter[2]}{endif}\n{if (is_extruder_used[3])}M862.1 T3 P{nozzle_diameter[3]}{endif}\n{if (is_extruder_used[4])}M862.1 T4 P{nozzle_diameter[4]}{endif}\n\n; turn off unused heaters\n{if ! is_extruder_used[0]} M104 T0 S0 {endif}\n{if ! is_extruder_used[1]} M104 T1 S0 {endif}\n{if num_extruders > 2 and ! is_extruder_used[2]} M104 T2 S0 {endif}\n{if num_extruders > 3 and ! is_extruder_used[3]} M104 T3 S0 {endif}\n{if num_extruders > 4 and ! is_extruder_used[4]} M104 T4 S0 {endif}\n\nM217 Z{max(zhop, 2.0)} ; set toolchange z hop to 2mm, or zhop variable from slicer if higher\n; set bed and extruder temp for MBL\nM140 S[first_layer_bed_temperature] ; set bed temp\nG0 Z5 ; add Z clearance\nM109 T{initial_tool} S{((filament_notes[initial_tool]=~/.*HT_MBL10.*/) ? (first_layer_temperature[initial_tool] - 10) : (filament_type[initial_tool] == \"PC\" or filament_type[initial_tool] == \"PA\") ? (first_layer_temperature[initial_tool] - 25) : (filament_type[initial_tool] == \"FLEX\") ? 210 : (filament_type[initial_tool]=~/.*PET.*/) ? 175 : 170)} ; wait for temp\n\n; Home XY\nG28 XY\n; try picking tools used in print\nG1 F{travel_speed * 60}\n{if (is_extruder_used[0]) and (initial_tool != 0)}T0 S1 L0 D0{endif}\n{if (is_extruder_used[1]) and (initial_tool != 1)}T1 S1 L0 D0{endif}\n{if (is_extruder_used[2]) and (initial_tool != 2)}T2 S1 L0 D0{endif}\n{if (is_extruder_used[3]) and (initial_tool != 3)}T3 S1 L0 D0{endif}\n{if (is_extruder_used[4]) and (initial_tool != 4)}T4 S1 L0 D0{endif}\n; select tool that will be used to home & MBL\nT{initial_tool} S1 L0 D0\n; home Z with MBL tool\nM84 E ; turn off E motor\nG28 Z\nG0 Z5 ; add Z clearance\n\nM104 T{initial_tool} S{if idle_temperature[initial_tool] == 0}70{else}{idle_temperature[initial_tool]}{endif} ; set idle temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\n\nG29 G ; absorb heat\n\nM109 T{initial_tool} S{((filament_notes[initial_tool]=~/.*HT_MBL10.*/) ? (first_layer_temperature[initial_tool] - 10) : (filament_type[initial_tool] == \"PC\" or filament_type[initial_tool] == \"PA\") ? (first_layer_temperature[initial_tool] - 25) : (filament_type[initial_tool] == \"FLEX\") ? 210 : (filament_type[initial_tool]=~/.*PET.*/) ? 175 : 170)} ; wait for temp\n\n; move to the nozzle cleanup area\nG1 X{(min(((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32))), first_layer_print_min[0])) + 32} Y{(min((first_layer_print_min[1] - 7), first_layer_print_min[1]))} Z{5} F{(travel_speed * 60)}\nM302 S160 ; lower cold extrusion limit to 160C\nG1 E{-(filament_type[0] == \"FLEX\" ? 4 : 2)} F2400 ; retraction for nozzle cleanup\n; nozzle cleanup\nM84 E ; turn off E motor\nG29 P9 X{((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)))} Y{(first_layer_print_min[1] - 7)} W{32} H{7}\nG0 Z5 F480 ; move away in Z\nM107 ; turn off the fan\n; MBL\nM84 E ; turn off E motor\nG29 P1 ; invalidate mbl & probe print area\nG29 P1 X30 Y0 W{(((is_extruder_used[4]) or ((is_extruder_used[3]) or (is_extruder_used[2]))) ? \"300\" : ((is_extruder_used[1]) ? \"130\" : \"50\"))} H20 C ; probe near purge place\nG29 P3.2 ; interpolate mbl probes\nG29 P3.13 ; extrapolate mbl outside probe area\nG29 A ; activate mbl\nG1 Z10 F720 ; move away in Z\nG1 F{travel_speed * 60}\nP0 S1 L1 D0; park the tool\n; set extruder temp\n{if first_layer_temperature[0] > 0 and (is_extruder_used[0])}M104 T0 S{first_layer_temperature[0]}{endif}\n{if first_layer_temperature[1] > 0 and (is_extruder_used[1])}M104 T1 S{first_layer_temperature[1]}{endif}\n{if first_layer_temperature[2] > 0 and (is_extruder_used[2])}M104 T2 S{first_layer_temperature[2]}{endif}\n{if first_layer_temperature[3] > 0 and (is_extruder_used[3])}M104 T3 S{first_layer_temperature[3]}{endif}\n{if first_layer_temperature[4] > 0 and (is_extruder_used[4])}M104 T4 S{first_layer_temperature[4]}{endif}\n{if (is_extruder_used[0]) and initial_tool != 0}\n;\n; purge first tool\n;\nG1 F{travel_speed * 60}\nP0 S1 L2 D0; park the tool\nM109 T0 S{first_layer_temperature[0]}\nT0 S1 L0 D0; pick the tool\nG92 E0 ; reset extruder position\n\nG0 X{(0 == 0 ? 30 : (0 == 1 ? 150 : (0 == 2 ? 210 : 330)))} Y{(0 < 4 ? -7 : -4.5)} Z10 F{(travel_speed * 60)} ; move close to the sheet's edge\nG0 E{if filament_multitool_ramming[0]}10{else}30{endif} X40 Z0.2 F{if filament_multitool_ramming[0]}500{else}170{endif} ; purge while moving towards the sheet\nG0 X70 E9 F800 ; continue purging and wipe the nozzle\nG0 X{70 + 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{70 + 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG1 E{- 1.5 * retract_length[0]} F2400 ; retract\n{e_retracted[0] = 1.5 * retract_length[0]} ; update slicer internal retract variable\nG92 E0 ; reset extruder position\n\nM104 S{(idle_temperature[0] == 0 ? (first_layer_temperature[0] + standby_temperature_delta) : (idle_temperature[0]))} T0\n{endif}\n{if (is_extruder_used[1]) and initial_tool != 1}\n;\n; purge second tool\n;\nG1 F{travel_speed * 60}\nP0 S1 L2 D0; park the tool\nM109 T1 S{first_layer_temperature[1]}\nT1 S1 L0 D0; pick the tool\nG92 E0 ; reset extruder position\n\nG0 X{(1 == 0 ? 30 : (1 == 1 ? 150 : (1 == 2 ? 210 : 330)))} Y{(1 < 4 ? -7 : -4.5)} Z10 F{(travel_speed * 60)} ; move close to the sheet's edge\nG0 E{if filament_multitool_ramming[1]}10{else}30{endif} X140 Z0.2 F{if filament_multitool_ramming[1]}500{else}170{endif} ; purge while moving towards the sheet\nG0 X110 E9 F800 ; continue purging and wipe the nozzle\nG0 X{110 - 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{110 - 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG1 E{- 1.5 * retract_length[1]} F2400 ; retract\n{e_retracted[1] = 1.5 * retract_length[1]} ; update slicer internal retract variable\nG92 E0 ; reset extruder position\n\nM104 S{(idle_temperature[1] == 0 ? (first_layer_temperature[1] + standby_temperature_delta) : (idle_temperature[1]))} T1\n{endif}\n{if (is_extruder_used[2]) and initial_tool != 2}\n;\n; purge third tool\n;\nG1 F{travel_speed * 60}\nP0 S1 L2 D0; park the tool\nM109 T2 S{first_layer_temperature[2]}\nT2 S1 L0 D0; pick the tool\nG92 E0 ; reset extruder position\n\nG0 X{(2 == 0 ? 30 : (2 == 1 ? 150 : (2 == 2 ? 210 : 330)))} Y{(2 < 4 ? -7 : -4.5)} Z10 F{(travel_speed * 60)} ; move close to the sheet's edge\nG0 E{if filament_multitool_ramming[2]}10{else}30{endif} X220 Z0.2 F{if filament_multitool_ramming[2]}500{else}170{endif} ; purge while moving towards the sheet\nG0 X250 E9 F800 ; continue purging and wipe the nozzle\nG0 X{250 + 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{250 + 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG1 E{- 1.5 * retract_length[2]} F2400 ; retract\n{e_retracted[2] = 1.5 * retract_length[2]} ; update slicer internal retract variable\nG92 E0 ; reset extruder position\n\nM104 S{(idle_temperature[2] == 0 ? (first_layer_temperature[2] + standby_temperature_delta) : (idle_temperature[2]))} T2\n{endif}\n{if (is_extruder_used[3]) and initial_tool != 3}\n;\n; purge fourth tool\n;\nG1 F{travel_speed * 60}\nP0 S1 L2 D0; park the tool\nM109 T3 S{first_layer_temperature[3]}\nT3 S1 L0 D0; pick the tool\nG92 E0 ; reset extruder position\n\nG0 X{(3 == 0 ? 30 : (3 == 1 ? 150 : (3 == 2 ? 210 : 330)))} Y{(3 < 4 ? -7 : -4.5)} Z10 F{(travel_speed * 60)} ; move close to the sheet's edge\nG0 E{if filament_multitool_ramming[3]}10{else}30{endif} X320 Z0.2 F{if filament_multitool_ramming[3]}500{else}170{endif} ; purge while moving towards the sheet\nG0 X290 E9 F800 ; continue purging and wipe the nozzle\nG0 X{290 - 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{290 - 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG1 E{- 1.5 * retract_length[3]} F2400 ; retract\n{e_retracted[3] = 1.5 * retract_length[3]} ; update slicer internal retract variable\nG92 E0 ; reset extruder position\n\nM104 S{(idle_temperature[3] == 0 ? (first_layer_temperature[3] + standby_temperature_delta) : (idle_temperature[3]))} T3\n{endif}\n{if (is_extruder_used[4]) and initial_tool != 4}\n;\n; purge fifth tool\n;\nG1 F{travel_speed * 60}\nP0 S1 L2 D0; park the tool\nM109 T4 S{first_layer_temperature[4]}\nT4 S1 L0 D0; pick the tool\nG92 E0 ; reset extruder position\n\nG0 X{(4 == 0 ? 30 : (4 == 1 ? 150 : (4 == 2 ? 210 : 330)))} Y{(4 < 4 ? -7 : -4.5)} Z10 F{(travel_speed * 60)} ; move close to the sheet's edge\nG0 E{if filament_multitool_ramming[4]}10{else}30{endif} X320 Z0.2 F{if filament_multitool_ramming[4]}500{else}170{endif} ; purge while moving towards the sheet\nG0 X290 E9 F800 ; continue purging and wipe the nozzle\nG0 X{290 - 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{290 - 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG1 E{- 1.5 * retract_length[4]} F2400 ; retract\n{e_retracted[4] = 1.5 * retract_length[4]} ; update slicer internal retract variable\nG92 E0 ; reset extruder position\n\nM104 S{(idle_temperature[4] == 0 ? (first_layer_temperature[4] + standby_temperature_delta) : (idle_temperature[4]))} T4\n{endif}\n;\n; purge initial tool\n;\nG1 F{travel_speed * 60}\nP0 S1 L2 D0; park the tool\nM109 T{initial_tool} S{first_layer_temperature[initial_tool]}\nT{initial_tool} S1 L0 D0; pick the tool\nG92 E0 ; reset extruder position\n\nG0 X{(initial_tool == 0 ? 30 : (initial_tool == 1 ? 150 : (initial_tool == 2 ? 210 : 330)))} Y{(initial_tool < 4 ? -7 : -4.5)} Z10 F{(travel_speed * 60)} ; move close to the sheet's edge\nG0 E{if filament_multitool_ramming[initial_tool]}10{else}30{endif} X{(initial_tool == 0 ? 30 : (initial_tool == 1 ? 150 : (initial_tool == 2 ? 210 : 330))) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 10)} Z0.2 F{if filament_multitool_ramming[initial_tool]}500{else}170{endif} ; purge while moving towards the sheet\nG0 X{(initial_tool == 0 ? 30 : (initial_tool == 1 ? 150 : (initial_tool == 2 ? 210 : 330))) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 40)} E9 F800 ; continue purging and wipe the nozzle\nG0 X{(initial_tool == 0 ? 30 : (initial_tool == 1 ? 150 : (initial_tool == 2 ? 210 : 330))) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 40) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 3)} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{(initial_tool == 0 ? 30 : (initial_tool == 1 ? 150 : (initial_tool == 2 ? 210 : 330))) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 40) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 3 * 2)} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG1 E{- 1.5 * retract_length[initial_tool]} F2400 ; retract\n{e_retracted[initial_tool] = 1.5 * retract_length[initial_tool]}\nG92 E0 ; reset extruder position\n", + "machine_end_gcode": "G4 ; wait\n\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+5, max_print_height)}{endif} ; Move bed down\n\nP0 S1 ; park tool\n\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+97, max_print_height)} F300{endif} ; Move bed further down\n\n; turn off extruder heaters\n{if is_extruder_used[0]} M104 T0 S0 {endif}\n{if is_extruder_used[1]} M104 T1 S0 {endif}\n{if is_extruder_used[2]} M104 T2 S0 {endif}\n{if is_extruder_used[3]} M104 T3 S0 {endif}\n{if is_extruder_used[4]} M104 T4 S0 {endif}\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM221 S100 ; reset flow percentage\nM84 ; disable motors\nM77 ; stop print timer\n; max_layer_z = [max_layer_z]", + "change_filament_gcode": "; Change Tool[previous_extruder] -> Tool[next_extruder] (layer [layer_num])\n{if travel_speed > 350.0}\nG1 F{350.0 * 60} \n{else}\nG1 F{travel_speed * 60} \n{endif}\nP0 S1 L2 D0\n; [layer_num]\n{if layer_num == 0}\nM109 S{first_layer_temperature[next_extruder]} T[next_extruder]\n{else}\nM109 S{nozzle_temperature[next_extruder]} T[next_extruder]\n{endif}\nT[next_extruder] S1 L0 D0\n", + "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\nG92 E0.0\n;[layer_z]\n", "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", - "printer_notes": "Don't remove the following keywords! These keywords are used in the \"compatible printer\" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_MODEL_XLIS\nPG\nINPUT_SHAPER" - + "printer_notes": "Do not remove the keywords below.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_XLIS\nPG\nINPUT_SHAPER" } \ No newline at end of file diff --git a/resources/profiles/Prusa/process/process_common_xl.json b/resources/profiles/Prusa/process/process_common_xl.json index f3f2a7e791..65622abadb 100644 --- a/resources/profiles/Prusa/process/process_common_xl.json +++ b/resources/profiles/Prusa/process/process_common_xl.json @@ -92,5 +92,7 @@ "min_bead_width": "85%", "min_feature_size": "25%", "filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[initial_tool]}_{print_time}.gcode", - "gcode_label_objects": "1" + "gcode_label_objects": "1", + "exclude_object": "1" + } \ No newline at end of file diff --git a/resources/profiles/Prusa/process/process_common_xl_5t.json b/resources/profiles/Prusa/process/process_common_xl_5t.json index abcc096c6c..f624f7780a 100644 --- a/resources/profiles/Prusa/process/process_common_xl_5t.json +++ b/resources/profiles/Prusa/process/process_common_xl_5t.json @@ -7,5 +7,8 @@ "enable_prime_tower": "1", "wipe_tower_cone_angle": "25", "wipe_tower_extra_spacing": "150%", - "wipe_tower_rotation_angle": "90" + "wipe_tower_rotation_angle": "90", + "single_extruder_multi_material_priming": "0", + "ooze_prevention": "1", + "standby_temperature_delta": "-40" } \ No newline at end of file From f84c3a00e06201041e7cc7365be09ac79dad4c78 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Sun, 14 Jul 2024 17:35:12 +0800 Subject: [PATCH 17/32] Fix a regression for SEMM when ramming and cooling is disabled --- src/libslic3r/GCode/WipeTower2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/GCode/WipeTower2.cpp b/src/libslic3r/GCode/WipeTower2.cpp index a22bec5dd8..6bebe14b76 100644 --- a/src/libslic3r/GCode/WipeTower2.cpp +++ b/src/libslic3r/GCode/WipeTower2.cpp @@ -984,7 +984,7 @@ void WipeTower2::toolchange_Unload( } const int& number_of_cooling_moves = m_filpar[m_current_tool].cooling_moves; - const bool cooling_will_happen = m_semm && number_of_cooling_moves > 0; + const bool cooling_will_happen = m_semm && number_of_cooling_moves > 0 && m_cooling_tube_length != 0; bool change_temp_later = false; // Wipe tower should only change temperature with single extruder MM. Otherwise, all temperatures should From 93d025bfd4e8c6ea6d135ff6d21cc808d1d6ed93 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Mon, 15 Jul 2024 21:46:57 +0800 Subject: [PATCH 18/32] update placeholderparser --- src/libslic3r/PlaceholderParser.cpp | 1560 +++++++++++++++++++-------- 1 file changed, 1101 insertions(+), 459 deletions(-) diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index 22ef3705d8..c6e4bc525d 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -1,6 +1,7 @@ #include "PlaceholderParser.hpp" #include "Exception.hpp" #include "Flow.hpp" +#include "Utils.hpp" #include #include #include @@ -40,19 +41,11 @@ #include #include #include -#if BOOST_VERSION >= 107800 #include #include #include #include #include -#else -#include -#include -#include -#include -#include -#endif #include #include #include @@ -73,11 +66,6 @@ namespace Slic3r { -//! macro used to mark string used at localization, -//! return same string -#define L(s) (s) -#define _(s) Slic3r::I18N::translate(s) - PlaceholderParser::PlaceholderParser(const DynamicConfig *external_config) : m_external_config(external_config) { this->set("version", std::string(SoftFever_VERSION)); @@ -180,30 +168,35 @@ namespace px = boost::phoenix; namespace client { - template + using Iterator = std::string::const_iterator; + using IteratorRange = boost::iterator_range; + struct OptWithPos { OptWithPos() {} - OptWithPos(ConfigOptionConstPtr opt, boost::iterator_range it_range) : opt(opt), it_range(it_range) {} + OptWithPos(ConfigOptionConstPtr opt, IteratorRange it_range, bool writable = false) : opt(opt), it_range(it_range), writable(writable) {} ConfigOptionConstPtr opt { nullptr }; bool writable { false }; // -1 means it is a scalar variable, or it is a vector variable and index was not assigned yet or the whole vector is considered. int index { -1 }; - boost::iterator_range it_range; + IteratorRange it_range; + bool empty() const { return opt == nullptr; } bool has_index() const { return index != -1; } }; - template - std::ostream& operator<<(std::ostream& os, OptWithPos const& opt) + std::ostream& operator<<(std::ostream& os, OptWithPos const& opt) { os << std::string(opt.it_range.begin(), opt.it_range.end()); return os; } - template struct expr { expr() {} + expr(const expr &rhs) : m_type(rhs.type()), it_range(rhs.it_range) + { if (rhs.type() == TYPE_STRING) m_data.s = new std::string(*rhs.m_data.s); else m_data.set(rhs.m_data); } + expr(expr &&rhs) : expr(std::move(rhs), rhs.it_range.begin(), rhs.it_range.end()) {} + explicit expr(bool b) : m_type(TYPE_BOOL) { m_data.b = b; } explicit expr(bool b, const Iterator &it_begin, const Iterator &it_end) : m_type(TYPE_BOOL), it_range(it_begin, it_end) { m_data.b = b; } explicit expr(int i) : m_type(TYPE_INT) { m_data.i = i; } @@ -212,13 +205,11 @@ namespace client explicit expr(double d, const Iterator &it_begin, const Iterator &it_end) : m_type(TYPE_DOUBLE), it_range(it_begin, it_end) { m_data.d = d; } explicit expr(const char *s) : m_type(TYPE_STRING) { m_data.s = new std::string(s); } explicit expr(const std::string &s) : m_type(TYPE_STRING) { m_data.s = new std::string(s); } + explicit expr(std::string &&s) : m_type(TYPE_STRING) { m_data.s = new std::string(std::move(s)); } explicit expr(const std::string &s, const Iterator &it_begin, const Iterator &it_end) : m_type(TYPE_STRING), it_range(it_begin, it_end) { m_data.s = new std::string(s); } - expr(const expr &rhs) : m_type(rhs.type()), it_range(rhs.it_range) - { if (rhs.type() == TYPE_STRING) m_data.s = new std::string(*rhs.m_data.s); else m_data.set(rhs.m_data); } - explicit expr(expr &&rhs) : expr(rhs, rhs.it_range.begin(), rhs.it_range.end()) {} explicit expr(expr &&rhs, const Iterator &it_begin, const Iterator &it_end) : m_type(rhs.type()), it_range{ it_begin, it_end } - { + { m_data.set(rhs.m_data); rhs.m_type = TYPE_EMPTY; } @@ -304,6 +295,9 @@ namespace client { std::string out; switch (this->type()) { + case TYPE_EMPTY: + // Inside an if / else block to be skipped. + break; case TYPE_BOOL: out = this->b() ? "true" : "false"; break; case TYPE_INT: out = std::to_string(this->i()); break; case TYPE_DOUBLE: @@ -328,15 +322,18 @@ namespace client // Range of input iterators covering this expression. // Used for throwing parse exceptions. - boost::iterator_range it_range; + IteratorRange it_range; expr unary_minus(const Iterator start_pos) const { switch (this->type()) { + case TYPE_EMPTY: + // Inside an if / else block to be skipped. + return expr(); case TYPE_INT : - return expr(- this->i(), start_pos, this->it_range.end()); + return expr(- this->i(), start_pos, this->it_range.end()); case TYPE_DOUBLE: - return expr(- this->d(), start_pos, this->it_range.end()); + return expr(- this->d(), start_pos, this->it_range.end()); default: this->throw_exception("Cannot apply unary minus operator."); } @@ -348,10 +345,13 @@ namespace client expr unary_integer(const Iterator start_pos) const { switch (this->type()) { + case TYPE_EMPTY: + // Inside an if / else block to be skipped. + return expr(); case TYPE_INT: - return expr(this->i(), start_pos, this->it_range.end()); + return expr(this->i(), start_pos, this->it_range.end()); case TYPE_DOUBLE: - return expr(static_cast(this->d()), start_pos, this->it_range.end()); + return expr(static_cast(this->d()), start_pos, this->it_range.end()); default: this->throw_exception("Cannot convert to integer."); } @@ -363,10 +363,13 @@ namespace client expr round(const Iterator start_pos) const { switch (this->type()) { + case TYPE_EMPTY: + // Inside an if / else block to be skipped. + return expr(); case TYPE_INT: - return expr(this->i(), start_pos, this->it_range.end()); + return expr(this->i(), start_pos, this->it_range.end()); case TYPE_DOUBLE: - return expr(static_cast(std::round(this->d())), start_pos, this->it_range.end()); + return expr(static_cast(std::round(this->d())), start_pos, this->it_range.end()); default: this->throw_exception("Cannot round a non-numeric value."); } @@ -378,8 +381,11 @@ namespace client expr unary_not(const Iterator start_pos) const { switch (this->type()) { + case TYPE_EMPTY: + // Inside an if / else block to be skipped. + return expr(); case TYPE_BOOL: - return expr(! this->b(), start_pos, this->it_range.end()); + return expr(! this->b(), start_pos, this->it_range.end()); default: this->throw_exception("Cannot apply a not operator."); } @@ -390,7 +396,9 @@ namespace client expr &operator+=(const expr &rhs) { - if (this->type() == TYPE_STRING) { + if (this->type() == TYPE_EMPTY) { + // Inside an if / else block to be skipped. + } else if (this->type() == TYPE_STRING) { // Convert the right hand side to string and append. *m_data.s += rhs.to_string(); } else if (rhs.type() == TYPE_STRING) { @@ -405,78 +413,104 @@ namespace client else m_data.i += rhs.i(); } - this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); + this->it_range = IteratorRange(this->it_range.begin(), rhs.it_range.end()); return *this; } expr &operator-=(const expr &rhs) { - const char *err_msg = "Cannot subtract non-numeric types."; - this->throw_if_not_numeric(err_msg); - rhs.throw_if_not_numeric(err_msg); - if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE) - this->set_d_lite(this->as_d() - rhs.as_d()); - else - m_data.i -= rhs.i(); - this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); + if (this->type() == TYPE_EMPTY) { + // Inside an if / else block to be skipped. + this->reset(); + } else { + const char *err_msg = "Cannot subtract non-numeric types."; + this->throw_if_not_numeric(err_msg); + rhs.throw_if_not_numeric(err_msg); + if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE) + this->set_d_lite(this->as_d() - rhs.as_d()); + else + m_data.i -= rhs.i(); + this->it_range = IteratorRange(this->it_range.begin(), rhs.it_range.end()); + } return *this; } expr &operator*=(const expr &rhs) { - const char *err_msg = "Cannot multiply with non-numeric type."; - this->throw_if_not_numeric(err_msg); - rhs.throw_if_not_numeric(err_msg); - if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE) - this->set_d_lite(this->as_d() * rhs.as_d()); - else - m_data.i *= rhs.i(); - this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); + if (this->type() == TYPE_EMPTY) { + // Inside an if / else block to be skipped. + this->reset(); + } else { + const char *err_msg = "Cannot multiply with non-numeric type."; + this->throw_if_not_numeric(err_msg); + rhs.throw_if_not_numeric(err_msg); + if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE) + this->set_d_lite(this->as_d() * rhs.as_d()); + else + m_data.i *= rhs.i(); + this->it_range = IteratorRange(this->it_range.begin(), rhs.it_range.end()); + } return *this; } expr &operator/=(const expr &rhs) { - this->throw_if_not_numeric("Cannot divide a non-numeric type."); - rhs.throw_if_not_numeric("Cannot divide with a non-numeric type."); - if (rhs.type() == TYPE_INT ? (rhs.i() == 0) : (rhs.d() == 0.)) - rhs.throw_exception("Division by zero"); - if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE) - this->set_d_lite(this->as_d() / rhs.as_d()); - else - m_data.i /= rhs.i(); - this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); + if (this->type() == TYPE_EMPTY) { + // Inside an if / else block to be skipped. + this->reset(); + } else { + this->throw_if_not_numeric("Cannot divide a non-numeric type."); + rhs.throw_if_not_numeric("Cannot divide with a non-numeric type."); + if (rhs.type() == TYPE_INT ? (rhs.i() == 0) : (rhs.d() == 0.)) + rhs.throw_exception("Division by zero"); + if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE) + this->set_d_lite(this->as_d() / rhs.as_d()); + else + m_data.i /= rhs.i(); + this->it_range = IteratorRange(this->it_range.begin(), rhs.it_range.end()); + } return *this; } expr &operator%=(const expr &rhs) { - this->throw_if_not_numeric("Cannot divide a non-numeric type."); - rhs.throw_if_not_numeric("Cannot divide with a non-numeric type."); - if (rhs.type() == TYPE_INT ? (rhs.i() == 0) : (rhs.d() == 0.)) - rhs.throw_exception("Division by zero"); - if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE) - this->set_d_lite(std::fmod(this->as_d(), rhs.as_d())); - else - m_data.i %= rhs.i(); - this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); + if (this->type() == TYPE_EMPTY) { + // Inside an if / else block to be skipped. + this->reset(); + } else { + this->throw_if_not_numeric("Cannot divide a non-numeric type."); + rhs.throw_if_not_numeric("Cannot divide with a non-numeric type."); + if (rhs.type() == TYPE_INT ? (rhs.i() == 0) : (rhs.d() == 0.)) + rhs.throw_exception("Division by zero"); + if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE) + this->set_d_lite(std::fmod(this->as_d(), rhs.as_d())); + else + m_data.i %= rhs.i(); + this->it_range = IteratorRange(this->it_range.begin(), rhs.it_range.end()); + } return *this; } static void to_string2(expr &self, std::string &out) { - out = self.to_string(); + if (self.type() != TYPE_EMPTY) + // Not inside an if / else block to be skipped + out = self.to_string(); } static void evaluate_boolean(expr &self, bool &out) { - if (self.type() != TYPE_BOOL) - self.throw_exception("Not a boolean expression"); - out = self.b(); + if (self.type() != TYPE_EMPTY) { + // Not inside an if / else block to be skipped + if (self.type() != TYPE_BOOL) + self.throw_exception("Not a boolean expression"); + out = self.b(); + } } static void evaluate_boolean_to_string(expr &self, std::string &out) { + assert(self.type() != TYPE_EMPTY); if (self.type() != TYPE_BOOL) self.throw_exception("Not a boolean expression"); out = self.b() ? "true" : "false"; @@ -485,6 +519,9 @@ namespace client // Is lhs==rhs? Store the result into lhs. static void compare_op(expr &lhs, expr &rhs, char op, bool invert) { + if (lhs.type() == TYPE_EMPTY) + // Inside an if / else block to be skipped + return; bool value = false; if (lhs.numeric_type() && rhs.numeric_type()) { // Both types are numeric. @@ -541,6 +578,9 @@ namespace client // Store the result into param1. static void function_2params(expr ¶m1, expr ¶m2, Function2ParamsType fun) { + if (param1.type() == TYPE_EMPTY) + // Inside an if / else block to be skipped + return; throw_if_not_numeric(param1); throw_if_not_numeric(param2); if (param1.type() == TYPE_DOUBLE || param2.type() == TYPE_DOUBLE) { @@ -568,6 +608,9 @@ namespace client // Store the result into param1. static void random(expr ¶m1, expr ¶m2, std::mt19937 &rng) { + if (param1.type() == TYPE_EMPTY) + // Inside an if / else block to be skipped + return; throw_if_not_numeric(param1); throw_if_not_numeric(param2); if (param1.type() == TYPE_DOUBLE || param2.type() == TYPE_DOUBLE) @@ -581,6 +624,9 @@ namespace client template static void digits(expr ¶m1, expr ¶m2, expr ¶m3) { + if (param1.type() == TYPE_EMPTY) + // Inside an if / else block to be skipped + return; throw_if_not_numeric(param1); if (param2.type() != TYPE_INT) param2.throw_exception("digits: second parameter must be integer"); @@ -600,8 +646,11 @@ namespace client param1.set_s(buf); } - static void regex_op(const expr &lhs, boost::iterator_range &rhs, char op, expr &out) + static void regex_op(const expr &lhs, IteratorRange &rhs, char op, expr &out) { + if (lhs.type() == TYPE_EMPTY) + // Inside an if / else block to be skipped + return; const std::string *subject = nullptr; if (lhs.type() == TYPE_STRING) { // One type is string, the other could be converted to string. @@ -622,14 +671,19 @@ namespace client } } - static void regex_matches (expr &lhs, boost::iterator_range &rhs) { return regex_op(lhs, rhs, '=', lhs); } - static void regex_doesnt_match(expr &lhs, boost::iterator_range &rhs) { return regex_op(lhs, rhs, '!', lhs); } + static void regex_matches (expr &lhs, IteratorRange &rhs) { return regex_op(lhs, rhs, '=', lhs); } + static void regex_doesnt_match(expr &lhs, IteratorRange &rhs) { return regex_op(lhs, rhs, '!', lhs); } static void one_of_test_init(expr &out) { out.set_b(false); } template static void one_of_test(const expr &match, const expr &pattern, expr &out) { + if (match.type() == TYPE_EMPTY) { + // Inside an if / else block to be skipped + out.reset(); + return; + } if (! out.b()) { if (match.type() != TYPE_STRING) match.throw_exception("one_of(): First parameter (the string to match against) has to be a string value"); @@ -646,7 +700,12 @@ namespace client out.set_b(match.s() == pattern.s()); } } - static void one_of_test_regex(const expr &match, boost::iterator_range &pattern, expr &out) { + static void one_of_test_regex(const expr &match, IteratorRange &pattern, expr &out) { + if (match.type() == TYPE_EMPTY) { + // Inside an if / else block to be skipped + out.reset(); + return; + } if (! out.b()) { if (match.type() != TYPE_STRING) match.throw_exception("one_of(): First parameter (the string to match against) has to be a string value"); @@ -656,6 +715,9 @@ namespace client static void logical_op(expr &lhs, expr &rhs, char op) { + if (lhs.type() == TYPE_EMPTY) + // Inside an if / else block to be skipped + return; bool value = false; if (lhs.type() == TYPE_BOOL && rhs.type() == TYPE_BOOL) { value = (op == '|') ? (lhs.b() || rhs.b()) : (lhs.b() && rhs.b()); @@ -668,24 +730,6 @@ namespace client static void logical_or (expr &lhs, expr &rhs) { logical_op(lhs, rhs, '|'); } static void logical_and(expr &lhs, expr &rhs) { logical_op(lhs, rhs, '&'); } - static void ternary_op(expr &lhs, expr &rhs1, expr &rhs2) - { - if (lhs.type() != TYPE_BOOL) - lhs.throw_exception("Not a boolean expression"); - if (lhs.b()) - lhs = std::move(rhs1); - else - lhs = std::move(rhs2); - } - - static void set_if(bool &cond, bool ¬_yet_consumed, std::string &str_in, std::string &str_out) - { - if (cond && not_yet_consumed) { - str_out = str_in; - not_yet_consumed = false; - } - } - void throw_exception(const char *message) const { boost::throw_exception(qi::expectation_failure( @@ -715,10 +759,9 @@ namespace client } m_data; }; - template - std::ostream& operator<<(std::ostream &os, const expr &expression) + std::ostream& operator<<(std::ostream &os, const expr &expression) { - typedef expr Expr; + typedef expr Expr; os << std::string(expression.it_range.begin(), expression.it_range.end()) << " - "; switch (expression.type()) { case Expr::TYPE_EMPTY: os << "empty"; break; @@ -732,11 +775,19 @@ namespace client } struct MyContext : public ConfigOptionResolver { + // Config provided as a parameter to PlaceholderParser invocation, overriding PlaceholderParser stored config. const DynamicConfig *external_config = nullptr; + // Config stored inside PlaceholderParser. const DynamicConfig *config = nullptr; + // Config provided as a parameter to PlaceholderParser invocation, evaluated after the two configs above. const DynamicConfig *config_override = nullptr; + // Config provided as a parameter to PlaceholderParser invocation, containing variables that will be read out + // and processed by the PlaceholderParser callee. mutable DynamicConfig *config_outputs = nullptr; + // Local variables, read / write + mutable DynamicConfig config_local; size_t current_extruder_id = 0; + // Random number generator and optionally global variables. PlaceholderParser::ContextData *context_data = nullptr; // If false, the macro_processor will evaluate a full macro. // If true, the macro processor will evaluate just a boolean condition using the full expressive power of the macro processor. @@ -746,7 +797,34 @@ namespace client // Table to translate symbol tag to a human readable error message. static std::map tag_to_error_message; - static void evaluate_full_macro(const MyContext *ctx, bool &result) { result = ! ctx->just_boolean_expression; } + // Should the parser consider the parsed string to be a macro or a boolean expression? + static bool evaluate_full_macro(const MyContext *ctx) { return ! ctx->just_boolean_expression; } + + // Entering a conditional block. + static void block_enter(const MyContext *ctx, const bool condition) + { + if (ctx->skipping() || ! condition) + ++ ctx->m_depth_suppressed; + } + // Exiting a conditional block. + static void block_exit(const MyContext *ctx, const bool condition, bool ¬_yet_consumed, std::string &data_in, std::string &data_out) + { + if (ctx->skipping()) + -- ctx->m_depth_suppressed; + else if (condition && not_yet_consumed) { + data_out = std::move(data_in); + not_yet_consumed = false; + } + } + static void block_exit_ternary(const MyContext* ctx, const bool condition, expr &data_in, expr &data_out) + { + if (ctx->skipping()) + -- ctx->m_depth_suppressed; + else if (condition) + data_out = std::move(data_in); + } + // Inside a block, which is conditionally suppressed? + bool skipping() const { return m_depth_suppressed > 0; } const ConfigOption* optptr(const t_config_option_key &opt_key) const override { @@ -761,14 +839,30 @@ namespace client } const ConfigOption* resolve_symbol(const std::string &opt_key) const { return this->optptr(opt_key); } - ConfigOption* resolve_output_symbol(const std::string &opt_key) const { return this->config_outputs ? this->config_outputs->optptr(opt_key, false) : nullptr; } + ConfigOption* resolve_output_symbol(const std::string &opt_key) const { + ConfigOption *out = nullptr; + if (this->config_outputs) + out = this->config_outputs->optptr(opt_key, false); + if (out == nullptr && this->context_data != nullptr && this->context_data->global_config) + out = this->context_data->global_config->optptr(opt_key); + if (out == nullptr) + out = this->config_local.optptr(opt_key); + return out; + } + void store_new_variable(const std::string &opt_key, std::unique_ptr &&opt, bool global_variable) { + assert(opt); + if (global_variable) { + assert(this->context_data != nullptr && this->context_data->global_config); + this->context_data->global_config->set_key_value(opt_key, opt.release()); + } else + this->config_local.set_key_value(opt_key, opt.release()); + } - template - static void legacy_variable_expansion( - const MyContext *ctx, - boost::iterator_range &opt_key, - std::string &output) + static void legacy_variable_expansion(const MyContext *ctx, IteratorRange &opt_key, std::string &output) { + if (ctx->skipping()) + return; + std::string opt_key_str(opt_key.begin(), opt_key.end()); const ConfigOption *opt = ctx->resolve_symbol(opt_key_str); size_t idx = ctx->current_extruder_id; @@ -783,29 +877,37 @@ namespace client char *endptr = nullptr; idx = strtol(opt_key_str.c_str() + idx + 1, &endptr, 10); if (endptr == nullptr || *endptr != 0) - ctx->throw_exception("Invalid vector index", boost::iterator_range(opt_key.begin() + idx + 1, opt_key.end())); + ctx->throw_exception("Invalid vector index", IteratorRange(opt_key.begin() + idx + 1, opt_key.end())); } } } if (opt == nullptr) - ctx->throw_exception("Variable does not exist", boost::iterator_range(opt_key.begin(), opt_key.end())); - if (opt->is_scalar()) + ctx->throw_exception("Variable does not exist", opt_key); + if (opt->is_scalar()) { + if (opt->is_nil()) + ctx->throw_exception("Trying to reference an undefined (nil) optional variable", opt_key); output = opt->serialize(); - else { + } else { const ConfigOptionVectorBase *vec = static_cast(opt); if (vec->empty()) ctx->throw_exception("Indexing an empty vector variable", opt_key); - output = vec->vserialize()[(idx >= vec->size()) ? 0 : idx]; + if (idx >= vec->size()) + idx = 0; + if (vec->is_nil(idx)) + ctx->throw_exception("Trying to reference an undefined (nil) element of vector of optional values", opt_key); + output = vec->vserialize()[idx]; } } - template static void legacy_variable_expansion2( - const MyContext *ctx, - boost::iterator_range &opt_key, - boost::iterator_range &opt_vector_index, - std::string &output) + const MyContext *ctx, + IteratorRange &opt_key, + IteratorRange &opt_vector_index, + std::string &output) { + if (ctx->skipping()) + return; + std::string opt_key_str(opt_key.begin(), opt_key.end()); const ConfigOption *opt = ctx->resolve_symbol(opt_key_str); if (opt == nullptr) { @@ -821,7 +923,7 @@ namespace client ctx->throw_exception("Trying to index a scalar variable", opt_key); const ConfigOptionVectorBase *vec = static_cast(opt); if (vec->empty()) - ctx->throw_exception("Indexing an empty vector variable", boost::iterator_range(opt_key.begin(), opt_key.end())); + ctx->throw_exception("Indexing an empty vector variable", opt_key); const ConfigOption *opt_index = ctx->resolve_symbol(std::string(opt_vector_index.begin(), opt_vector_index.end())); if (opt_index == nullptr) ctx->throw_exception("Variable does not exist", opt_key); @@ -830,133 +932,275 @@ namespace client int idx = opt_index->getInt(); if (idx < 0) ctx->throw_exception("Negative vector index", opt_key); - output = vec->vserialize()[(idx >= (int)vec->size()) ? 0 : idx]; + if (idx >= (int)vec->size()) + idx = 0; + if (vec->is_nil(idx)) + ctx->throw_exception("Trying to reference an undefined (nil) element of vector of optional values", opt_key); + output = vec->vserialize()[idx]; } - template static void resolve_variable( - const MyContext *ctx, - boost::iterator_range &opt_key, - OptWithPos &output) + const MyContext *ctx, + IteratorRange &opt_key, + OptWithPos &output) { - const ConfigOption *opt = ctx->resolve_symbol(std::string(opt_key.begin(), opt_key.end())); - if (opt == nullptr) { - opt = ctx->resolve_output_symbol(std::string(opt_key.begin(), opt_key.end())); - if (opt == nullptr) - ctx->throw_exception("Not a variable name", opt_key); - output.writable = true; + if (! ctx->skipping()) { + const std::string key{ opt_key.begin(), opt_key.end() }; + const ConfigOption *opt = ctx->resolve_symbol(key); + if (opt == nullptr) { + opt = ctx->resolve_output_symbol(key); + if (opt == nullptr) + ctx->throw_exception("Not a variable name", opt_key); + output.writable = true; + } + output.opt = opt; } - output.opt = opt; output.it_range = opt_key; } - template static void store_variable_index( - const MyContext *ctx, - OptWithPos &opt, - int index, - Iterator it_end, - OptWithPos &output) + const MyContext *ctx, + OptWithPos &opt, + int index, + Iterator it_end, + OptWithPos &output) { - if (! opt.opt->is_vector()) - ctx->throw_exception("Cannot index a scalar variable", opt.it_range); - if (index < 0) - ctx->throw_exception("Referencing a vector variable with a negative index", opt.it_range); - output = opt; - output.index = index; + if (! ctx->skipping()) { + if (! opt.opt->is_vector()) + ctx->throw_exception("Cannot index a scalar variable", opt.it_range); + if (index < 0) + ctx->throw_exception("Referencing a vector variable with a negative index", opt.it_range); + output = opt; + output.index = index; + } else + output = opt; output.it_range.end() = it_end; } - template - static void variable_value( - const MyContext *ctx, - OptWithPos &opt, - expr &output) + // Evaluating a scalar variable into expr, + // all possible ConfigOption types are supported. + static void scalar_variable_to_expr(const MyContext *ctx, OptWithPos &opt, expr &output) { - if (opt.opt->is_vector()) { - if (! opt.has_index()) - ctx->throw_exception("Referencing a vector variable when scalar is expected", opt.it_range); - const ConfigOptionVectorBase *vec = static_cast(opt.opt); - if (vec->empty()) - ctx->throw_exception("Indexing an empty vector variable", opt.it_range); - size_t idx = (opt.index < 0) ? 0 : (opt.index >= int(vec->size())) ? 0 : size_t(opt.index); - switch (opt.opt->type()) { - case coFloats: output.set_d(static_cast(opt.opt)->values[idx]); break; - case coInts: output.set_i(static_cast(opt.opt)->values[idx]); break; - case coStrings: output.set_s(static_cast(opt.opt)->values[idx]); break; - case coPercents: output.set_d(static_cast(opt.opt)->values[idx]); break; - case coPoints: output.set_s(to_string(static_cast(opt.opt)->values[idx])); break; - case coBools: output.set_b(static_cast(opt.opt)->values[idx] != 0); break; - // Orca: support enum vector variable type - case coEnums: output.set_i(static_cast(opt.opt)->values[idx]); break; - default: - ctx->throw_exception("Unknown vector variable type", opt.it_range); - } - } else { - assert(opt.opt->is_scalar()); - switch (opt.opt->type()) { - case coFloat: output.set_d(opt.opt->getFloat()); break; - case coInt: output.set_i(opt.opt->getInt()); break; - case coString: output.set_s(static_cast(opt.opt)->value); break; - case coPercent: output.set_d(opt.opt->getFloat()); break; - case coEnum: - case coPoint: output.set_s(opt.opt->serialize()); break; - case coBool: output.set_b(opt.opt->getBool()); break; - case coFloatOrPercent: - { - std::string opt_key(opt.it_range.begin(), opt.it_range.end()); - if (boost::ends_with(opt_key, "extrusion_width")) { - // Extrusion width supports defaults and a complex graph of dependencies. - output.set_d(Flow::extrusion_width(opt_key, *ctx, static_cast(ctx->current_extruder_id))); - } else if (! static_cast(opt.opt)->percent) { - // Not a percent, just return the value. - output.set_d(opt.opt->getFloat()); - } else { - // Resolve dependencies using the "ratio_over" link to a parent value. - const ConfigOptionDef *opt_def = print_config_def.get(opt_key); - assert(opt_def != nullptr); - double v = opt.opt->getFloat() * 0.01; // percent to ratio - for (;;) { - const ConfigOption *opt_parent = opt_def->ratio_over.empty() ? nullptr : ctx->resolve_symbol(opt_def->ratio_over); - if (opt_parent == nullptr) - ctx->throw_exception("FloatOrPercent variable failed to resolve the \"ratio_over\" dependencies", opt.it_range); - if (boost::ends_with(opt_def->ratio_over, "extrusion_width")) { - // Extrusion width supports defaults and a complex graph of dependencies. - assert(opt_parent->type() == coFloatOrPercent); - v *= Flow::extrusion_width(opt_def->ratio_over, static_cast(opt_parent), *ctx, static_cast(ctx->current_extruder_id)); - break; - } - if (opt_parent->type() == coFloat || opt_parent->type() == coFloatOrPercent) { - v *= opt_parent->getFloat(); - if (opt_parent->type() == coFloat || ! static_cast(opt_parent)->percent) - break; - v *= 0.01; // percent to ratio - } - // Continue one level up in the "ratio_over" hierarchy. - opt_def = print_config_def.get(opt_def->ratio_over); - assert(opt_def != nullptr); - } - output.set_d(v); - } - break; - } - default: - ctx->throw_exception("Unknown scalar variable type", opt.it_range); - } - } + if (ctx->skipping()) + return; + assert(opt.opt->is_scalar()); + + if (opt.opt->is_nil()) + ctx->throw_exception("Trying to reference an undefined (nil) optional variable", opt.it_range); + + switch (opt.opt->type()) { + case coFloat: output.set_d(opt.opt->getFloat()); break; + case coInt: output.set_i(opt.opt->getInt()); break; + case coString: output.set_s(static_cast(opt.opt)->value); break; + case coPercent: output.set_d(opt.opt->getFloat()); break; + case coEnum: + case coPoint: output.set_s(opt.opt->serialize()); break; + case coBool: output.set_b(opt.opt->getBool()); break; + case coFloatOrPercent: + { + std::string opt_key(opt.it_range.begin(), opt.it_range.end()); + if (boost::ends_with(opt_key, "extrusion_width")) { + // Extrusion width supports defaults and a complex graph of dependencies. + output.set_d(Flow::extrusion_width(opt_key, *ctx, static_cast(ctx->current_extruder_id))); + } else if (! static_cast(opt.opt)->percent) { + // Not a percent, just return the value. + output.set_d(opt.opt->getFloat()); + } else { + // Resolve dependencies using the "ratio_over" link to a parent value. + const ConfigOptionDef *opt_def = print_config_def.get(opt_key); + assert(opt_def != nullptr); + double v = opt.opt->getFloat() * 0.01; // percent to ratio + for (;;) { + const ConfigOption *opt_parent = opt_def->ratio_over.empty() ? nullptr : ctx->resolve_symbol(opt_def->ratio_over); + if (opt_parent == nullptr) + ctx->throw_exception("FloatOrPercent variable failed to resolve the \"ratio_over\" dependencies", opt.it_range); + if (boost::ends_with(opt_def->ratio_over, "extrusion_width")) { + // Extrusion width supports defaults and a complex graph of dependencies. + assert(opt_parent->type() == coFloatOrPercent); + v *= Flow::extrusion_width(opt_def->ratio_over, static_cast(opt_parent), *ctx, static_cast(ctx->current_extruder_id)); + break; + } + if (opt_parent->type() == coFloat || opt_parent->type() == coFloatOrPercent) { + v *= opt_parent->getFloat(); + if (opt_parent->type() == coFloat || ! static_cast(opt_parent)->percent) + break; + v *= 0.01; // percent to ratio + } + // Continue one level up in the "ratio_over" hierarchy. + opt_def = print_config_def.get(opt_def->ratio_over); + assert(opt_def != nullptr); + } + output.set_d(v); + } + break; + } + default: + ctx->throw_exception("Unsupported scalar variable type", opt.it_range); + } + } + + // Evaluating one element of a vector variable. + // all possible ConfigOption types are supported. + static void vector_element_to_expr(const MyContext *ctx, OptWithPos &opt, expr &output) + { + if (ctx->skipping()) + return; + + assert(opt.opt->is_vector()); + if (! opt.has_index()) + ctx->throw_exception("Referencing a vector variable when scalar is expected", opt.it_range); + const ConfigOptionVectorBase* vec = static_cast(opt.opt); + if (vec->empty()) + ctx->throw_exception("Indexing an empty vector variable", opt.it_range); + size_t idx = (opt.index < 0) ? 0 : (opt.index >= int(vec->size())) ? 0 : size_t(opt.index); + if (vec->is_nil(idx)) + ctx->throw_exception("Trying to reference an undefined (nil) element of vector of optional values", opt.it_range); + switch (opt.opt->type()) { + case coFloats: output.set_d(static_cast(opt.opt)->values[idx]); break; + case coInts: output.set_i(static_cast(opt.opt)->values[idx]); break; + case coStrings: output.set_s(static_cast(opt.opt)->values[idx]); break; + case coPercents: output.set_d(static_cast(opt.opt)->values[idx]); break; + case coPoints: output.set_s(to_string(static_cast(opt.opt)->values[idx])); break; + case coBools: output.set_b(static_cast(opt.opt)->values[idx] != 0); break; + //case coEnums: output.set_s(opt.opt->vserialize()[idx]); break; + default: + ctx->throw_exception("Unsupported vector variable type", opt.it_range); + } + } + + static void check_writable(const MyContext *ctx, OptWithPos &opt) { + if (! opt.writable) + ctx->throw_exception("Cannot modify a read-only variable", opt.it_range); + } + + static void check_numeric(const expr ¶m) { + if (! param.numeric_type()) + param.throw_exception("Right side is not a numeric expression"); + }; + + static size_t evaluate_count(const expr &expr_count) { + if (expr_count.type() != expr::TYPE_INT) + expr_count.throw_exception("Expected number of elements to fill a vector with."); + int count = expr_count.i(); + if (count < 0) + expr_count.throw_exception("Negative number of elements specified."); + return size_t(count); + }; + + static void scalar_variable_assign_scalar(const MyContext *ctx, OptWithPos &lhs, const expr &rhs) + { + assert(! ctx->skipping()); + assert(lhs.opt->is_scalar()); + check_writable(ctx, lhs); + ConfigOption *wropt = const_cast(lhs.opt); + switch (wropt->type()) { + case coFloat: + check_numeric(rhs); + static_cast(wropt)->value = rhs.as_d(); + break; + case coInt: + check_numeric(rhs); + static_cast(wropt)->value = rhs.as_i(); + break; + case coString: + static_cast(wropt)->value = rhs.to_string(); + break; + case coPercent: + check_numeric(rhs); + static_cast(wropt)->value = rhs.as_d(); + break; + case coBool: + if (rhs.type() != expr::TYPE_BOOL) + ctx->throw_exception("Right side is not a boolean expression", rhs.it_range); + static_cast(wropt)->value = rhs.b(); + break; + default: + ctx->throw_exception("Unsupported output scalar variable type", lhs.it_range); + } + } + + static void vector_variable_element_assign_scalar(const MyContext *ctx, OptWithPos &lhs, const expr &rhs) + { + assert(! ctx->skipping()); + assert(lhs.opt->is_vector()); + check_writable(ctx, lhs); + if (! lhs.has_index()) + ctx->throw_exception("Referencing an output vector variable when scalar is expected", lhs.it_range); + ConfigOptionVectorBase *vec = const_cast(static_cast(lhs.opt)); + if (vec->empty()) + ctx->throw_exception("Indexing an empty vector variable", lhs.it_range); + if (lhs.index >= int(vec->size())) + ctx->throw_exception("Index out of range", lhs.it_range); + switch (lhs.opt->type()) { + case coFloats: + check_numeric(rhs); + static_cast(vec)->values[lhs.index] = rhs.as_d(); + break; + case coInts: + check_numeric(rhs); + static_cast(vec)->values[lhs.index] = rhs.as_i(); + break; + case coStrings: + static_cast(vec)->values[lhs.index] = rhs.to_string(); + break; + case coPercents: + check_numeric(rhs); + static_cast(vec)->values[lhs.index] = rhs.as_d(); + break; + case coBools: + if (rhs.type() != expr::TYPE_BOOL) + ctx->throw_exception("Right side is not a boolean expression", rhs.it_range); + static_cast(vec)->values[lhs.index] = rhs.b(); + break; + default: + ctx->throw_exception("Unsupported output vector variable type", lhs.it_range); + } + } + + static void vector_variable_assign_expr_with_count(const MyContext *ctx, OptWithPos &lhs, const expr &rhs_count, const expr &rhs_value) + { + assert(! ctx->skipping()); + size_t count = evaluate_count(rhs_count); + auto *opt = const_cast(lhs.opt); + switch (lhs.opt->type()) { + case coFloats: + check_numeric(rhs_value); + static_cast(opt)->values.assign(count, rhs_value.as_d()); + break; + case coInts: + check_numeric(rhs_value); + static_cast(opt)->values.assign(count, rhs_value.as_i()); + break; + case coStrings: + static_cast(opt)->values.assign(count, rhs_value.to_string()); + break; + case coBools: + if (rhs_value.type() != expr::TYPE_BOOL) + rhs_value.throw_exception("Right side is not a boolean expression"); + static_cast(opt)->values.assign(count, rhs_value.b()); + break; + default: assert(false); + } + } + + static void variable_value(const MyContext *ctx, OptWithPos &opt, expr &output) + { + if (! ctx->skipping()) { + if (opt.opt->is_vector()) + vector_element_to_expr(ctx, opt, output); + else + scalar_variable_to_expr(ctx, opt, output); + } output.it_range = opt.it_range; } // Return a boolean value, true if the scalar variable referenced by "opt" is nullable and it has a nil value. // Return a boolean value, true if an element of a vector variable referenced by "opt[index]" is nullable and it has a nil value. - template - static void is_nil_test( - const MyContext *ctx, - OptWithPos &opt, - expr &output) + static void is_nil_test(const MyContext *ctx, OptWithPos &opt, expr &output) { - if (opt.opt->is_vector()) { + if (ctx->skipping()) { + } else if (opt.opt->is_vector()) { if (! opt.has_index()) ctx->throw_exception("Referencing a vector variable when scalar is expected", opt.it_range); const ConfigOptionVectorBase *vec = static_cast(opt.opt); @@ -970,112 +1214,354 @@ namespace client output.it_range = opt.it_range; } - // Decoding a scalar variable symbol "opt", assigning it a value of "param". - template - static void variable_assign( - const MyContext *ctx, - OptWithPos &opt, - expr ¶m, - // Not used, just clear it. - std::string &out) + // Reference to an existing symbol, or a name of a new symbol. + struct NewOldVariable { + std::string name; + IteratorRange it_range; + ConfigOption *opt{ nullptr }; + }; + static void new_old_variable( + const MyContext *ctx, + bool global_variable, + const IteratorRange &it_range, + NewOldVariable &out) { - if (! opt.writable) - ctx->throw_exception("Cannot modify a read-only variable", opt.it_range); - auto check_numeric = [](const expr ¶m) { - if (! param.numeric_type()) - param.throw_exception("Right side is not a numeric expression"); - }; - if (opt.opt->is_vector()) { - if (! opt.has_index()) - ctx->throw_exception("Referencing an output vector variable when scalar is expected", opt.it_range); - ConfigOptionVectorBase *vec = const_cast(static_cast(opt.opt)); - if (vec->empty()) - ctx->throw_exception("Indexing an empty vector variable", opt.it_range); - if (opt.index >= int(vec->size())) - ctx->throw_exception("Index out of range", opt.it_range); - switch (opt.opt->type()) { - case coFloats: - check_numeric(param); - static_cast(vec)->values[opt.index] = param.as_d(); - break; - case coInts: - check_numeric(param); - static_cast(vec)->values[opt.index] = param.as_i(); - break; - case coStrings: - static_cast(vec)->values[opt.index] = param.to_string(); - break; - case coPercents: - check_numeric(param); - static_cast(vec)->values[opt.index] = param.as_d(); - break; - case coBools: - if (param.type() != expr::TYPE_BOOL) - ctx->throw_exception("Right side is not a boolean expression", param.it_range); - static_cast(vec)->values[opt.index] = param.b(); - break; - default: - ctx->throw_exception("Unsupported output vector variable type", opt.it_range); + if (! ctx->skipping()) { + t_config_option_key key(std::string(it_range.begin(), it_range.end())); + if (const ConfigOption* opt = ctx->resolve_symbol(key); opt) + ctx->throw_exception("Symbol is already defined in read-only system dictionary", it_range); + if (ctx->config_outputs && ctx->config_outputs->optptr(key)) + ctx->throw_exception("Symbol is already defined as system output variable", it_range); + bool has_global_dictionary = ctx->context_data != nullptr && ctx->context_data->global_config; + if (global_variable) { + if (! has_global_dictionary) + ctx->throw_exception("Global variables are not available in this context", it_range); + if (ctx->config_local.optptr(key)) + ctx->throw_exception("Variable name already defined in local scope", it_range); + out.opt = ctx->context_data->global_config->optptr(key); + } else { + if (has_global_dictionary && ctx->context_data->global_config->optptr(key)) + ctx->throw_exception("Variable name already defined in global scope", it_range); + out.opt = ctx->config_local.optptr(key); } + out.name = std::move(key); + } + out.it_range = it_range; + } + + // Decoding a scalar variable symbol "opt", assigning it a value of "param". + static void scalar_variable_assign_scalar_expression(const MyContext *ctx, OptWithPos &opt, const expr ¶m) + { + if (! ctx->skipping()) { + check_writable(ctx, opt); + if (opt.opt->is_vector()) + vector_variable_element_assign_scalar(ctx, opt, param); + else + scalar_variable_assign_scalar(ctx, opt, param); + } + } + + static void scalar_variable_new_from_scalar_expression( + const MyContext *ctx, + bool global_variable, + NewOldVariable &lhs, + const expr &rhs) + { + if (ctx->skipping()) { + } else if (lhs.opt) { + if (lhs.opt->is_vector()) + rhs.throw_exception("Cannot assign a scalar value to a vector variable."); + OptWithPos lhs_opt{ lhs.opt, lhs.it_range, true }; + scalar_variable_assign_scalar(ctx, lhs_opt, rhs); } else { - assert(opt.opt->is_scalar()); - ConfigOption *wropt = const_cast(opt.opt); - switch (wropt->type()) { - case coFloat: - check_numeric(param); - static_cast(wropt)->value = param.as_d(); - break; - case coInt: - check_numeric(param); - static_cast(wropt)->value = param.as_i(); - break; - case coString: - static_cast(wropt)->value = param.to_string(); - break; - case coPercent: - check_numeric(param); - static_cast(wropt)->value = param.as_d(); - break; - case coBool: - if (param.type() != expr::TYPE_BOOL) - ctx->throw_exception("Right side is not a boolean expression", param.it_range); - static_cast(wropt)->value = param.b(); - break; + std::unique_ptr opt_new; + switch (rhs.type()) { + case expr::TYPE_BOOL: opt_new = std::make_unique(rhs.b()); break; + case expr::TYPE_INT: opt_new = std::make_unique(rhs.i()); break; + case expr::TYPE_DOUBLE: opt_new = std::make_unique(rhs.d()); break; + case expr::TYPE_STRING: opt_new = std::make_unique(rhs.s()); break; + default: assert(false); + } + const_cast(ctx)->store_new_variable(lhs.name, std::move(opt_new), global_variable); + } + } + + static void vector_variable_new_from_array( + const MyContext *ctx, + bool global_variable, + NewOldVariable &lhs, + const expr &rhs_count, + const expr &rhs_value) + { + if (ctx->skipping()) { + } else if (lhs.opt) { + if (lhs.opt->is_scalar()) + rhs_value.throw_exception("Cannot assign a vector value to a scalar variable."); + OptWithPos lhs_opt{ lhs.opt, lhs.it_range, true }; + vector_variable_assign_expr_with_count(ctx, lhs_opt, rhs_count, rhs_value); + } else { + size_t count = evaluate_count(rhs_count); + std::unique_ptr opt_new; + switch (rhs_value.type()) { + case expr::TYPE_BOOL: opt_new = std::make_unique(count, rhs_value.b()); break; + case expr::TYPE_INT: opt_new = std::make_unique(count, rhs_value.i()); break; + case expr::TYPE_DOUBLE: opt_new = std::make_unique(count, rhs_value.d()); break; + case expr::TYPE_STRING: opt_new = std::make_unique(count, rhs_value.s()); break; + default: assert(false); + } + const_cast(ctx)->store_new_variable(lhs.name, std::move(opt_new), global_variable); + } + } + + static void vector_variable_assign_array( + const MyContext *ctx, + OptWithPos &lhs, + const expr &rhs_count, + const expr &rhs_value) + { + if (! ctx->skipping()) { + check_writable(ctx, lhs); + if (lhs.opt->is_scalar()) + rhs_value.throw_exception("Cannot assign a vector value to a scalar variable."); + vector_variable_assign_expr_with_count(ctx, lhs, rhs_count, rhs_value); + } + } + + template + static void fill_vector_from_initializer_list(ConfigOption *opt, const std::vector &il, RightValueEvaluate rv_eval) { + auto& out = static_cast(opt)->values; + out.clear(); + out.reserve(il.size()); + for (const expr& i : il) + out.emplace_back(rv_eval(i)); + } + + static void vector_variable_assign_initializer_list(const MyContext *ctx, OptWithPos &lhs, const std::vector &il) + { + if (ctx->skipping()) + return; + + check_writable(ctx, lhs); + + if (lhs.opt->is_scalar()) { + if (il.size() == 1) + // scalar_var = ( scalar ) + scalar_variable_assign_scalar_expression(ctx, lhs, il.front()); + else + // scalar_var = () + // or + // scalar_var = ( scalar, scalar, ... ) + ctx->throw_exception("Cannot assign a vector value to a scalar variable.", lhs.it_range); + } + + auto check_numeric_vector = [](const std::vector &il) { + for (auto &i : il) + if (! i.numeric_type()) + i.throw_exception("Right side is not a numeric expression"); + }; + + ConfigOption *opt = const_cast(lhs.opt); + switch (lhs.opt->type()) { + case coFloats: + check_numeric_vector(il); + fill_vector_from_initializer_list(opt, il, [](auto &v){ return v.as_d(); }); + break; + case coInts: + check_numeric_vector(il); + fill_vector_from_initializer_list(opt, il, [](auto &v){ return v.as_i(); }); + break; + case coStrings: + fill_vector_from_initializer_list(opt, il, [](auto &v){ return v.to_string(); }); + break; + case coBools: + for (auto &i : il) + if (i.type() != expr::TYPE_BOOL) + i.throw_exception("Right side is not a boolean expression"); + fill_vector_from_initializer_list(opt, il, [](auto &v){ return v.b(); }); + break; + default: assert(false); + } + } + + static void vector_variable_new_from_initializer_list( + const MyContext *ctx, + bool global_variable, + NewOldVariable &lhs, + const std::vector &il) + { + if (ctx->skipping()) + return; + + if (lhs.opt) { + // Assign to an existing vector variable. + OptWithPos lhs_opt{ lhs.opt, lhs.it_range, true }; + vector_variable_assign_initializer_list(ctx, lhs_opt, il); + } else { + if (il.empty()) + ctx->throw_exception("Cannot create vector variable from an empty initializer list, because its type cannot be deduced.", lhs.it_range); + // Allocate a new vector variable. + // First guesstimate type of the output vector. + size_t num_bool = 0; + size_t num_int = 0; + size_t num_double = 0; + size_t num_string = 0; + for (auto &i : il) + switch (i.type()) { + case expr::TYPE_BOOL: ++ num_bool; break; + case expr::TYPE_INT: ++ num_int; break; + case expr::TYPE_DOUBLE: ++ num_double; break; + case expr::TYPE_STRING: ++ num_string; break; + default: assert(false); + } + std::unique_ptr opt_new; + if (num_string > 0) + // Convert everything to strings. + opt_new = std::make_unique(); + else if (num_bool > 0) { + if (num_double + num_int > 0) + ctx->throw_exception("Right side is not valid: Mixing numeric and boolean types.", IteratorRange{ il.front().it_range.begin(), il.back().it_range.end() }); + opt_new = std::make_unique(); + } else { + // Output is numeric. + if (num_double == 0) + opt_new = std::make_unique(); + else + opt_new = std::make_unique(); + } + OptWithPos lhs_opt{ opt_new.get(), lhs.it_range, true }; + vector_variable_assign_initializer_list(ctx, lhs_opt, il); + const_cast(ctx)->store_new_variable(lhs.name, std::move(opt_new), global_variable); + } + } + + static bool is_vector_variable_reference(const OptWithPos &var) { + return ! var.empty() && ! var.has_index() && var.opt->is_vector(); + } + + // Called when checking whether the NewOldVariable could be assigned a vectir right hand side. + static bool could_be_vector_variable_reference(const NewOldVariable &var) { + return var.opt == nullptr || var.opt->is_vector(); + } + + static void copy_vector_variable_to_vector_variable(const MyContext *ctx, OptWithPos &lhs, const OptWithPos &rhs) + { + if (ctx->skipping()) + return; + + check_writable(ctx, lhs); + assert(lhs.opt->is_vector()); + if (rhs.has_index() || ! rhs.opt->is_vector()) + ctx->throw_exception("Cannot assign scalar to a vector", lhs.it_range); + if (rhs.opt->is_nil()) + ctx->throw_exception("Some elements of the right hand side vector variable of optional values are undefined (nil)", rhs.it_range); + if (lhs.opt->type() != rhs.opt->type()) { + // Vector types are not compatible. + switch (lhs.opt->type()) { + case coFloats: + ctx->throw_exception("Left hand side is a float vector, while the right hand side is not.", lhs.it_range); + case coInts: + ctx->throw_exception("Left hand side is an int vector, while the right hand side is not.", lhs.it_range); + case coStrings: + ctx->throw_exception("Left hand side is a string vector, while the right hand side is not.", lhs.it_range); + case coBools: + ctx->throw_exception("Left hand side is a bool vector, while the right hand side is not.", lhs.it_range); default: - ctx->throw_exception("Unsupported output scalar variable type", opt.it_range); + ctx->throw_exception("Left hand side / right hand side vectors are not compatible.", lhs.it_range); } } - out.clear(); + const_cast(lhs.opt)->set(rhs.opt); + } + + static bool vector_variable_new_from_copy( + const MyContext *ctx, + bool global_variable, + NewOldVariable &lhs, + const OptWithPos &rhs) + { + if (ctx->skipping()) + // Skipping, continue parsing. + return true; + + if (lhs.opt) { + assert(lhs.opt->is_vector()); + OptWithPos lhs_opt{ lhs.opt, lhs.it_range, true }; + copy_vector_variable_to_vector_variable(ctx, lhs_opt, rhs); + } else { + if (rhs.has_index() || ! rhs.opt->is_vector()) + // Stop parsing, let the other rules resolve this case. + return false; + if (rhs.opt->is_nil()) + ctx->throw_exception("Some elements of the right hand side vector variable of optional values are undefined (nil)", rhs.it_range); + // Clone the vector variable. + std::unique_ptr opt_new; + if (one_of(rhs.opt->type(), { coFloats, coInts, coStrings, coBools })) + opt_new = std::unique_ptr(rhs.opt->clone()); + else if (rhs.opt->type() == coPercents) + opt_new = std::make_unique(static_cast(rhs.opt)->values); + else + ctx->throw_exception("Duplicating this type of vector variable is not supported", rhs.it_range); + const_cast(ctx)->store_new_variable(lhs.name, std::move(opt_new), global_variable); + } + // Continue parsing. + return true; + } + + static void initializer_list_append(std::vector &list, expr ¶m) + { + if (param.type() != expr::TYPE_EMPTY) + // not skipping + list.emplace_back(std::move(param)); + } + + static void is_vector_empty(const MyContext *ctx, OptWithPos &opt, expr &out) + { + if (! ctx->skipping()) { + if (opt.has_index() || ! opt.opt->is_vector()) + ctx->throw_exception("parameter of empty() is not a vector variable", opt.it_range); + out.set_b(static_cast(opt.opt)->size() == 0); + } + out.it_range = opt.it_range; + } + + static void vector_size(const MyContext *ctx, OptWithPos &opt, expr &out) + { + if (! ctx->skipping()) { + if (opt.has_index() || ! opt.opt->is_vector()) + ctx->throw_exception("parameter of size() is not a vector variable", opt.it_range); + out.set_i(int(static_cast(opt.opt)->size())); + } + out.it_range = opt.it_range; } // Verify that the expression returns an integer, which may be used // to address a vector. - template - static void evaluate_index(expr &expr_index, int &output) + static void evaluate_index(expr &expr_index, int &output) { - if (expr_index.type() != expr::TYPE_INT) - expr_index.throw_exception("Non-integer index is not allowed to address a vector variable."); - output = expr_index.i(); + if (expr_index.type() != expr::TYPE_EMPTY) { + if (expr_index.type() != expr::TYPE_INT) + expr_index.throw_exception("Non-integer index is not allowed to address a vector variable."); + output = expr_index.i(); + } } - template - static void random(const MyContext *ctx, expr ¶m1, expr ¶m2) + static void random(const MyContext *ctx, expr ¶m1, expr ¶m2) { + if (ctx->skipping()) + return; + if (ctx->context_data == nullptr) ctx->throw_exception("Random number generator not available in this context.", - boost::iterator_range(param1.it_range.begin(), param2.it_range.end())); - expr::random(param1, param2, ctx->context_data->rng); + IteratorRange(param1.it_range.begin(), param2.it_range.end())); + expr::random(param1, param2, ctx->context_data->rng); } - template - static void throw_exception(const std::string &msg, const boost::iterator_range &it_range) + static void throw_exception(const std::string &msg, const IteratorRange &it_range) { // An asterix is added to the start of the string to differentiate the boost::spirit::info::tag content // between the grammer terminal / non-terminal symbol name and a free-form error message. - boost::throw_exception(qi::expectation_failure(it_range.begin(), it_range.end(), spirit::info(std::string("*") + msg))); + boost::throw_exception(qi::expectation_failure(it_range.begin(), it_range.end(), spirit::info(std::string("*") + msg))); } - template static void process_error_message(const MyContext *context, const boost::spirit::info &info, const Iterator &it_begin, const Iterator &it_end, const Iterator &it_error) { std::string &msg = const_cast(context)->error_message; @@ -1122,37 +1608,48 @@ namespace client msg += ' '; msg += "^\n"; } + + private: + // For skipping execution of inactive conditional branches. + mutable int m_depth_suppressed{ 0 }; }; - template struct InterpolateTableContext { struct Item { - double x; - boost::iterator_range it_range_x; - double y; + double x; + IteratorRange it_range_x; + double y; }; std::vector table; - static void init(const expr &x) { - if (!x.numeric_type()) - x.throw_exception("Interpolation value must be a number."); + static void init(const expr &x) { + if (x.type() != expr::TYPE_EMPTY) { + if (!x.numeric_type()) + x.throw_exception("Interpolation value must be a number."); + } } - static void add_pair(const expr &x, const expr &y, InterpolateTableContext &table) { - if (! x.numeric_type()) - x.throw_exception("X value of a table point must be a number."); - if (! y.numeric_type()) - y.throw_exception("Y value of a table point must be a number."); - table.table.push_back({ x.as_d(), x.it_range, y.as_d() }); + static void add_pair(const expr &x, const expr &y, InterpolateTableContext &table) { + if (x.type() != expr::TYPE_EMPTY) { + if (! x.numeric_type()) + x.throw_exception("X value of a table point must be a number."); + if (! y.numeric_type()) + y.throw_exception("Y value of a table point must be a number."); + table.table.push_back({ x.as_d(), x.it_range, y.as_d() }); + } } - static void evaluate(const expr &expr_x, const InterpolateTableContext &table, expr &out) { + static void evaluate(const expr &expr_x, const InterpolateTableContext &table, expr &out) { + if (expr_x.type() == expr::TYPE_EMPTY) + return; + // Check whether the table X values are sorted. double x = expr_x.as_d(); + assert(! std::isnan(x)); bool evaluated = false; for (size_t i = 1; i < table.table.size(); ++i) { double x0 = table.table[i - 1].x; double x1 = table.table[i].x; if (x0 > x1) - boost::throw_exception(qi::expectation_failure( + boost::throw_exception(qi::expectation_failure( table.table[i - 1].it_range_x.begin(), table.table[i].it_range_x.end(), spirit::info("X coordinates of the table must be increasing"))); if (! evaluated && x >= x0 && x <= x1) { double y0 = table.table[i - 1].y; @@ -1170,9 +1667,9 @@ namespace client } if (! evaluated) { // Clamp x into the table range with EPSILON. - if (x > table.table.front().x - EPSILON) + if (double x0 = table.table.front().x; x > x0 - EPSILON && x < x0) out.set_d(table.table.front().y); - else if (x < table.table.back().x + EPSILON) + else if (double x1 = table.table.back().x; x > x1 && x < x1 + EPSILON) out.set_d(table.table.back().y); else // The value is really outside the table range. @@ -1181,8 +1678,7 @@ namespace client } }; - template - std::ostream& operator<<(std::ostream &os, const InterpolateTableContext &table_context) + std::ostream& operator<<(std::ostream &os, const InterpolateTableContext &table_context) { for (const auto &item : table_context.table) os << "(" << item.x << "," << item.y << ")"; @@ -1196,6 +1692,7 @@ namespace client { "text", "Invalid text." }, { "text_block", "Invalid text block." }, { "macro", "Invalid macro." }, + { "repeat", "Unknown syntax error" }, { "if_else_output", "Not an {if}{else}{endif} macro." }, { "switch_output", "Not a {switch} macro." }, { "legacy_variable_expansion", "Expecting a legacy variable expansion format" }, @@ -1212,14 +1709,12 @@ namespace client { "optional_parameter", "Expecting a closing brace or an optional parameter." }, { "one_of_list", "Expecting a list of string patterns (simple text or rexep)" }, { "variable_reference", "Expecting a variable reference."}, - { "is_nil_test", "Expecting a scalar variable reference."}, { "variable", "Expecting a variable name."}, { "regular_expression", "Expecting a regular expression."} }; // For debugging the boost::spirit parsers. Print out the string enclosed in it_range. - template - std::ostream& operator<<(std::ostream& os, const boost::iterator_range &it_range) + std::ostream& operator<<(std::ostream& os, const IteratorRange &it_range) { os << std::string(it_range.begin(), it_range.end()); return os; @@ -1234,7 +1729,7 @@ namespace client // This parser is to be used inside a raw[] directive to accept a single valid UTF-8 character. // If an invalid UTF-8 sequence is encountered, a qi::expectation_failure is thrown. - struct utf8_char_skipper_parser : qi::primitive_parser + struct utf8_char_parser : qi::primitive_parser { // Define the attribute type exposed by this parser component template @@ -1243,9 +1738,10 @@ namespace client typedef wchar_t type; }; - // This function is called during the actual parsing process + // This function is called during the actual parsing process to skip whitespaces. + // Also it throws if it encounters valid or invalid UTF-8 sequence. template - bool parse(Iterator& first, Iterator const& last, Context& context, Skipper const& skipper, Attribute& attr) const + bool parse(Iterator &first, Iterator const &last, Context &context, Skipper const &skipper, Attribute& attr) const { // The skipper shall always be empty, any white space will be accepted. // skip_over(first, last, skipper); @@ -1283,7 +1779,7 @@ namespace client first = it; return true; err: - MyContext::throw_exception("Invalid utf8 sequence", boost::iterator_range(first, last)); + MyContext::throw_exception("Invalid utf8 sequence", IteratorRange(first, last)); return false; } @@ -1295,12 +1791,131 @@ namespace client } }; + // This parser is to be used inside a raw[] directive to accept a single valid UTF-8 character. + // If an invalid UTF-8 sequence is encountered, a qi::expectation_failure is thrown. + struct ascii_char_skipper_parser : public utf8_char_parser + { + // This function is called during the actual parsing process + template + bool parse(Iterator &first, Iterator const &last, Context &context, Skipper const &skipper, Attribute &attr) const + { + Iterator it = first; + // Let the UTF-8 parser throw if it encounters an invalid UTF-8 sequence. + if (! utf8_char_parser::parse(it, last, context, skipper, attr)) + return false; + char c = *first; + if (it - first > 1 || c < 0) + MyContext::throw_exception("Non-ASCII7 characters are only allowed inside text blocks and string literals, not inside code blocks.", IteratorRange(first, it)); + if (c == '\r' || c == '\n' || c == '\t' || c == ' ') { + // Skip the whitespaces + ++ first; + return true; + } else + // Stop skipping, let this 7bit ASCII character be processed. + return false; + } + + // This function is called during error handling to create a human readable string for the error context. + template + spirit::info what(Context&) const + { + return spirit::info("ASCII7_char"); + } + }; + + struct FactorActions { + static void set_start_pos(Iterator &start_pos, expr &out) + { out.it_range = IteratorRange(start_pos, start_pos); } + static void int_(const MyContext *ctx, int &value, Iterator &end_pos, expr &out) { + if (ctx->skipping()) { + out.reset(); + out.it_range.end() = end_pos; + } else + out = expr(value, out.it_range.begin(), end_pos); + } + static void double_(const MyContext *ctx, double &value, Iterator &end_pos, expr &out) { + if (ctx->skipping()) { + out.reset(); + out.it_range.end() = end_pos; + } else + out = expr(value, out.it_range.begin(), end_pos); + } + static void bool_(const MyContext *ctx, bool &value, Iterator &end_pos, expr &out) { + if (ctx->skipping()) { + out.reset(); + out.it_range.end() = end_pos; + } else + out = expr(value, out.it_range.begin(), end_pos); + } + static void string_(const MyContext *ctx, IteratorRange &it_range, expr &out) { + if (ctx->skipping()) { + out.reset(); + out.it_range = it_range; + } else { + // Unescape the string, UTF-8 safe. + std::string s; + auto begin = std::next(it_range.begin()); + auto end = std::prev(it_range.end()); + assert(begin <= end); + { + // 1) Get the size of the string after unescaping. + size_t len = 0; + for (auto it = begin; it != end;) { + if (*it == '\\') { + if (++ it == end || + (*it != 'r' && *it != 'n' && *it != '"' && *it != '\\')) + ctx->throw_exception("Invalid escape sequence", {std::prev(it), std::next(it) }); + ++ len; + ++ it; + } else { + size_t n = get_utf8_sequence_length(&*it, end - it); + len += n; + it += n; + } + } + // and reserve the string. + s.reserve(len); + } + // 2) Copy & unescape the string. + for (auto it = begin; it != end;) { + if (*it == '\\') { + char c = *(++ it); + if (c == 'r') + c = '\r'; + else if (c == 'n') + c = '\n'; + s += c; + ++ it; + } else { + size_t n = get_utf8_sequence_length(&*it, end - it); + s.append(&*it, n); + it += n; + } + } + out = expr(std::move(s), it_range.begin(), it_range.end()); + } + } + static void expr_(expr &value, Iterator &end_pos, expr &out) + { auto begin_pos = out.it_range.begin(); out = expr(std::move(value), begin_pos, end_pos); } + static void minus_(expr &value, expr &out) + { out = value.unary_minus(out.it_range.begin()); } + static void not_(expr &value, expr &out) + { out = value.unary_not(out.it_range.begin()); } + static void to_int(expr &value, expr &out) + { out = value.unary_integer(out.it_range.begin()); } + static void round(expr &value, expr &out) + { out = value.round(out.it_range.begin()); } + // For indicating "no optional parameter". + static void noexpr(expr &out) { out.reset(); } + }; + + using skipper = ascii_char_skipper_parser; + /////////////////////////////////////////////////////////////////////////// // Our macro_processor grammar /////////////////////////////////////////////////////////////////////////// // Inspired by the C grammar rules https://www.lysator.liu.se/c/ANSI-C-grammar-y.html - template - struct macro_processor : qi::grammar, spirit_encoding::space_type> + struct macro_processor : qi::grammar, skipper> { macro_processor() : macro_processor::base_type(start) { @@ -1314,7 +1929,7 @@ namespace client qi::no_skip_type no_skip; qi::real_parser strict_double; spirit_encoding::char_type char_; - utf8_char_skipper_parser utf8char; + utf8_char_parser utf8char; spirit::bool_type bool_; spirit::int_type int_; spirit::double_type double_; @@ -1339,19 +1954,19 @@ namespace client // Also the start symbol switches between the "full macro syntax" and a "boolean expression only", // depending on the context->just_boolean_expression flag. This way a single static expression parser // could serve both purposes. - start = eps[px::bind(&MyContext::evaluate_full_macro, _r1, _a)] > - ( (eps(_a==true) > text_block(_r1) [_val=_1]) - | conditional_expression(_r1) [ px::bind(&expr::evaluate_boolean_to_string, _1, _val) ] + start = + ( (eps(px::bind(&MyContext::evaluate_full_macro, _r1)) > text_block(_r1) [_val=_1]) + | conditional_expression(_r1) [ px::bind(&expr::evaluate_boolean_to_string, _1, _val) ] ) > eoi; start.name("start"); - qi::on_error(start, px::bind(&MyContext::process_error_message, _r1, _4, _1, _2, _3)); + qi::on_error(start, px::bind(&MyContext::process_error_message, _r1, _4, _1, _2, _3)); text_block = *( text [_val+=_1] // Allow back tracking after '{' in case of a text_block embedded inside a condition. // In that case the inner-most {else} wins and the {if}/{elsif}/{else} shall be paired. // {elsif}/{else} without an {if} will be allowed to back track from the embedded text_block. - | (lit('{') >> macro(_r1) [_val+=_1] > '}') + | (lit('{') >> (macros(_r1)[_val += _1] > '}') | '}') | (lit('[') > legacy_variable_expansion(_r1) [_val+=_1] > ']') ); text_block.name("text_block"); @@ -1363,41 +1978,61 @@ namespace client // New style of macro expansion. // The macro expansion may contain numeric or string expressions, ifs and cases. - macro = - (kw["if"] > if_else_output(_r1) [_val = _1]) -// | (kw["switch"] > switch_output(_r1) [_val = _1]) - | (assignment_statement(_r1) [_val = _1]) - | (additive_expression(_r1) [ px::bind(&expr::to_string2, _1, _val) ]) + macros = + +(block(_r1)[_val += _1] | (statement(_r1) > (+lit(';') | &lit('}')))[_val += _1] | +lit(';')); + macros.name("macro"); + // if_macros and else_macros only differ by the look-ahead ending condition, which is to not have to repeat the last semicolon + // at the end of the block. + if_macros = kw["then"] > *(block(_r1)[_val += _1] | (statement(_r1) > (+lit(';') | &(kw["elsif"] | kw["else"] | kw["endif"])))[_val += _1] | +lit(';')); + if_macros.name("if_macros"); + else_macros = *(block(_r1)[_val += _1] | (statement(_r1) > (+lit(';') | &kw["endif"]))[_val += _1] | +lit(';')); + else_macros.name("else_macros"); + + // Blocks do not require a separating semicolon. + block = + (kw["if"] > if_else_output(_r1)[_val = _1]) + // (kw["switch"] ... + ; + block.name("block"); + + // Statements require a separating semicolon. + statement = + (assignment_statement(_r1) [_val = _1]) + | (new_variable_statement(_r1)[_val = _1]) + | (conditional_expression(_r1)[px::bind(&expr::to_string2, _1, _val)]) ; - macro.name("macro"); // An if expression enclosed in {} (the outmost {} are already parsed by the caller). + // Also }{ could be replaced with ; to simplify writing of pure code. if_else_output = - eps[_b=true] > - bool_expr_eval(_r1)[_a=_1] > '}' > - text_block(_r1)[px::bind(&expr::set_if, _a, _b, _1, _val)] > '{' > - *(kw["elsif"] > bool_expr_eval(_r1)[_a=_1] > '}' > - text_block(_r1)[px::bind(&expr::set_if, _a, _b, _1, _val)] > '{') > - -(kw["else"] > lit('}') > - text_block(_r1)[px::bind(&expr::set_if, _b, _b, _1, _val)] > '{') > + eps[_a=true] > + (bool_expr_eval(_r1)[px::bind(&MyContext::block_enter, _r1, _1)] > (if_text_block(_r1) | if_macros(_r1))) + [px::bind(&MyContext::block_exit, _r1, _1, _a, _2, _val)] > + *((kw["elsif"] > bool_expr_eval(_r1)[px::bind(&MyContext::block_enter, _r1, _1 && _a)] > (if_text_block(_r1) | if_macros(_r1))) + [px::bind(&MyContext::block_exit, _r1, _1, _a, _2, _val)]) > + -(kw["else"] > eps[px::bind(&MyContext::block_enter, _r1, _a)] > (if_text_block(_r1) | else_macros(_r1))) + [px::bind(&MyContext::block_exit, _r1, _a, _a, _1, _val)] > kw["endif"]; if_else_output.name("if_else_output"); + if_text_block = (lit('}') > text_block(_r1) > '{'); + if_text_block.name("if_text_block"); + // A switch expression enclosed in {} (the outmost {} are already parsed by the caller). /* switch_output = eps[_b=true] > - omit[expr(_r1)[_a=_1]] > '}' > text_block(_r1)[px::bind(&expr::set_if_equal, _a, _b, _1, _val)] > '{' > - *("elsif" > omit[bool_expr_eval(_r1)[_a=_1]] > '}' > text_block(_r1)[px::bind(&expr::set_if, _a, _b, _1, _val)]) >> - -("else" > '}' >> text_block(_r1)[px::bind(&expr::set_if, _b, _b, _1, _val)]) > + omit[expr(_r1)[_a=_1]] > '}' > text_block(_r1)[px::bind(&expr::set_if_equal, _a, _b, _1, _val)] > '{' > + *("elsif" > omit[bool_expr_eval(_r1)[_a=_1]] > '}' > text_block(_r1)[px::bind(&expr::set_if, _a, _b, _1, _val)]) >> + -("else" > '}' >> text_block(_r1)[px::bind(&expr::set_if, _b, _b, _1, _val)]) > "endif"; */ // Legacy variable expansion of the original Slic3r, in the form of [scalar_variable] or [vector_variable_index]. legacy_variable_expansion = (identifier >> &lit(']')) - [ px::bind(&MyContext::legacy_variable_expansion, _r1, _1, _val) ] + [ px::bind(&MyContext::legacy_variable_expansion, _r1, _1, _val) ] | (identifier > lit('[') > identifier > ']') - [ px::bind(&MyContext::legacy_variable_expansion2, _r1, _1, _2, _val) ] + [ px::bind(&MyContext::legacy_variable_expansion2, _r1, _1, _2, _val) ] ; legacy_variable_expansion.name("legacy_variable_expansion"); @@ -1407,41 +2042,44 @@ namespace client identifier.name("identifier"); conditional_expression = - logical_or_expression(_r1) [_val = _1] - >> -('?' > conditional_expression(_r1) > ':' > conditional_expression(_r1)) [px::bind(&expr::ternary_op, _val, _1, _2)]; + logical_or_expression(_r1) [_val = _1] + >> -('?' > eps[px::bind(&expr::evaluate_boolean, _val, _a)] > + eps[px::bind(&MyContext::block_enter, _r1, _a)] > conditional_expression(_r1)[px::bind(&MyContext::block_exit_ternary, _r1, _a, _1, _val)] + > ':' > + eps[px::bind(&MyContext::block_enter, _r1, ! _a)] > conditional_expression(_r1)[px::bind(&MyContext::block_exit_ternary, _r1, ! _a, _1, _val)]); conditional_expression.name("conditional_expression"); logical_or_expression = logical_and_expression(_r1) [_val = _1] - >> *( ((kw["or"] | "||") > logical_and_expression(_r1) ) [px::bind(&expr::logical_or, _val, _1)] ); + >> *( ((kw["or"] | "||") > logical_and_expression(_r1) ) [px::bind(&expr::logical_or, _val, _1)] ); logical_or_expression.name("logical_or_expression"); logical_and_expression = equality_expression(_r1) [_val = _1] - >> *( ((kw["and"] | "&&") > equality_expression(_r1) ) [px::bind(&expr::logical_and, _val, _1)] ); + >> *( ((kw["and"] | "&&") > equality_expression(_r1) ) [px::bind(&expr::logical_and, _val, _1)] ); logical_and_expression.name("logical_and_expression"); equality_expression = relational_expression(_r1) [_val = _1] - >> *( ("==" > relational_expression(_r1) ) [px::bind(&expr::equal, _val, _1)] - | ("!=" > relational_expression(_r1) ) [px::bind(&expr::not_equal, _val, _1)] - | ("<>" > relational_expression(_r1) ) [px::bind(&expr::not_equal, _val, _1)] - | ("=~" > regular_expression ) [px::bind(&expr::regex_matches, _val, _1)] - | ("!~" > regular_expression ) [px::bind(&expr::regex_doesnt_match, _val, _1)] + >> *( ("==" > relational_expression(_r1) ) [px::bind(&expr::equal, _val, _1)] + | ("!=" > relational_expression(_r1) ) [px::bind(&expr::not_equal, _val, _1)] + | ("<>" > relational_expression(_r1) ) [px::bind(&expr::not_equal, _val, _1)] + | ("=~" > regular_expression ) [px::bind(&expr::regex_matches, _val, _1)] + | ("!~" > regular_expression ) [px::bind(&expr::regex_doesnt_match, _val, _1)] ); equality_expression.name("bool expression"); // Evaluate a boolean expression stored as expr into a boolean value. // Throw if the equality_expression does not produce a expr of boolean type. - bool_expr_eval = conditional_expression(_r1) [ px::bind(&expr::evaluate_boolean, _1, _val) ]; + bool_expr_eval = conditional_expression(_r1) [ px::bind(&expr::evaluate_boolean, _1, _val) ]; bool_expr_eval.name("bool_expr_eval"); relational_expression = additive_expression(_r1) [_val = _1] - >> *( ("<=" > additive_expression(_r1) ) [px::bind(&expr::leq, _val, _1)] - | (">=" > additive_expression(_r1) ) [px::bind(&expr::geq, _val, _1)] - | (lit('<') > additive_expression(_r1) ) [px::bind(&expr::lower, _val, _1)] - | (lit('>') > additive_expression(_r1) ) [px::bind(&expr::greater, _val, _1)] + >> *( ("<=" > additive_expression(_r1) ) [px::bind(&expr::leq, _val, _1)] + | (">=" > additive_expression(_r1) ) [px::bind(&expr::geq, _val, _1)] + | (lit('<') > additive_expression(_r1) ) [px::bind(&expr::lower, _val, _1)] + | (lit('>') > additive_expression(_r1) ) [px::bind(&expr::greater, _val, _1)] ); relational_expression.name("relational_expression"); @@ -1461,71 +2099,83 @@ namespace client multiplicative_expression.name("multiplicative_expression"); assignment_statement = - (variable_reference(_r1) >> '=' > additive_expression(_r1)) - [px::bind(&MyContext::variable_assign, _r1, _1, _2, _val)]; + (variable_reference(_r1)[_a = _1] >> '=') > + ( // Consumes also '(' conditional_expression ')', that means enclosing an expression into braces makes it a single value vector initializer. + initializer_list(_r1)[px::bind(&MyContext::vector_variable_assign_initializer_list, _r1, _a, _1)] + // Process it before conditional_expression, as conditional_expression requires a vector reference to be augmented with an index. + // Only process such variable references, which return a naked vector variable. + | eps(px::bind(&MyContext::is_vector_variable_reference, _a)) >> + variable_reference(_r1)[px::bind(&MyContext::copy_vector_variable_to_vector_variable, _r1, _a, _1)] + // Would NOT consume '(' conditional_expression ')' because such value was consumed with the expression above. + | conditional_expression(_r1) + [px::bind(&MyContext::scalar_variable_assign_scalar_expression, _r1, _a, _1)] + | (kw["repeat"] > "(" > additive_expression(_r1) > "," > conditional_expression(_r1) > ")") + [px::bind(&MyContext::vector_variable_assign_array, _r1, _a, _1, _2)] + ); + + new_variable_statement = + (kw["local"][_a = false] | kw["global"][_a = true]) > identifier[px::bind(&MyContext::new_old_variable, _r1, _a, _1, _b)] > lit('=') > + ( // Consumes also '(' conditional_expression ')', that means enclosing an expression into braces makes it a single value vector initializer. + initializer_list(_r1)[px::bind(&MyContext::vector_variable_new_from_initializer_list, _r1, _a, _b, _1)] + // Process it before conditional_expression, as conditional_expression requires a vector reference to be augmented with an index. + // Only process such variable references, which return a naked vector variable. + // Orca todo: following code cause strange build errors with MSVC C++17 + // | eps(px::bind(&MyContext::could_be_vector_variable_reference, _b)) >> + // variable_reference(_r1)[px::val(qi::_pass) = px::bind(&MyContext::vector_variable_new_from_copy, _r1, _a, _b, _1)] + // Would NOT consume '(' conditional_expression ')' because such value was consumed with the expression above. + | conditional_expression(_r1) + [px::bind(&MyContext::scalar_variable_new_from_scalar_expression, _r1, _a, _b, _1)] + | (kw["repeat"] > "(" > additive_expression(_r1) > "," > conditional_expression(_r1) > ")") + [px::bind(&MyContext::vector_variable_new_from_array, _r1, _a, _b, _1, _2)] + ); + initializer_list = lit('(') > + ( lit(')') | + ( conditional_expression(_r1)[px::bind(&MyContext::initializer_list_append, _val, _1)] > + *(lit(',') > conditional_expression(_r1)[px::bind(&MyContext::initializer_list_append, _val, _1)]) > + lit(')') + ) + ); - struct FactorActions { - static void set_start_pos(Iterator &start_pos, expr &out) - { out.it_range = boost::iterator_range(start_pos, start_pos); } - static void int_(int &value, Iterator &end_pos, expr &out) - { out = expr(value, out.it_range.begin(), end_pos); } - static void double_(double &value, Iterator &end_pos, expr &out) - { out = expr(value, out.it_range.begin(), end_pos); } - static void bool_(bool &value, Iterator &end_pos, expr &out) - { out = expr(value, out.it_range.begin(), end_pos); } - static void string_(boost::iterator_range &it_range, expr &out) - { out = expr(std::string(it_range.begin() + 1, it_range.end() - 1), it_range.begin(), it_range.end()); } - static void expr_(expr &value, Iterator &end_pos, expr &out) - { auto begin_pos = out.it_range.begin(); out = expr(std::move(value), begin_pos, end_pos); } - static void minus_(expr &value, expr &out) - { out = value.unary_minus(out.it_range.begin()); } - static void not_(expr &value, expr &out) - { out = value.unary_not(out.it_range.begin()); } - static void to_int(expr &value, expr &out) - { out = value.unary_integer(out.it_range.begin()); } - static void round(expr &value, expr &out) - { out = value.round(out.it_range.begin()); } - // For indicating "no optional parameter". - static void noexpr(expr &out) { out.reset(); } - }; unary_expression = iter_pos[px::bind(&FactorActions::set_start_pos, _1, _val)] >> ( - variable_reference(_r1) [px::bind(&MyContext::variable_value, _r1, _1, _val)] + variable_reference(_r1) [px::bind(&MyContext::variable_value, _r1, _1, _val)] | (lit('(') > conditional_expression(_r1) > ')' > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ] | (lit('-') > unary_expression(_r1) ) [ px::bind(&FactorActions::minus_, _1, _val) ] | (lit('+') > unary_expression(_r1) > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ] | ((kw["not"] | '!') > unary_expression(_r1) > iter_pos) [ px::bind(&FactorActions::not_, _1, _val) ] | (kw["min"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')') - [ px::bind(&expr::min, _val, _2) ] + [ px::bind(&expr::min, _val, _2) ] | (kw["max"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')') - [ px::bind(&expr::max, _val, _2) ] + [ px::bind(&expr::max, _val, _2) ] | (kw["random"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')') - [ px::bind(&MyContext::random, _r1, _val, _2) ] + [ px::bind(&MyContext::random, _r1, _val, _2) ] | (kw["digits"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > optional_parameter(_r1)) - [ px::bind(&expr::template digits, _val, _2, _3) ] + [ px::bind(&expr::digits, _val, _2, _3) ] | (kw["zdigits"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > optional_parameter(_r1)) - [ px::bind(&expr::template digits, _val, _2, _3) ] + [ px::bind(&expr::digits, _val, _2, _3) ] | (kw["int"] > '(' > conditional_expression(_r1) > ')') [ px::bind(&FactorActions::to_int, _1, _val) ] | (kw["round"] > '(' > conditional_expression(_r1) > ')') [ px::bind(&FactorActions::round, _1, _val) ] - | (kw["is_nil"] > '(' > is_nil_test(_r1) > ')') [ _val = _1 ] + | (kw["is_nil"] > '(' > variable_reference(_r1) > ')') [px::bind(&MyContext::is_nil_test, _r1, _1, _val)] | (kw["one_of"] > '(' > one_of(_r1) > ')') [ _val = _1 ] + | (kw["empty"] > '(' > variable_reference(_r1) > ')') [px::bind(&MyContext::is_vector_empty, _r1, _1, _val)] + | (kw["size"] > '(' > variable_reference(_r1) > ')') [px::bind(&MyContext::vector_size, _r1, _1, _val)] | (kw["interpolate_table"] > '(' > interpolate_table(_r1) > ')') [ _val = _1 ] - | (strict_double > iter_pos) [ px::bind(&FactorActions::double_, _1, _2, _val) ] - | (int_ > iter_pos) [ px::bind(&FactorActions::int_, _1, _2, _val) ] - | (kw[bool_] > iter_pos) [ px::bind(&FactorActions::bool_, _1, _2, _val) ] + | (strict_double > iter_pos) [ px::bind(&FactorActions::double_, _r1, _1, _2, _val) ] + | (int_ > iter_pos) [ px::bind(&FactorActions::int_, _r1, _1, _2, _val) ] + | (kw[bool_] > iter_pos) [ px::bind(&FactorActions::bool_, _r1, _1, _2, _val) ] | raw[lexeme['"' > *((utf8char - char_('\\') - char_('"')) | ('\\' > char_)) > '"']] - [ px::bind(&FactorActions::string_, _1, _val) ] + [ px::bind(&FactorActions::string_, _r1, _1, _val) ] ); unary_expression.name("unary_expression"); one_of = (unary_expression(_r1)[_a = _1] > one_of_list(_r1, _a))[_val = _2]; one_of.name("one_of"); one_of_list = - eps[px::bind(&expr::one_of_test_init, _val)] > + eps[px::bind(&expr::one_of_test_init, _val)] > ( ( ',' > *( ( - unary_expression(_r1)[px::bind(&expr::template one_of_test, _r2, _1, _val)] - | (lit('~') > unary_expression(_r1))[px::bind(&expr::template one_of_test, _r2, _1, _val)] - | regular_expression[px::bind(&expr::one_of_test_regex, _r2, _1, _val)] + unary_expression(_r1)[px::bind(&expr::one_of_test, _r2, _1, _val)] + | (lit('~') > unary_expression(_r1))[px::bind(&expr::one_of_test, _r2, _1, _val)] + | regular_expression[px::bind(&expr::one_of_test_regex, _r2, _1, _val)] ) >> -lit(',')) ) | eps @@ -1533,12 +2183,12 @@ namespace client one_of_list.name("one_of_list"); interpolate_table = (unary_expression(_r1)[_a = _1] > ',' > interpolate_table_list(_r1, _a)) - [px::bind(&InterpolateTableContext::evaluate, _a, _2, _val)]; + [px::bind(&InterpolateTableContext::evaluate, _a, _2, _val)]; interpolate_table.name("interpolate_table"); interpolate_table_list = - eps[px::bind(&InterpolateTableContext::init, _r2)] > + eps[px::bind(&InterpolateTableContext::init, _r2)] > ( *(( lit('(') > unary_expression(_r1) > ',' > unary_expression(_r1) > ')' ) - [px::bind(&InterpolateTableContext::add_pair, _1, _2, _val)] >> -lit(',')) ); + [px::bind(&InterpolateTableContext::add_pair, _1, _2, _val)] >> -lit(',')) ); interpolate_table.name("interpolate_table_list"); optional_parameter = iter_pos[px::bind(&FactorActions::set_start_pos, _1, _val)] >> ( @@ -1547,20 +2197,17 @@ namespace client ); optional_parameter.name("optional_parameter"); - is_nil_test = variable_reference(_r1)[px::bind(&MyContext::is_nil_test, _r1, _1, _val)]; - is_nil_test.name("is_nil test"); - variable_reference = variable(_r1)[_a=_1] >> ( - ('[' > additive_expression(_r1)[px::bind(&MyContext::evaluate_index, _1, _b)] > ']' > iter_pos) - [px::bind(&MyContext::store_variable_index, _r1, _a, _b, _2, _val)] + ('[' > additive_expression(_r1)[px::bind(&MyContext::evaluate_index, _1, _b)] > ']' > iter_pos) + [px::bind(&MyContext::store_variable_index, _r1, _a, _b, _2, _val)] | eps[_val=_a] ); variable_reference.name("variable reference"); - variable = identifier[ px::bind(&MyContext::resolve_variable, _r1, _1, _val) ]; - variable.name("variable reference"); + variable = identifier[ px::bind(&MyContext::resolve_variable, _r1, _1, _val) ]; + variable.name("variable name"); regular_expression = raw[lexeme['/' > *((utf8char - char_('\\') - char_('/')) | ('\\' > char_)) > '/']]; regular_expression.name("regular_expression"); @@ -1569,29 +2216,34 @@ namespace client ("and") ("digits") ("zdigits") + ("empty") ("if") ("int") ("is_nil") + ("local") //("inf") ("else") ("elsif") ("endif") ("false") + ("global") ("interpolate_table") ("min") ("max") ("random") + ("repeat") ("round") ("not") ("one_of") ("or") + ("size") ("true"); if (0) { debug(start); debug(text); debug(text_block); - debug(macro); + debug(macros); debug(if_else_output); debug(interpolate_table); // debug(switch_output); @@ -1613,28 +2265,27 @@ namespace client debug(optional_parameter); debug(variable_reference); debug(variable); - debug(is_nil_test); debug(regular_expression); } } - // Generic expression over expr. - typedef qi::rule(const MyContext*), spirit_encoding::space_type> RuleExpression; + // Generic expression over expr. + typedef qi::rule RuleExpression; // The start of the grammar. - qi::rule, spirit_encoding::space_type> start; + qi::rule, skipper> start; // A free-form text. - qi::rule text; + qi::rule text; // A free-form text, possibly empty, possibly containing macro expansions. - qi::rule text_block; + qi::rule text_block; // Statements enclosed in curely braces {} - qi::rule macro; + qi::rule block, statement, macros, if_text_block, if_macros, else_macros; // Legacy variable expansion of the original Slic3r, in the form of [scalar_variable] or [vector_variable_index]. - qi::rule legacy_variable_expansion; + qi::rule legacy_variable_expansion; // Parsed identifier name. - qi::rule(), spirit_encoding::space_type> identifier; + qi::rule identifier; // Ternary operator (?:) over logical_or_expression. - RuleExpression conditional_expression; + qi::rule, skipper> conditional_expression; // Logical or over logical_and_expressions. RuleExpression logical_or_expression; // Logical and over relational_expressions. @@ -1652,48 +2303,39 @@ namespace client // Accepting an optional parameter. RuleExpression optional_parameter; // Rule to capture a regular expression enclosed in //. - qi::rule(), spirit_encoding::space_type> regular_expression; + qi::rule regular_expression; // Evaluate boolean expression into bool. - qi::rule bool_expr_eval; + qi::rule bool_expr_eval; // Reference of a scalar variable, or reference to a field of a vector variable. - qi::rule(const MyContext*), qi::locals, int>, spirit_encoding::space_type> variable_reference; + qi::rule, skipper> variable_reference; // Rule to translate an identifier to a ConfigOption, or to fail. - qi::rule(const MyContext*), spirit_encoding::space_type> variable; + qi::rule variable; // Evaluating whether a nullable variable is nil. - qi::rule(const MyContext*), spirit_encoding::space_type> is_nil_test; + qi::rule is_nil_test; // Evaluating "one of" list of patterns. - qi::rule(const MyContext*), qi::locals>, spirit_encoding::space_type> one_of; - qi::rule(const MyContext*, const expr ¶m), spirit_encoding::space_type> one_of_list; + qi::rule, skipper> one_of; + qi::rule one_of_list; // Evaluating the "interpolate_table" expression. - qi::rule(const MyContext*), qi::locals>, spirit_encoding::space_type> interpolate_table; - qi::rule(const MyContext*, const expr ¶m), spirit_encoding::space_type> interpolate_table_list; + qi::rule, skipper> interpolate_table; + qi::rule interpolate_table_list; - qi::rule, spirit_encoding::space_type> if_else_output; - qi::rule, int>, spirit_encoding::space_type> assignment_statement; -// qi::rule, bool, std::string>, spirit_encoding::space_type> switch_output; + qi::rule, skipper> if_else_output; + qi::rule, skipper> assignment_statement; + // Allocating new local or global variables. + qi::rule, skipper> new_variable_statement; + qi::rule(const MyContext*), skipper> initializer_list; qi::symbols keywords; }; } +static const client::macro_processor g_macro_processor_instance; + static std::string process_macro(const std::string &templ, client::MyContext &context) { - typedef std::string::const_iterator iterator_type; - typedef client::macro_processor macro_processor; - - // Our whitespace skipper. - spirit_encoding::space_type space; - // Our grammar, statically allocated inside the method, meaning it will be allocated the first time - // PlaceholderParser::process() runs. - //FIXME this kind of initialization is not thread safe! - static macro_processor macro_processor_instance; - // Iterators over the source template. - std::string::const_iterator iter = templ.begin(); - std::string::const_iterator end = templ.end(); - // Accumulator for the processed template. - std::string output; - phrase_parse(iter, end, macro_processor_instance(&context), space, output); - if (!context.error_message.empty()) { + std::string output; + phrase_parse(templ.begin(), templ.end(), g_macro_processor_instance(&context), client::skipper{}, output); + if (! context.error_message.empty()) { if (context.error_message.back() != '\n' && context.error_message.back() != '\r') context.error_message += '\n'; throw Slic3r::PlaceholderParserError(context.error_message); From 71be87ecef222ad9033ffa7ac0b90f751bb12f44 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 29 Mar 2023 17:53:23 +0200 Subject: [PATCH 19/32] Fixed crash if toolchange G-code modifies final position, because the extruder was not set yet. --- src/libslic3r/GCode.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 4deaa2671f..599292acbe 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -6302,10 +6302,12 @@ Vec2d GCode::point_to_gcode(const Point &point) const // convert a model-space scaled point into G-code coordinates Point GCode::gcode_to_point(const Vec2d &point) const { - Vec2d extruder_offset = EXTRUDER_CONFIG(extruder_offset); - return Point( - scale_(point(0) - m_origin(0) + extruder_offset(0)), - scale_(point(1) - m_origin(1) + extruder_offset(1))); + Vec2d pt = point - m_origin; + if (const Extruder *extruder = m_writer.extruder(); extruder) + // This function may be called at the very start from toolchange G-code when the extruder is not assigned yet. + pt += m_config.extruder_offset.get_at(extruder->id()); + return scaled(pt); + } Vec2d GCode::point_to_gcode_quantized(const Point& point) const From 73e4d79a86acfca163e8d5dc2a7e4b6888d102a9 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Mon, 15 Jul 2024 23:07:39 +0800 Subject: [PATCH 20/32] update prusa profiles --- resources/profiles/Prusa.json | 2 +- .../Prusa/filament/Prusa Generic ABS @MINIIS 0.25.json | 1 - .../Prusa/filament/Prusa Generic ABS @MINIIS 0.6.json | 1 - .../Prusa/filament/Prusa Generic ABS @MINIIS 0.8.json | 1 - .../profiles/Prusa/filament/Prusa Generic ABS @MINIIS.json | 1 - .../profiles/Prusa/filament/Prusa Generic ABS @MK4.json | 1 - .../profiles/Prusa/filament/Prusa Generic ABS @XL 5T.json | 3 +-- resources/profiles/Prusa/filament/Prusa Generic ABS @XL.json | 3 +-- resources/profiles/Prusa/filament/Prusa Generic ABS.json | 1 - .../Prusa/filament/Prusa Generic ASA @MINIIS 0.25.json | 1 - .../Prusa/filament/Prusa Generic ASA @MINIIS 0.6.json | 1 - .../Prusa/filament/Prusa Generic ASA @MINIIS 0.8.json | 1 - .../profiles/Prusa/filament/Prusa Generic ASA @MINIIS.json | 1 - .../profiles/Prusa/filament/Prusa Generic ASA @MK4.json | 1 - resources/profiles/Prusa/filament/Prusa Generic ASA.json | 1 - .../Prusa/filament/Prusa Generic PA @MINIIS 0.25.json | 1 - .../Prusa/filament/Prusa Generic PA @MINIIS 0.6.json | 1 - .../Prusa/filament/Prusa Generic PA @MINIIS 0.8.json | 1 - .../profiles/Prusa/filament/Prusa Generic PA @MINIIS.json | 1 - .../Prusa/filament/Prusa Generic PA-CF @MINIIS 0.25.json | 1 - .../Prusa/filament/Prusa Generic PA-CF @MINIIS 0.6.json | 1 - .../Prusa/filament/Prusa Generic PA-CF @MINIIS 0.8.json | 1 - .../profiles/Prusa/filament/Prusa Generic PA-CF @MINIIS.json | 1 - resources/profiles/Prusa/filament/Prusa Generic PA-CF.json | 1 - resources/profiles/Prusa/filament/Prusa Generic PA.json | 1 - .../Prusa/filament/Prusa Generic PC @MINIIS 0.25.json | 1 - .../Prusa/filament/Prusa Generic PC @MINIIS 0.6.json | 1 - .../Prusa/filament/Prusa Generic PC @MINIIS 0.8.json | 1 - .../profiles/Prusa/filament/Prusa Generic PC @MINIIS.json | 1 - resources/profiles/Prusa/filament/Prusa Generic PC.json | 1 - .../Prusa/filament/Prusa Generic PETG @MINIIS 0.25.json | 1 - .../Prusa/filament/Prusa Generic PETG @MINIIS 0.6.json | 1 - .../Prusa/filament/Prusa Generic PETG @MINIIS 0.8.json | 1 - .../profiles/Prusa/filament/Prusa Generic PETG @MINIIS.json | 1 - .../profiles/Prusa/filament/Prusa Generic PETG @MK4.json | 1 - .../profiles/Prusa/filament/Prusa Generic PETG @XL 5T.json | 5 ++--- .../profiles/Prusa/filament/Prusa Generic PETG @XL.json | 3 +-- resources/profiles/Prusa/filament/Prusa Generic PETG.json | 1 - .../Prusa/filament/Prusa Generic PLA @MINIIS 0.25.json | 1 - .../Prusa/filament/Prusa Generic PLA @MINIIS 0.6.json | 1 - .../Prusa/filament/Prusa Generic PLA @MINIIS 0.8.json | 1 - .../profiles/Prusa/filament/Prusa Generic PLA @MINIIS.json | 1 - .../profiles/Prusa/filament/Prusa Generic PLA @MK4.json | 1 - .../profiles/Prusa/filament/Prusa Generic PLA @XL 5T.json | 5 ++--- resources/profiles/Prusa/filament/Prusa Generic PLA @XL.json | 3 +-- .../Prusa/filament/Prusa Generic PLA-CF @MINIIS 0.25.json | 1 - .../Prusa/filament/Prusa Generic PLA-CF @MINIIS 0.6.json | 1 - .../Prusa/filament/Prusa Generic PLA-CF @MINIIS 0.8.json | 1 - .../Prusa/filament/Prusa Generic PLA-CF @MINIIS.json | 1 - resources/profiles/Prusa/filament/Prusa Generic PLA-CF.json | 1 - resources/profiles/Prusa/filament/Prusa Generic PLA.json | 1 - .../Prusa/filament/Prusa Generic PVA @MINIIS 0.25.json | 1 - .../Prusa/filament/Prusa Generic PVA @MINIIS 0.6.json | 1 - .../Prusa/filament/Prusa Generic PVA @MINIIS 0.8.json | 1 - .../profiles/Prusa/filament/Prusa Generic PVA @MINIIS.json | 1 - resources/profiles/Prusa/filament/Prusa Generic PVA.json | 1 - .../profiles/Prusa/filament/Prusa Generic TPU @MINIIS.json | 1 - .../profiles/Prusa/filament/Prusa Generic TPU @MK4.json | 1 - resources/profiles/Prusa/filament/Prusa Generic TPU.json | 1 - resources/profiles/Prusa/filament/Prusament ASA @XL 5T.json | 3 +-- resources/profiles/Prusa/filament/Prusament ASA @XL.json | 3 +-- .../profiles/Prusa/filament/Prusament PA-CF @XL 5T.json | 3 +-- resources/profiles/Prusa/filament/Prusament PA-CF @XL.json | 3 +-- .../profiles/Prusa/filament/Prusament PC Blend @XL 5T.json | 3 +-- .../profiles/Prusa/filament/Prusament PC Blend @XL.json | 3 +-- .../profiles/Prusa/filament/Prusament PC-CF @XL 5T.json | 3 +-- resources/profiles/Prusa/filament/Prusament PC-CF @XL.json | 3 +-- resources/profiles/Prusa/filament/Prusament PETG @XL 5T.json | 5 ++--- resources/profiles/Prusa/filament/Prusament PETG @XL.json | 3 +-- resources/profiles/Prusa/filament/Prusament PLA @XL 5T.json | 3 +-- resources/profiles/Prusa/filament/Prusament PLA @XL.json | 3 +-- resources/profiles/Prusa/filament/Prusament PVB @XL 5T.json | 3 +-- resources/profiles/Prusa/filament/Prusament PVB @XL.json | 3 +-- resources/profiles/Prusa/filament/Prusament rPLA @XL 5T.json | 3 +-- resources/profiles/Prusa/filament/Prusament rPLA @XL.json | 3 +-- resources/profiles/Prusa/filament/fdm_filament_abs.json | 1 + resources/profiles/Prusa/filament/fdm_filament_asa.json | 1 + resources/profiles/Prusa/filament/fdm_filament_pa.json | 1 + resources/profiles/Prusa/filament/fdm_filament_pa11cf.json | 1 + resources/profiles/Prusa/filament/fdm_filament_pc.json | 1 + resources/profiles/Prusa/filament/fdm_filament_pccf.json | 1 + resources/profiles/Prusa/filament/fdm_filament_pet.json | 1 + resources/profiles/Prusa/filament/fdm_filament_pla.json | 1 + resources/profiles/Prusa/filament/fdm_filament_pva.json | 1 + resources/profiles/Prusa/filament/fdm_filament_pvb.json | 1 + resources/profiles/Prusa/filament/fdm_filament_tpu.json | 1 + .../profiles/Prusa/machine/fdm_machine_common_xl_5t.json | 3 ++- 87 files changed, 39 insertions(+), 101 deletions(-) diff --git a/resources/profiles/Prusa.json b/resources/profiles/Prusa.json index 62af7c6fa9..071bf1bfb0 100644 --- a/resources/profiles/Prusa.json +++ b/resources/profiles/Prusa.json @@ -1,6 +1,6 @@ { "name": "Prusa", - "version": "02.01.01.20", + "version": "02.01.01.30", "force_update": "0", "description": "Prusa configurations", "machine_model_list": [ diff --git a/resources/profiles/Prusa/filament/Prusa Generic ABS @MINIIS 0.25.json b/resources/profiles/Prusa/filament/Prusa Generic ABS @MINIIS 0.25.json index f1f91d3f78..b4d82f7794 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic ABS @MINIIS 0.25.json +++ b/resources/profiles/Prusa/filament/Prusa Generic ABS @MINIIS 0.25.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFB99_5", "setting_id": "GFSA04", "name": "Prusa Generic ABS @MINIIS 0.25", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic ABS @MINIIS 0.6.json b/resources/profiles/Prusa/filament/Prusa Generic ABS @MINIIS 0.6.json index 3ef1005948..1a76559cbd 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic ABS @MINIIS 0.6.json +++ b/resources/profiles/Prusa/filament/Prusa Generic ABS @MINIIS 0.6.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFB99_3", "setting_id": "GFSA04", "name": "Prusa Generic ABS @MINIIS 0.6", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic ABS @MINIIS 0.8.json b/resources/profiles/Prusa/filament/Prusa Generic ABS @MINIIS 0.8.json index 8a3fefe1b4..1668805ca4 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic ABS @MINIIS 0.8.json +++ b/resources/profiles/Prusa/filament/Prusa Generic ABS @MINIIS 0.8.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFB99_4", "setting_id": "GFSA04", "name": "Prusa Generic ABS @MINIIS 0.8", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic ABS @MINIIS.json b/resources/profiles/Prusa/filament/Prusa Generic ABS @MINIIS.json index 08495b61ac..97779cd277 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic ABS @MINIIS.json +++ b/resources/profiles/Prusa/filament/Prusa Generic ABS @MINIIS.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFB99_2", "setting_id": "GFSA04", "name": "Prusa Generic ABS @MINIIS", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic ABS @MK4.json b/resources/profiles/Prusa/filament/Prusa Generic ABS @MK4.json index 0de674b7fe..7a98f46d84 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic ABS @MK4.json +++ b/resources/profiles/Prusa/filament/Prusa Generic ABS @MK4.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFB99_1", "setting_id": "GFSA04", "name": "Prusa Generic ABS @MK4", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic ABS @XL 5T.json b/resources/profiles/Prusa/filament/Prusa Generic ABS @XL 5T.json index a299264967..a80bfb533d 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic ABS @XL 5T.json +++ b/resources/profiles/Prusa/filament/Prusa Generic ABS @XL 5T.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFB99_1", "setting_id": "GFSA04", "name": "Prusa Generic ABS @XL 5T", "from": "system", @@ -57,7 +56,7 @@ "filament_stamping_loading_speed": [ "29" ], - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.04{elsif nozzle_diameter[0]==0.25}0.1{elsif nozzle_diameter[0]==0.3}0.06{elsif nozzle_diameter[0]==0.35}0.05{elsif nozzle_diameter[0]==0.5}0.03{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.02{elsif nozzle_diameter[0]==0.5}0.018{elsif nozzle_diameter[0]==0.6}0.012{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.25}0.09{elsif nozzle_diameter[0]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.04{elsif nozzle_diameter[0]==0.25}0.1{elsif nozzle_diameter[0]==0.3}0.06{elsif nozzle_diameter[0]==0.35}0.05{elsif nozzle_diameter[0]==0.5}0.03{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.02{elsif nozzle_diameter[0]==0.5}0.018{elsif nozzle_diameter[0]==0.6}0.012{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.25}0.09{elsif nozzle_diameter[0]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 5T 0.25 nozzle", "Prusa XL 5T 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/Prusa Generic ABS @XL.json b/resources/profiles/Prusa/filament/Prusa Generic ABS @XL.json index 544d644b27..eaaa8223dc 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic ABS @XL.json +++ b/resources/profiles/Prusa/filament/Prusa Generic ABS @XL.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFB99_1", "setting_id": "GFSA04", "name": "Prusa Generic ABS @XL", "from": "system", @@ -42,7 +41,7 @@ "filament_cooling_initial_speed": "10", "filament_cooling_final_speed": "50", "filament_retract_lift_below": "1.5", - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.04{elsif nozzle_diameter[0]==0.25}0.1{elsif nozzle_diameter[0]==0.3}0.06{elsif nozzle_diameter[0]==0.35}0.05{elsif nozzle_diameter[0]==0.5}0.03{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.02{elsif nozzle_diameter[0]==0.5}0.018{elsif nozzle_diameter[0]==0.6}0.012{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.25}0.09{elsif nozzle_diameter[0]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.04{elsif nozzle_diameter[0]==0.25}0.1{elsif nozzle_diameter[0]==0.3}0.06{elsif nozzle_diameter[0]==0.35}0.05{elsif nozzle_diameter[0]==0.5}0.03{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.02{elsif nozzle_diameter[0]==0.5}0.018{elsif nozzle_diameter[0]==0.6}0.012{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.25}0.09{elsif nozzle_diameter[0]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 0.25 nozzle", "Prusa XL 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/Prusa Generic ABS.json b/resources/profiles/Prusa/filament/Prusa Generic ABS.json index a23cd0693e..724c0a3f80 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic ABS.json +++ b/resources/profiles/Prusa/filament/Prusa Generic ABS.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFB99", "setting_id": "GFSA04", "name": "Prusa Generic ABS", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic ASA @MINIIS 0.25.json b/resources/profiles/Prusa/filament/Prusa Generic ASA @MINIIS 0.25.json index 577d06c5ea..8dd21dc40a 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic ASA @MINIIS 0.25.json +++ b/resources/profiles/Prusa/filament/Prusa Generic ASA @MINIIS 0.25.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFB98_5", "setting_id": "GFSA04", "name": "Prusa Generic ASA @MINIIS 0.25", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic ASA @MINIIS 0.6.json b/resources/profiles/Prusa/filament/Prusa Generic ASA @MINIIS 0.6.json index 8d9c6edd6a..f2016a0eeb 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic ASA @MINIIS 0.6.json +++ b/resources/profiles/Prusa/filament/Prusa Generic ASA @MINIIS 0.6.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFB98_3", "setting_id": "GFSA04", "name": "Prusa Generic ASA @MINIIS 0.6", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic ASA @MINIIS 0.8.json b/resources/profiles/Prusa/filament/Prusa Generic ASA @MINIIS 0.8.json index 6eff61395e..739c7b2078 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic ASA @MINIIS 0.8.json +++ b/resources/profiles/Prusa/filament/Prusa Generic ASA @MINIIS 0.8.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFB98_4", "setting_id": "GFSA04", "name": "Prusa Generic ASA @MINIIS 0.8", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic ASA @MINIIS.json b/resources/profiles/Prusa/filament/Prusa Generic ASA @MINIIS.json index 5fd2131170..f6dd7710f7 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic ASA @MINIIS.json +++ b/resources/profiles/Prusa/filament/Prusa Generic ASA @MINIIS.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFB98_2", "setting_id": "GFSA04", "name": "Prusa Generic ASA @MINIIS", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic ASA @MK4.json b/resources/profiles/Prusa/filament/Prusa Generic ASA @MK4.json index de823b2306..5fea76436a 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic ASA @MK4.json +++ b/resources/profiles/Prusa/filament/Prusa Generic ASA @MK4.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFB98_1", "setting_id": "GFSA04", "name": "Prusa Generic ASA @MK4", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic ASA.json b/resources/profiles/Prusa/filament/Prusa Generic ASA.json index 5631cd38e8..86444714c3 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic ASA.json +++ b/resources/profiles/Prusa/filament/Prusa Generic ASA.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFB98", "setting_id": "GFSA04", "name": "Prusa Generic ASA", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PA @MINIIS 0.25.json b/resources/profiles/Prusa/filament/Prusa Generic PA @MINIIS 0.25.json index b6576cc0d1..8f37a5bd49 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PA @MINIIS 0.25.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PA @MINIIS 0.25.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFN99_4", "setting_id": "GFSA04", "name": "Prusa Generic PA @MINIIS 0.25", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PA @MINIIS 0.6.json b/resources/profiles/Prusa/filament/Prusa Generic PA @MINIIS 0.6.json index bdb64a4a8b..ef375d0645 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PA @MINIIS 0.6.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PA @MINIIS 0.6.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFN99_2", "setting_id": "GFSA04", "name": "Prusa Generic PA @MINIIS 0.6", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PA @MINIIS 0.8.json b/resources/profiles/Prusa/filament/Prusa Generic PA @MINIIS 0.8.json index 2075ae25ed..b3660df86a 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PA @MINIIS 0.8.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PA @MINIIS 0.8.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFN99_3", "setting_id": "GFSA04", "name": "Prusa Generic PA @MINIIS 0.8", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PA @MINIIS.json b/resources/profiles/Prusa/filament/Prusa Generic PA @MINIIS.json index ff8c622dec..df2b3e8bdb 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PA @MINIIS.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PA @MINIIS.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFN99_1", "setting_id": "GFSA04", "name": "Prusa Generic PA @MINIIS", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PA-CF @MINIIS 0.25.json b/resources/profiles/Prusa/filament/Prusa Generic PA-CF @MINIIS 0.25.json index 68b628210d..6107892792 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PA-CF @MINIIS 0.25.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PA-CF @MINIIS 0.25.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFN98_4", "setting_id": "GFSA04", "name": "Prusa Generic PA-CF @MINIIS 0.25", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PA-CF @MINIIS 0.6.json b/resources/profiles/Prusa/filament/Prusa Generic PA-CF @MINIIS 0.6.json index f19a1545d6..558ed7aac4 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PA-CF @MINIIS 0.6.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PA-CF @MINIIS 0.6.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFN98_2", "setting_id": "GFSA04", "name": "Prusa Generic PA-CF @MINIIS 0.6", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PA-CF @MINIIS 0.8.json b/resources/profiles/Prusa/filament/Prusa Generic PA-CF @MINIIS 0.8.json index c4dbec0528..6d2c69a00a 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PA-CF @MINIIS 0.8.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PA-CF @MINIIS 0.8.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFN98_3", "setting_id": "GFSA04", "name": "Prusa Generic PA-CF @MINIIS 0.8", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PA-CF @MINIIS.json b/resources/profiles/Prusa/filament/Prusa Generic PA-CF @MINIIS.json index a0a6b78914..36dbe45128 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PA-CF @MINIIS.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PA-CF @MINIIS.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFN98_1", "setting_id": "GFSA04", "name": "Prusa Generic PA-CF @MINIIS", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PA-CF.json b/resources/profiles/Prusa/filament/Prusa Generic PA-CF.json index 8b389957c7..338e3fceb5 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PA-CF.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PA-CF.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFN98", "setting_id": "GFSA04", "name": "Prusa Generic PA-CF", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PA.json b/resources/profiles/Prusa/filament/Prusa Generic PA.json index c92b0a981e..d573a9185c 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PA.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PA.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFN99", "setting_id": "GFSA04", "name": "Prusa Generic PA", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PC @MINIIS 0.25.json b/resources/profiles/Prusa/filament/Prusa Generic PC @MINIIS 0.25.json index e1ca18d3ae..5eae079a9b 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PC @MINIIS 0.25.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PC @MINIIS 0.25.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFC99_4", "setting_id": "GFSA04", "name": "Prusa Generic PC @MINIIS 0.25", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PC @MINIIS 0.6.json b/resources/profiles/Prusa/filament/Prusa Generic PC @MINIIS 0.6.json index 2636f59ea3..de41d697a5 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PC @MINIIS 0.6.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PC @MINIIS 0.6.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFC99_2", "setting_id": "GFSA04", "name": "Prusa Generic PC @MINIIS 0.6", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PC @MINIIS 0.8.json b/resources/profiles/Prusa/filament/Prusa Generic PC @MINIIS 0.8.json index e7bac7b4eb..a336739fda 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PC @MINIIS 0.8.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PC @MINIIS 0.8.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFC99_3", "setting_id": "GFSA04", "name": "Prusa Generic PC @MINIIS 0.8", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PC @MINIIS.json b/resources/profiles/Prusa/filament/Prusa Generic PC @MINIIS.json index 3dadd23764..e07f12a355 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PC @MINIIS.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PC @MINIIS.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFC99_1", "setting_id": "GFSA04", "name": "Prusa Generic PC @MINIIS", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PC.json b/resources/profiles/Prusa/filament/Prusa Generic PC.json index b1821e1d4d..88844a11bb 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PC.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PC.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFC99", "setting_id": "GFSA04", "name": "Prusa Generic PC", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PETG @MINIIS 0.25.json b/resources/profiles/Prusa/filament/Prusa Generic PETG @MINIIS 0.25.json index 8090554d09..4c64f88db2 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PETG @MINIIS 0.25.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PETG @MINIIS 0.25.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFG99_5", "setting_id": "GFSA04", "name": "Prusa Generic PETG @MINIIS 0.25", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PETG @MINIIS 0.6.json b/resources/profiles/Prusa/filament/Prusa Generic PETG @MINIIS 0.6.json index 8dad5b26e8..8a32807d15 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PETG @MINIIS 0.6.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PETG @MINIIS 0.6.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFG99_3", "setting_id": "GFSA04", "name": "Prusa Generic PETG @MINIIS 0.6", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PETG @MINIIS 0.8.json b/resources/profiles/Prusa/filament/Prusa Generic PETG @MINIIS 0.8.json index 8829ea6f8f..e53595ee01 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PETG @MINIIS 0.8.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PETG @MINIIS 0.8.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFG99_4", "setting_id": "GFSA04", "name": "Prusa Generic PETG @MINIIS 0.8", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PETG @MINIIS.json b/resources/profiles/Prusa/filament/Prusa Generic PETG @MINIIS.json index e9b57ebada..7ce30af419 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PETG @MINIIS.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PETG @MINIIS.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFG99_2", "setting_id": "GFSA04", "name": "Prusa Generic PETG @MINIIS", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PETG @MK4.json b/resources/profiles/Prusa/filament/Prusa Generic PETG @MK4.json index 9caa793e9f..7eedb38b60 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PETG @MK4.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PETG @MK4.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFG99_1", "setting_id": "GFSA04", "name": "Prusa Generic PETG @MK4", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PETG @XL 5T.json b/resources/profiles/Prusa/filament/Prusa Generic PETG @XL 5T.json index 5f26694dc5..ef5778964f 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PETG @XL 5T.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PETG @XL 5T.json @@ -1,7 +1,6 @@ { "type": "filament", - "filament_id": "GFL99_1", - "setting_id": "GFSA04", + "setting_id": "GFG99_PRUSA_0", "name": "Prusa Generic PETG @XL 5T", "from": "system", "instantiation": "true", @@ -60,7 +59,7 @@ ], "filament_wipe": "1", "filament_retract_before_wipe": "20%", - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.053{elsif nozzle_diameter[0]==0.5}0.042{elsif nozzle_diameter[0]==0.6}0.032{elsif nozzle_diameter[0]==0.8}0.018{elsif nozzle_diameter[0]==0.25}0.18{elsif nozzle_diameter[0]==0.3}0.1{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.053{elsif nozzle_diameter[0]==0.5}0.042{elsif nozzle_diameter[0]==0.6}0.032{elsif nozzle_diameter[0]==0.8}0.018{elsif nozzle_diameter[0]==0.25}0.18{elsif nozzle_diameter[0]==0.3}0.1{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 5T 0.25 nozzle", "Prusa XL 5T 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PETG @XL.json b/resources/profiles/Prusa/filament/Prusa Generic PETG @XL.json index c2c535cd91..4767e5ef77 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PETG @XL.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PETG @XL.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL99_1", "setting_id": "GFSA04", "name": "Prusa Generic PETG @XL", "from": "system", @@ -45,7 +44,7 @@ "filament_retract_lift_below": "1.5", "filament_wipe": "1", "filament_retract_before_wipe": "20%", - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.053{elsif nozzle_diameter[0]==0.5}0.042{elsif nozzle_diameter[0]==0.6}0.032{elsif nozzle_diameter[0]==0.8}0.018{elsif nozzle_diameter[0]==0.25}0.18{elsif nozzle_diameter[0]==0.3}0.1{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.053{elsif nozzle_diameter[0]==0.5}0.042{elsif nozzle_diameter[0]==0.6}0.032{elsif nozzle_diameter[0]==0.8}0.018{elsif nozzle_diameter[0]==0.25}0.18{elsif nozzle_diameter[0]==0.3}0.1{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 0.25 nozzle", "Prusa XL 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PETG.json b/resources/profiles/Prusa/filament/Prusa Generic PETG.json index 9076a6c3aa..532ad318d0 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PETG.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PETG.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFG99", "setting_id": "GFSA04", "name": "Prusa Generic PETG", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PLA @MINIIS 0.25.json b/resources/profiles/Prusa/filament/Prusa Generic PLA @MINIIS 0.25.json index 9df6c863c0..bc64fdef61 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PLA @MINIIS 0.25.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PLA @MINIIS 0.25.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL99_5", "setting_id": "GFSA04", "name": "Prusa Generic PLA @MINIIS 0.25", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PLA @MINIIS 0.6.json b/resources/profiles/Prusa/filament/Prusa Generic PLA @MINIIS 0.6.json index 667c98c801..5eaa277a93 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PLA @MINIIS 0.6.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PLA @MINIIS 0.6.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL99_3", "setting_id": "GFSA04", "name": "Prusa Generic PLA @MINIIS 0.6", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PLA @MINIIS 0.8.json b/resources/profiles/Prusa/filament/Prusa Generic PLA @MINIIS 0.8.json index 711b271b1c..4f4b21eab2 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PLA @MINIIS 0.8.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PLA @MINIIS 0.8.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL99_4", "setting_id": "GFSA04", "name": "Prusa Generic PLA @MINIIS 0.8", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PLA @MINIIS.json b/resources/profiles/Prusa/filament/Prusa Generic PLA @MINIIS.json index 2ac1386e71..fcb2e730ba 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PLA @MINIIS.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PLA @MINIIS.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL99_2", "setting_id": "GFSA04", "name": "Prusa Generic PLA @MINIIS", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PLA @MK4.json b/resources/profiles/Prusa/filament/Prusa Generic PLA @MK4.json index d3293a39cc..6f8952d40e 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PLA @MK4.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PLA @MK4.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL99_1", "setting_id": "GFSA04", "name": "Prusa Generic PLA @MK4", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PLA @XL 5T.json b/resources/profiles/Prusa/filament/Prusa Generic PLA @XL 5T.json index ff37c0b691..fc3fea69cd 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PLA @XL 5T.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PLA @XL 5T.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL99_1", "setting_id": "GFSA04", "name": "Prusa Generic PLA @XL 5T", "from": "system", @@ -55,7 +54,7 @@ "filament_stamping_loading_speed": [ "29" ], - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.036{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.036{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 5T 0.25 nozzle", "Prusa XL 5T 0.3 nozzle", @@ -64,4 +63,4 @@ "Prusa XL 5T 0.6 nozzle", "Prusa XL 5T 0.8 nozzle" ] -} +} \ No newline at end of file diff --git a/resources/profiles/Prusa/filament/Prusa Generic PLA @XL.json b/resources/profiles/Prusa/filament/Prusa Generic PLA @XL.json index 06acddef20..6ab8b011ee 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PLA @XL.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PLA @XL.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL99_1", "setting_id": "GFSA04", "name": "Prusa Generic PLA @XL", "from": "system", @@ -40,7 +39,7 @@ "filament_cooling_initial_speed": "10", "filament_cooling_final_speed": "3.5", "filament_retract_lift_below": "0.6", - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.036{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.036{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 0.25 nozzle", "Prusa XL 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PLA-CF @MINIIS 0.25.json b/resources/profiles/Prusa/filament/Prusa Generic PLA-CF @MINIIS 0.25.json index 929fe26671..e9c5476044 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PLA-CF @MINIIS 0.25.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PLA-CF @MINIIS 0.25.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL98_5", "setting_id": "GFSA04", "name": "Prusa Generic PLA-CF @MINIIS 0.25", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PLA-CF @MINIIS 0.6.json b/resources/profiles/Prusa/filament/Prusa Generic PLA-CF @MINIIS 0.6.json index cee0363300..f095249c54 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PLA-CF @MINIIS 0.6.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PLA-CF @MINIIS 0.6.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL98_3", "setting_id": "GFSA04", "name": "Prusa Generic PLA-CF @MINIIS 0.6", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PLA-CF @MINIIS 0.8.json b/resources/profiles/Prusa/filament/Prusa Generic PLA-CF @MINIIS 0.8.json index 1bfce10352..c784a473ab 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PLA-CF @MINIIS 0.8.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PLA-CF @MINIIS 0.8.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL98_4", "setting_id": "GFSA04", "name": "Prusa Generic PLA-CF @MINIIS 0.8", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PLA-CF @MINIIS.json b/resources/profiles/Prusa/filament/Prusa Generic PLA-CF @MINIIS.json index 24559261d9..740c2bfe19 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PLA-CF @MINIIS.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PLA-CF @MINIIS.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL98_1", "setting_id": "GFSA04", "name": "Prusa Generic PLA-CF @MINIIS", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PLA-CF.json b/resources/profiles/Prusa/filament/Prusa Generic PLA-CF.json index 4461005ad3..6bb298a0f4 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PLA-CF.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PLA-CF.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL98", "setting_id": "GFSA04", "name": "Prusa Generic PLA-CF", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PLA.json b/resources/profiles/Prusa/filament/Prusa Generic PLA.json index f31ec71c51..049691036c 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PLA.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PLA.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL99", "setting_id": "GFSA04", "name": "Prusa Generic PLA", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PVA @MINIIS 0.25.json b/resources/profiles/Prusa/filament/Prusa Generic PVA @MINIIS 0.25.json index bbbc4a6aa9..34ce1a84e4 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PVA @MINIIS 0.25.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PVA @MINIIS 0.25.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFS99_4", "setting_id": "GFSA04", "name": "Prusa Generic PVA @MINIIS 0.25", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PVA @MINIIS 0.6.json b/resources/profiles/Prusa/filament/Prusa Generic PVA @MINIIS 0.6.json index d9f64abbed..3ee44fa9a6 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PVA @MINIIS 0.6.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PVA @MINIIS 0.6.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFS99_2", "setting_id": "GFSA04", "name": "Prusa Generic PVA @MINIIS 0.6", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PVA @MINIIS 0.8.json b/resources/profiles/Prusa/filament/Prusa Generic PVA @MINIIS 0.8.json index 5e0055a5fb..eeb2dbd43d 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PVA @MINIIS 0.8.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PVA @MINIIS 0.8.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFS99_3", "setting_id": "GFSA04", "name": "Prusa Generic PVA @MINIIS 0.8", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PVA @MINIIS.json b/resources/profiles/Prusa/filament/Prusa Generic PVA @MINIIS.json index 164b717964..b5f5602f37 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PVA @MINIIS.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PVA @MINIIS.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFS99_1", "setting_id": "GFSA04", "name": "Prusa Generic PVA @MINIIS", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic PVA.json b/resources/profiles/Prusa/filament/Prusa Generic PVA.json index 2c0e2017e3..c5cdfa8518 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic PVA.json +++ b/resources/profiles/Prusa/filament/Prusa Generic PVA.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFS99", "setting_id": "GFSA04", "name": "Prusa Generic PVA", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic TPU @MINIIS.json b/resources/profiles/Prusa/filament/Prusa Generic TPU @MINIIS.json index b9214b3031..3baf1ac2e4 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic TPU @MINIIS.json +++ b/resources/profiles/Prusa/filament/Prusa Generic TPU @MINIIS.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFU99_2", "setting_id": "GFSA04", "name": "Prusa Generic TPU @MINIIS", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic TPU @MK4.json b/resources/profiles/Prusa/filament/Prusa Generic TPU @MK4.json index ac940c00aa..27fbaa6601 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic TPU @MK4.json +++ b/resources/profiles/Prusa/filament/Prusa Generic TPU @MK4.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFU99_1", "setting_id": "GFSA04", "name": "Prusa Generic TPU @MK4", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusa Generic TPU.json b/resources/profiles/Prusa/filament/Prusa Generic TPU.json index 47239a500e..5384820c98 100644 --- a/resources/profiles/Prusa/filament/Prusa Generic TPU.json +++ b/resources/profiles/Prusa/filament/Prusa Generic TPU.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFU99", "setting_id": "GFSA04", "name": "Prusa Generic TPU", "from": "system", diff --git a/resources/profiles/Prusa/filament/Prusament ASA @XL 5T.json b/resources/profiles/Prusa/filament/Prusament ASA @XL 5T.json index 2ec8efea09..2022485fab 100644 --- a/resources/profiles/Prusa/filament/Prusament ASA @XL 5T.json +++ b/resources/profiles/Prusa/filament/Prusament ASA @XL 5T.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFB98", "setting_id": "GFSA04", "name": "Prusament ASA @XL 5T", "from": "system", @@ -59,7 +58,7 @@ "filament_stamping_loading_speed": [ "29" ], - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.04{elsif nozzle_diameter[0]==0.25}0.1{elsif nozzle_diameter[0]==0.3}0.06{elsif nozzle_diameter[0]==0.35}0.05{elsif nozzle_diameter[0]==0.5}0.03{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.02{elsif nozzle_diameter[0]==0.5}0.018{elsif nozzle_diameter[0]==0.6}0.012{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.25}0.09{elsif nozzle_diameter[0]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.04{elsif nozzle_diameter[0]==0.25}0.1{elsif nozzle_diameter[0]==0.3}0.06{elsif nozzle_diameter[0]==0.35}0.05{elsif nozzle_diameter[0]==0.5}0.03{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.02{elsif nozzle_diameter[0]==0.5}0.018{elsif nozzle_diameter[0]==0.6}0.012{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.25}0.09{elsif nozzle_diameter[0]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 5T 0.25 nozzle", "Prusa XL 5T 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/Prusament ASA @XL.json b/resources/profiles/Prusa/filament/Prusament ASA @XL.json index 36e1f6c601..496d63fd1f 100644 --- a/resources/profiles/Prusa/filament/Prusament ASA @XL.json +++ b/resources/profiles/Prusa/filament/Prusament ASA @XL.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFB98", "setting_id": "GFSA04", "name": "Prusament ASA @XL", "from": "system", @@ -44,7 +43,7 @@ "filament_cooling_initial_speed": "10", "filament_cooling_final_speed": "50", "filament_retract_lift_below": "1.5", - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.04{elsif nozzle_diameter[0]==0.25}0.1{elsif nozzle_diameter[0]==0.3}0.06{elsif nozzle_diameter[0]==0.35}0.05{elsif nozzle_diameter[0]==0.5}0.03{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.02{elsif nozzle_diameter[0]==0.5}0.018{elsif nozzle_diameter[0]==0.6}0.012{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.25}0.09{elsif nozzle_diameter[0]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.04{elsif nozzle_diameter[0]==0.25}0.1{elsif nozzle_diameter[0]==0.3}0.06{elsif nozzle_diameter[0]==0.35}0.05{elsif nozzle_diameter[0]==0.5}0.03{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.02{elsif nozzle_diameter[0]==0.5}0.018{elsif nozzle_diameter[0]==0.6}0.012{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.25}0.09{elsif nozzle_diameter[0]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 0.25 nozzle", "Prusa XL 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/Prusament PA-CF @XL 5T.json b/resources/profiles/Prusa/filament/Prusament PA-CF @XL 5T.json index ffd0f3cfe3..c15ee9784e 100644 --- a/resources/profiles/Prusa/filament/Prusament PA-CF @XL 5T.json +++ b/resources/profiles/Prusa/filament/Prusament PA-CF @XL 5T.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFN98", "setting_id": "GFSA04", "name": "Prusament PA-CF @XL 5T", "from": "system", @@ -59,7 +58,7 @@ "filament_stamping_loading_speed": [ "29" ], - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.6}0.025{elsif nozzle_diameter[0]==0.8}0.016{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.6}0.025{elsif nozzle_diameter[0]==0.8}0.016{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 5T 0.25 nozzle", "Prusa XL 5T 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/Prusament PA-CF @XL.json b/resources/profiles/Prusa/filament/Prusament PA-CF @XL.json index 28d4862819..d718cf7966 100644 --- a/resources/profiles/Prusa/filament/Prusament PA-CF @XL.json +++ b/resources/profiles/Prusa/filament/Prusament PA-CF @XL.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFN98", "setting_id": "GFSA04", "name": "Prusament PA-CF @XL", "from": "system", @@ -44,7 +43,7 @@ "filament_cooling_initial_speed": "10", "filament_cooling_final_speed": "50", "filament_retract_lift_below": "1.5", - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.6}0.025{elsif nozzle_diameter[0]==0.8}0.016{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.6}0.025{elsif nozzle_diameter[0]==0.8}0.016{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 0.25 nozzle", "Prusa XL 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/Prusament PC Blend @XL 5T.json b/resources/profiles/Prusa/filament/Prusament PC Blend @XL 5T.json index 0b3077d471..aad5ab31ef 100644 --- a/resources/profiles/Prusa/filament/Prusament PC Blend @XL 5T.json +++ b/resources/profiles/Prusa/filament/Prusament PC Blend @XL 5T.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL99_1", "setting_id": "GFSA04", "name": "Prusament PC Blend @XL 5T", "from": "system", @@ -59,7 +58,7 @@ "filament_stamping_loading_speed": [ "29" ], - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.6}0.025{elsif nozzle_diameter[0]==0.8}0.016{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.6}0.025{elsif nozzle_diameter[0]==0.8}0.016{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 5T 0.25 nozzle", "Prusa XL 5T 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/Prusament PC Blend @XL.json b/resources/profiles/Prusa/filament/Prusament PC Blend @XL.json index a2bfaada98..025cc39eee 100644 --- a/resources/profiles/Prusa/filament/Prusament PC Blend @XL.json +++ b/resources/profiles/Prusa/filament/Prusament PC Blend @XL.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL99_1", "setting_id": "GFSA04", "name": "Prusament PC Blend @XL", "from": "system", @@ -44,7 +43,7 @@ "filament_cooling_initial_speed": "10", "filament_cooling_final_speed": "50", "filament_retract_lift_below": "1.5", - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.6}0.025{elsif nozzle_diameter[0]==0.8}0.016{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.6}0.025{elsif nozzle_diameter[0]==0.8}0.016{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 0.25 nozzle", "Prusa XL 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/Prusament PC-CF @XL 5T.json b/resources/profiles/Prusa/filament/Prusament PC-CF @XL 5T.json index e82f40ba46..1bba76b7c4 100644 --- a/resources/profiles/Prusa/filament/Prusament PC-CF @XL 5T.json +++ b/resources/profiles/Prusa/filament/Prusament PC-CF @XL 5T.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL99_1", "setting_id": "GFSA04", "name": "Prusament PC-CF @XL 5T", "from": "system", @@ -59,7 +58,7 @@ "filament_stamping_loading_speed": [ "29" ], - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.6}0.025{elsif nozzle_diameter[0]==0.8}0.016{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.6}0.025{elsif nozzle_diameter[0]==0.8}0.016{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 5T 0.25 nozzle", "Prusa XL 5T 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/Prusament PC-CF @XL.json b/resources/profiles/Prusa/filament/Prusament PC-CF @XL.json index 79c707f999..44bbd20d6a 100644 --- a/resources/profiles/Prusa/filament/Prusament PC-CF @XL.json +++ b/resources/profiles/Prusa/filament/Prusament PC-CF @XL.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL99_1", "setting_id": "GFSA04", "name": "Prusament PC-CF @XL", "from": "system", @@ -44,7 +43,7 @@ "filament_cooling_initial_speed": "10", "filament_cooling_final_speed": "50", "filament_retract_lift_below": "1.5", - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.6}0.025{elsif nozzle_diameter[0]==0.8}0.016{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.6}0.025{elsif nozzle_diameter[0]==0.8}0.016{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 0.25 nozzle", "Prusa XL 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/Prusament PETG @XL 5T.json b/resources/profiles/Prusa/filament/Prusament PETG @XL 5T.json index 10856125da..5c62c313cc 100644 --- a/resources/profiles/Prusa/filament/Prusament PETG @XL 5T.json +++ b/resources/profiles/Prusa/filament/Prusament PETG @XL 5T.json @@ -1,7 +1,6 @@ { "type": "filament", - "filament_id": "GFL99_1", - "setting_id": "GFSA04", + "setting_id": "GFG99_PRUSA_1", "name": "Prusament PETG @XL 5T", "from": "system", "instantiation": "true", @@ -60,7 +59,7 @@ ], "filament_wipe": "1", "filament_retract_before_wipe": "20%", - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.053{elsif nozzle_diameter[0]==0.5}0.042{elsif nozzle_diameter[0]==0.6}0.032{elsif nozzle_diameter[0]==0.8}0.018{elsif nozzle_diameter[0]==0.25}0.18{elsif nozzle_diameter[0]==0.3}0.1{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.053{elsif nozzle_diameter[0]==0.5}0.042{elsif nozzle_diameter[0]==0.6}0.032{elsif nozzle_diameter[0]==0.8}0.018{elsif nozzle_diameter[0]==0.25}0.18{elsif nozzle_diameter[0]==0.3}0.1{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 5T 0.25 nozzle", "Prusa XL 5T 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/Prusament PETG @XL.json b/resources/profiles/Prusa/filament/Prusament PETG @XL.json index c4505feda5..da28d7d588 100644 --- a/resources/profiles/Prusa/filament/Prusament PETG @XL.json +++ b/resources/profiles/Prusa/filament/Prusament PETG @XL.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL99_1", "setting_id": "GFSA04", "name": "Prusament PETG @XL", "from": "system", @@ -45,7 +44,7 @@ "filament_retract_lift_below": "1.5", "filament_wipe": "1", "filament_retract_before_wipe": "20%", - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.053{elsif nozzle_diameter[0]==0.5}0.042{elsif nozzle_diameter[0]==0.6}0.032{elsif nozzle_diameter[0]==0.8}0.018{elsif nozzle_diameter[0]==0.25}0.18{elsif nozzle_diameter[0]==0.3}0.1{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.053{elsif nozzle_diameter[0]==0.5}0.042{elsif nozzle_diameter[0]==0.6}0.032{elsif nozzle_diameter[0]==0.8}0.018{elsif nozzle_diameter[0]==0.25}0.18{elsif nozzle_diameter[0]==0.3}0.1{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 0.25 nozzle", "Prusa XL 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/Prusament PLA @XL 5T.json b/resources/profiles/Prusa/filament/Prusament PLA @XL 5T.json index ede4ce5755..b3efef6127 100644 --- a/resources/profiles/Prusa/filament/Prusament PLA @XL 5T.json +++ b/resources/profiles/Prusa/filament/Prusament PLA @XL 5T.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL99_1", "setting_id": "GFSA04", "name": "Prusament PLA @XL 5T", "from": "system", @@ -55,7 +54,7 @@ "filament_stamping_loading_speed": [ "29" ], - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.036{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.036{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 5T 0.25 nozzle", "Prusa XL 5T 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/Prusament PLA @XL.json b/resources/profiles/Prusa/filament/Prusament PLA @XL.json index 949dfb23b3..fe9f0b5281 100644 --- a/resources/profiles/Prusa/filament/Prusament PLA @XL.json +++ b/resources/profiles/Prusa/filament/Prusament PLA @XL.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL99_1", "setting_id": "GFSA04", "name": "Prusament PLA @XL", "from": "system", @@ -40,7 +39,7 @@ "filament_cooling_initial_speed": "10", "filament_cooling_final_speed": "3.5", "filament_retract_lift_below": "0.6", - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.036{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.036{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 0.25 nozzle", "Prusa XL 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/Prusament PVB @XL 5T.json b/resources/profiles/Prusa/filament/Prusament PVB @XL 5T.json index f7d360fdb7..354f904cef 100644 --- a/resources/profiles/Prusa/filament/Prusament PVB @XL 5T.json +++ b/resources/profiles/Prusa/filament/Prusament PVB @XL 5T.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFS99", "setting_id": "GFSA04", "name": "Prusament PVB @XL 5T", "from": "system", @@ -60,7 +59,7 @@ "filament_stamping_loading_speed": [ "29" ], - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.036{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.036{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 5T 0.25 nozzle", "Prusa XL 5T 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/Prusament PVB @XL.json b/resources/profiles/Prusa/filament/Prusament PVB @XL.json index c7e1e5fe0e..67b2c9501c 100644 --- a/resources/profiles/Prusa/filament/Prusament PVB @XL.json +++ b/resources/profiles/Prusa/filament/Prusament PVB @XL.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFS99", "setting_id": "GFSA04", "name": "Prusament PVB @XL", "from": "system", @@ -45,7 +44,7 @@ "filament_cooling_initial_speed": "10", "filament_cooling_final_speed": "3.5", "filament_retract_lift_below": "0.6", - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.036{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.036{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 0.25 nozzle", "Prusa XL 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/Prusament rPLA @XL 5T.json b/resources/profiles/Prusa/filament/Prusament rPLA @XL 5T.json index af36626c3f..9a7cce6455 100644 --- a/resources/profiles/Prusa/filament/Prusament rPLA @XL 5T.json +++ b/resources/profiles/Prusa/filament/Prusament rPLA @XL 5T.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL99_1", "setting_id": "GFSA04", "name": "Prusament rPLA @XL 5T", "from": "system", @@ -58,7 +57,7 @@ "filament_stamping_loading_speed": [ "29" ], - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.036{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.036{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 5T 0.25 nozzle", "Prusa XL 5T 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/Prusament rPLA @XL.json b/resources/profiles/Prusa/filament/Prusament rPLA @XL.json index 6fa3b54c17..cfe956641f 100644 --- a/resources/profiles/Prusa/filament/Prusament rPLA @XL.json +++ b/resources/profiles/Prusa/filament/Prusament rPLA @XL.json @@ -1,6 +1,5 @@ { "type": "filament", - "filament_id": "GFL99_1", "setting_id": "GFSA04", "name": "Prusament rPLA @XL", "from": "system", @@ -43,7 +42,7 @@ "filament_cooling_initial_speed": "10", "filament_cooling_final_speed": "3.5", "filament_retract_lift_below": "0.6", - "filament_start_gcode": "; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.036{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp", + "filament_start_gcode": ["; filament start gcode\nM900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_XLIS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.036{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"], "compatible_printers": [ "Prusa XL 0.25 nozzle", "Prusa XL 0.3 nozzle", diff --git a/resources/profiles/Prusa/filament/fdm_filament_abs.json b/resources/profiles/Prusa/filament/fdm_filament_abs.json index a00127c466..d60e0c16bd 100644 --- a/resources/profiles/Prusa/filament/fdm_filament_abs.json +++ b/resources/profiles/Prusa/filament/fdm_filament_abs.json @@ -4,6 +4,7 @@ "from": "system", "instantiation": "false", "inherits": "fdm_filament_common", + "filament_id": "GFB99", "cool_plate_temp": [ "105" ], diff --git a/resources/profiles/Prusa/filament/fdm_filament_asa.json b/resources/profiles/Prusa/filament/fdm_filament_asa.json index a087f32f0c..7aa9917aa4 100644 --- a/resources/profiles/Prusa/filament/fdm_filament_asa.json +++ b/resources/profiles/Prusa/filament/fdm_filament_asa.json @@ -4,6 +4,7 @@ "from": "system", "instantiation": "false", "inherits": "fdm_filament_common", + "filament_id": "GFB98", "cool_plate_temp" : [ "105" ], diff --git a/resources/profiles/Prusa/filament/fdm_filament_pa.json b/resources/profiles/Prusa/filament/fdm_filament_pa.json index cf59c08b65..c473b6a203 100644 --- a/resources/profiles/Prusa/filament/fdm_filament_pa.json +++ b/resources/profiles/Prusa/filament/fdm_filament_pa.json @@ -4,6 +4,7 @@ "from": "system", "instantiation": "false", "inherits": "fdm_filament_common", + "filament_id": "GFN99", "cool_plate_temp" : [ "0" ], diff --git a/resources/profiles/Prusa/filament/fdm_filament_pa11cf.json b/resources/profiles/Prusa/filament/fdm_filament_pa11cf.json index b3083a5e20..2afd4c1696 100644 --- a/resources/profiles/Prusa/filament/fdm_filament_pa11cf.json +++ b/resources/profiles/Prusa/filament/fdm_filament_pa11cf.json @@ -4,6 +4,7 @@ "from": "system", "instantiation": "false", "inherits": "fdm_filament_common", + "filament_id": "GFN98", "cool_plate_temp" : [ "0" ], diff --git a/resources/profiles/Prusa/filament/fdm_filament_pc.json b/resources/profiles/Prusa/filament/fdm_filament_pc.json index b9f61730aa..2a152fe354 100644 --- a/resources/profiles/Prusa/filament/fdm_filament_pc.json +++ b/resources/profiles/Prusa/filament/fdm_filament_pc.json @@ -4,6 +4,7 @@ "from": "system", "instantiation": "false", "inherits": "fdm_filament_common", + "filament_id": "GFC99", "cool_plate_temp" : [ "0" ], diff --git a/resources/profiles/Prusa/filament/fdm_filament_pccf.json b/resources/profiles/Prusa/filament/fdm_filament_pccf.json index ce4afb1f9a..1c6e13f360 100644 --- a/resources/profiles/Prusa/filament/fdm_filament_pccf.json +++ b/resources/profiles/Prusa/filament/fdm_filament_pccf.json @@ -4,6 +4,7 @@ "from": "system", "instantiation": "false", "inherits": "fdm_filament_common", + "filament_id": "GFC98", "cool_plate_temp" : [ "0" ], diff --git a/resources/profiles/Prusa/filament/fdm_filament_pet.json b/resources/profiles/Prusa/filament/fdm_filament_pet.json index dcc3e74e42..b494b4d3a7 100644 --- a/resources/profiles/Prusa/filament/fdm_filament_pet.json +++ b/resources/profiles/Prusa/filament/fdm_filament_pet.json @@ -4,6 +4,7 @@ "from": "system", "instantiation": "false", "inherits": "fdm_filament_common", + "filament_id": "GFT02", "cool_plate_temp" : [ "60" ], diff --git a/resources/profiles/Prusa/filament/fdm_filament_pla.json b/resources/profiles/Prusa/filament/fdm_filament_pla.json index f065b5c37a..9e7c6746f2 100644 --- a/resources/profiles/Prusa/filament/fdm_filament_pla.json +++ b/resources/profiles/Prusa/filament/fdm_filament_pla.json @@ -4,6 +4,7 @@ "from": "system", "instantiation": "false", "inherits": "fdm_filament_common", + "filament_id": "GFL99", "fan_cooling_layer_time": [ "100" ], diff --git a/resources/profiles/Prusa/filament/fdm_filament_pva.json b/resources/profiles/Prusa/filament/fdm_filament_pva.json index 65e3b71a9c..ee8e4311e3 100644 --- a/resources/profiles/Prusa/filament/fdm_filament_pva.json +++ b/resources/profiles/Prusa/filament/fdm_filament_pva.json @@ -4,6 +4,7 @@ "from": "system", "instantiation": "false", "inherits": "fdm_filament_common", + "filament_id": "GFS99", "cool_plate_temp" : [ "35" ], diff --git a/resources/profiles/Prusa/filament/fdm_filament_pvb.json b/resources/profiles/Prusa/filament/fdm_filament_pvb.json index 49c4911c53..b4fed01543 100644 --- a/resources/profiles/Prusa/filament/fdm_filament_pvb.json +++ b/resources/profiles/Prusa/filament/fdm_filament_pvb.json @@ -4,6 +4,7 @@ "from": "system", "instantiation": "false", "inherits": "fdm_filament_common", + "filament_id": "GFS98", "cool_plate_temp" : [ "35" ], diff --git a/resources/profiles/Prusa/filament/fdm_filament_tpu.json b/resources/profiles/Prusa/filament/fdm_filament_tpu.json index cb20416bb7..27a8b984b7 100644 --- a/resources/profiles/Prusa/filament/fdm_filament_tpu.json +++ b/resources/profiles/Prusa/filament/fdm_filament_tpu.json @@ -4,6 +4,7 @@ "from": "system", "instantiation": "false", "inherits": "fdm_filament_common", + "filament_id": "GFU99", "cool_plate_temp" : [ "30" ], diff --git a/resources/profiles/Prusa/machine/fdm_machine_common_xl_5t.json b/resources/profiles/Prusa/machine/fdm_machine_common_xl_5t.json index ff3cabed2b..eedd38b152 100644 --- a/resources/profiles/Prusa/machine/fdm_machine_common_xl_5t.json +++ b/resources/profiles/Prusa/machine/fdm_machine_common_xl_5t.json @@ -14,7 +14,8 @@ "machine_pause_gcode": "M601", "machine_start_gcode": "M17 ; enable steppers\nM862.3 P \"XL\" ; printer model check\nM862.5 P2 ; g-code level check\nM862.6 P\"Input shaper\" ; FW feature check\nM115 U6.0.3+14902\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\n; set print area\nM555 X{first_layer_print_min[0]} Y{first_layer_print_min[1]} W{(first_layer_print_max[0]) - (first_layer_print_min[0])} H{(first_layer_print_max[1]) - (first_layer_print_min[1])}\n; inform about nozzle diameter\n{if (is_extruder_used[0])}M862.1 T0 P{nozzle_diameter[0]}{endif}\n{if (is_extruder_used[1])}M862.1 T1 P{nozzle_diameter[1]}{endif}\n{if (is_extruder_used[2])}M862.1 T2 P{nozzle_diameter[2]}{endif}\n{if (is_extruder_used[3])}M862.1 T3 P{nozzle_diameter[3]}{endif}\n{if (is_extruder_used[4])}M862.1 T4 P{nozzle_diameter[4]}{endif}\n\n; turn off unused heaters\n{if ! is_extruder_used[0]} M104 T0 S0 {endif}\n{if ! is_extruder_used[1]} M104 T1 S0 {endif}\n{if num_extruders > 2 and ! is_extruder_used[2]} M104 T2 S0 {endif}\n{if num_extruders > 3 and ! is_extruder_used[3]} M104 T3 S0 {endif}\n{if num_extruders > 4 and ! is_extruder_used[4]} M104 T4 S0 {endif}\n\nM217 Z{max(zhop, 2.0)} ; set toolchange z hop to 2mm, or zhop variable from slicer if higher\n; set bed and extruder temp for MBL\nM140 S[first_layer_bed_temperature] ; set bed temp\nG0 Z5 ; add Z clearance\nM109 T{initial_tool} S{((filament_notes[initial_tool]=~/.*HT_MBL10.*/) ? (first_layer_temperature[initial_tool] - 10) : (filament_type[initial_tool] == \"PC\" or filament_type[initial_tool] == \"PA\") ? (first_layer_temperature[initial_tool] - 25) : (filament_type[initial_tool] == \"FLEX\") ? 210 : (filament_type[initial_tool]=~/.*PET.*/) ? 175 : 170)} ; wait for temp\n\n; Home XY\nG28 XY\n; try picking tools used in print\nG1 F{travel_speed * 60}\n{if (is_extruder_used[0]) and (initial_tool != 0)}T0 S1 L0 D0{endif}\n{if (is_extruder_used[1]) and (initial_tool != 1)}T1 S1 L0 D0{endif}\n{if (is_extruder_used[2]) and (initial_tool != 2)}T2 S1 L0 D0{endif}\n{if (is_extruder_used[3]) and (initial_tool != 3)}T3 S1 L0 D0{endif}\n{if (is_extruder_used[4]) and (initial_tool != 4)}T4 S1 L0 D0{endif}\n; select tool that will be used to home & MBL\nT{initial_tool} S1 L0 D0\n; home Z with MBL tool\nM84 E ; turn off E motor\nG28 Z\nG0 Z5 ; add Z clearance\n\nM104 T{initial_tool} S{if idle_temperature[initial_tool] == 0}70{else}{idle_temperature[initial_tool]}{endif} ; set idle temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\n\nG29 G ; absorb heat\n\nM109 T{initial_tool} S{((filament_notes[initial_tool]=~/.*HT_MBL10.*/) ? (first_layer_temperature[initial_tool] - 10) : (filament_type[initial_tool] == \"PC\" or filament_type[initial_tool] == \"PA\") ? (first_layer_temperature[initial_tool] - 25) : (filament_type[initial_tool] == \"FLEX\") ? 210 : (filament_type[initial_tool]=~/.*PET.*/) ? 175 : 170)} ; wait for temp\n\n; move to the nozzle cleanup area\nG1 X{(min(((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32))), first_layer_print_min[0])) + 32} Y{(min((first_layer_print_min[1] - 7), first_layer_print_min[1]))} Z{5} F{(travel_speed * 60)}\nM302 S160 ; lower cold extrusion limit to 160C\nG1 E{-(filament_type[0] == \"FLEX\" ? 4 : 2)} F2400 ; retraction for nozzle cleanup\n; nozzle cleanup\nM84 E ; turn off E motor\nG29 P9 X{((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)))} Y{(first_layer_print_min[1] - 7)} W{32} H{7}\nG0 Z5 F480 ; move away in Z\nM107 ; turn off the fan\n; MBL\nM84 E ; turn off E motor\nG29 P1 ; invalidate mbl & probe print area\nG29 P1 X30 Y0 W{(((is_extruder_used[4]) or ((is_extruder_used[3]) or (is_extruder_used[2]))) ? \"300\" : ((is_extruder_used[1]) ? \"130\" : \"50\"))} H20 C ; probe near purge place\nG29 P3.2 ; interpolate mbl probes\nG29 P3.13 ; extrapolate mbl outside probe area\nG29 A ; activate mbl\nG1 Z10 F720 ; move away in Z\nG1 F{travel_speed * 60}\nP0 S1 L1 D0; park the tool\n; set extruder temp\n{if first_layer_temperature[0] > 0 and (is_extruder_used[0])}M104 T0 S{first_layer_temperature[0]}{endif}\n{if first_layer_temperature[1] > 0 and (is_extruder_used[1])}M104 T1 S{first_layer_temperature[1]}{endif}\n{if first_layer_temperature[2] > 0 and (is_extruder_used[2])}M104 T2 S{first_layer_temperature[2]}{endif}\n{if first_layer_temperature[3] > 0 and (is_extruder_used[3])}M104 T3 S{first_layer_temperature[3]}{endif}\n{if first_layer_temperature[4] > 0 and (is_extruder_used[4])}M104 T4 S{first_layer_temperature[4]}{endif}\n{if (is_extruder_used[0]) and initial_tool != 0}\n;\n; purge first tool\n;\nG1 F{travel_speed * 60}\nP0 S1 L2 D0; park the tool\nM109 T0 S{first_layer_temperature[0]}\nT0 S1 L0 D0; pick the tool\nG92 E0 ; reset extruder position\n\nG0 X{(0 == 0 ? 30 : (0 == 1 ? 150 : (0 == 2 ? 210 : 330)))} Y{(0 < 4 ? -7 : -4.5)} Z10 F{(travel_speed * 60)} ; move close to the sheet's edge\nG0 E{if filament_multitool_ramming[0]}10{else}30{endif} X40 Z0.2 F{if filament_multitool_ramming[0]}500{else}170{endif} ; purge while moving towards the sheet\nG0 X70 E9 F800 ; continue purging and wipe the nozzle\nG0 X{70 + 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{70 + 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG1 E{- 1.5 * retract_length[0]} F2400 ; retract\n{e_retracted[0] = 1.5 * retract_length[0]} ; update slicer internal retract variable\nG92 E0 ; reset extruder position\n\nM104 S{(idle_temperature[0] == 0 ? (first_layer_temperature[0] + standby_temperature_delta) : (idle_temperature[0]))} T0\n{endif}\n{if (is_extruder_used[1]) and initial_tool != 1}\n;\n; purge second tool\n;\nG1 F{travel_speed * 60}\nP0 S1 L2 D0; park the tool\nM109 T1 S{first_layer_temperature[1]}\nT1 S1 L0 D0; pick the tool\nG92 E0 ; reset extruder position\n\nG0 X{(1 == 0 ? 30 : (1 == 1 ? 150 : (1 == 2 ? 210 : 330)))} Y{(1 < 4 ? -7 : -4.5)} Z10 F{(travel_speed * 60)} ; move close to the sheet's edge\nG0 E{if filament_multitool_ramming[1]}10{else}30{endif} X140 Z0.2 F{if filament_multitool_ramming[1]}500{else}170{endif} ; purge while moving towards the sheet\nG0 X110 E9 F800 ; continue purging and wipe the nozzle\nG0 X{110 - 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{110 - 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG1 E{- 1.5 * retract_length[1]} F2400 ; retract\n{e_retracted[1] = 1.5 * retract_length[1]} ; update slicer internal retract variable\nG92 E0 ; reset extruder position\n\nM104 S{(idle_temperature[1] == 0 ? (first_layer_temperature[1] + standby_temperature_delta) : (idle_temperature[1]))} T1\n{endif}\n{if (is_extruder_used[2]) and initial_tool != 2}\n;\n; purge third tool\n;\nG1 F{travel_speed * 60}\nP0 S1 L2 D0; park the tool\nM109 T2 S{first_layer_temperature[2]}\nT2 S1 L0 D0; pick the tool\nG92 E0 ; reset extruder position\n\nG0 X{(2 == 0 ? 30 : (2 == 1 ? 150 : (2 == 2 ? 210 : 330)))} Y{(2 < 4 ? -7 : -4.5)} Z10 F{(travel_speed * 60)} ; move close to the sheet's edge\nG0 E{if filament_multitool_ramming[2]}10{else}30{endif} X220 Z0.2 F{if filament_multitool_ramming[2]}500{else}170{endif} ; purge while moving towards the sheet\nG0 X250 E9 F800 ; continue purging and wipe the nozzle\nG0 X{250 + 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{250 + 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG1 E{- 1.5 * retract_length[2]} F2400 ; retract\n{e_retracted[2] = 1.5 * retract_length[2]} ; update slicer internal retract variable\nG92 E0 ; reset extruder position\n\nM104 S{(idle_temperature[2] == 0 ? (first_layer_temperature[2] + standby_temperature_delta) : (idle_temperature[2]))} T2\n{endif}\n{if (is_extruder_used[3]) and initial_tool != 3}\n;\n; purge fourth tool\n;\nG1 F{travel_speed * 60}\nP0 S1 L2 D0; park the tool\nM109 T3 S{first_layer_temperature[3]}\nT3 S1 L0 D0; pick the tool\nG92 E0 ; reset extruder position\n\nG0 X{(3 == 0 ? 30 : (3 == 1 ? 150 : (3 == 2 ? 210 : 330)))} Y{(3 < 4 ? -7 : -4.5)} Z10 F{(travel_speed * 60)} ; move close to the sheet's edge\nG0 E{if filament_multitool_ramming[3]}10{else}30{endif} X320 Z0.2 F{if filament_multitool_ramming[3]}500{else}170{endif} ; purge while moving towards the sheet\nG0 X290 E9 F800 ; continue purging and wipe the nozzle\nG0 X{290 - 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{290 - 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG1 E{- 1.5 * retract_length[3]} F2400 ; retract\n{e_retracted[3] = 1.5 * retract_length[3]} ; update slicer internal retract variable\nG92 E0 ; reset extruder position\n\nM104 S{(idle_temperature[3] == 0 ? (first_layer_temperature[3] + standby_temperature_delta) : (idle_temperature[3]))} T3\n{endif}\n{if (is_extruder_used[4]) and initial_tool != 4}\n;\n; purge fifth tool\n;\nG1 F{travel_speed * 60}\nP0 S1 L2 D0; park the tool\nM109 T4 S{first_layer_temperature[4]}\nT4 S1 L0 D0; pick the tool\nG92 E0 ; reset extruder position\n\nG0 X{(4 == 0 ? 30 : (4 == 1 ? 150 : (4 == 2 ? 210 : 330)))} Y{(4 < 4 ? -7 : -4.5)} Z10 F{(travel_speed * 60)} ; move close to the sheet's edge\nG0 E{if filament_multitool_ramming[4]}10{else}30{endif} X320 Z0.2 F{if filament_multitool_ramming[4]}500{else}170{endif} ; purge while moving towards the sheet\nG0 X290 E9 F800 ; continue purging and wipe the nozzle\nG0 X{290 - 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{290 - 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG1 E{- 1.5 * retract_length[4]} F2400 ; retract\n{e_retracted[4] = 1.5 * retract_length[4]} ; update slicer internal retract variable\nG92 E0 ; reset extruder position\n\nM104 S{(idle_temperature[4] == 0 ? (first_layer_temperature[4] + standby_temperature_delta) : (idle_temperature[4]))} T4\n{endif}\n;\n; purge initial tool\n;\nG1 F{travel_speed * 60}\nP0 S1 L2 D0; park the tool\nM109 T{initial_tool} S{first_layer_temperature[initial_tool]}\nT{initial_tool} S1 L0 D0; pick the tool\nG92 E0 ; reset extruder position\n\nG0 X{(initial_tool == 0 ? 30 : (initial_tool == 1 ? 150 : (initial_tool == 2 ? 210 : 330)))} Y{(initial_tool < 4 ? -7 : -4.5)} Z10 F{(travel_speed * 60)} ; move close to the sheet's edge\nG0 E{if filament_multitool_ramming[initial_tool]}10{else}30{endif} X{(initial_tool == 0 ? 30 : (initial_tool == 1 ? 150 : (initial_tool == 2 ? 210 : 330))) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 10)} Z0.2 F{if filament_multitool_ramming[initial_tool]}500{else}170{endif} ; purge while moving towards the sheet\nG0 X{(initial_tool == 0 ? 30 : (initial_tool == 1 ? 150 : (initial_tool == 2 ? 210 : 330))) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 40)} E9 F800 ; continue purging and wipe the nozzle\nG0 X{(initial_tool == 0 ? 30 : (initial_tool == 1 ? 150 : (initial_tool == 2 ? 210 : 330))) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 40) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 3)} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{(initial_tool == 0 ? 30 : (initial_tool == 1 ? 150 : (initial_tool == 2 ? 210 : 330))) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 40) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 3 * 2)} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG1 E{- 1.5 * retract_length[initial_tool]} F2400 ; retract\n{e_retracted[initial_tool] = 1.5 * retract_length[initial_tool]}\nG92 E0 ; reset extruder position\n", "machine_end_gcode": "G4 ; wait\n\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+5, max_print_height)}{endif} ; Move bed down\n\nP0 S1 ; park tool\n\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+97, max_print_height)} F300{endif} ; Move bed further down\n\n; turn off extruder heaters\n{if is_extruder_used[0]} M104 T0 S0 {endif}\n{if is_extruder_used[1]} M104 T1 S0 {endif}\n{if is_extruder_used[2]} M104 T2 S0 {endif}\n{if is_extruder_used[3]} M104 T3 S0 {endif}\n{if is_extruder_used[4]} M104 T4 S0 {endif}\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM221 S100 ; reset flow percentage\nM84 ; disable motors\nM77 ; stop print timer\n; max_layer_z = [max_layer_z]", - "change_filament_gcode": "; Change Tool[previous_extruder] -> Tool[next_extruder] (layer [layer_num])\n{if travel_speed > 350.0}\nG1 F{350.0 * 60} \n{else}\nG1 F{travel_speed * 60} \n{endif}\nP0 S1 L2 D0\n; [layer_num]\n{if layer_num == 0}\nM109 S{first_layer_temperature[next_extruder]} T[next_extruder]\n{else}\nM109 S{nozzle_temperature[next_extruder]} T[next_extruder]\n{endif}\nT[next_extruder] S1 L0 D0\n", + "change_filament_gcode": "; Change Tool[previous_extruder] -> Tool[next_extruder] (layer [layer_num])\n{\nposition[2] = position[2] + 2.0;\n}\n{if travel_speed > 350.0}\nG1 F{350.0 * 60} \n{else}\nG1 F{travel_speed * 60} \n{endif}\nP0 S1 L2 D0\n; [layer_num]\n{if layer_num == 0}\nM109 S{first_layer_temperature[next_extruder]} T[next_extruder]\n{else}\nM109 S{nozzle_temperature[next_extruder]} T[next_extruder]\n{endif}\nT[next_extruder] S1 L0 D0\n", + "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\nG92 E0.0\n;[layer_z]\n", "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", "printer_notes": "Do not remove the keywords below.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_XLIS\nPG\nINPUT_SHAPER" From 4b3f91b2e23a9c3ec0e802495394e2a25a645a66 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Tue, 16 Jul 2024 00:02:38 +0800 Subject: [PATCH 21/32] Simple preheat, temperary solution --- src/libslic3r/GCode/WipeTower2.cpp | 47 +++++++++++++++++++++++++++++- src/libslic3r/GCode/WipeTower2.hpp | 2 ++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/GCode/WipeTower2.cpp b/src/libslic3r/GCode/WipeTower2.cpp index 6bebe14b76..548e29ab5b 100644 --- a/src/libslic3r/GCode/WipeTower2.cpp +++ b/src/libslic3r/GCode/WipeTower2.cpp @@ -781,7 +781,49 @@ std::vector WipeTower2::prime( return results; } +#define FLAVOR_IS(val) this->m_gcode_flavor == val +#define FLAVOR_IS_NOT(val) this->m_gcode_flavor != val +std::string WipeTower2::set_preheat_temperature(unsigned int temperature, bool wait, int tool) +{ + if (wait && (FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish))) + return ""; + + std::string code, comment; + if (wait && FLAVOR_IS_NOT(gcfTeacup) && FLAVOR_IS_NOT(gcfRepRapFirmware)) { + code = "M109"; + comment = "set nozzle temperature and wait for it to be reached"; + } else { + if (FLAVOR_IS(gcfRepRapFirmware)) { // M104 is deprecated on RepRapFirmware + code = "G10"; + } else { + code = "M104"; + } + comment = "preheat next nozzle"; + } + + std::ostringstream gcode; + gcode << code << " "; + if (FLAVOR_IS(gcfMach3) || FLAVOR_IS(gcfMachinekit)) { + gcode << "P"; + } else { + gcode << "S"; + } + gcode << temperature; + if (tool != -1) { + if (FLAVOR_IS(gcfRepRapFirmware)) { + gcode << " P" << tool; + } else { + gcode << " T" << tool; + } + } + gcode << " ; " << comment << "\n"; + + if ((FLAVOR_IS(gcfTeacup) || FLAVOR_IS(gcfRepRapFirmware)) && wait) + gcode << "M116 ; wait for temperature to be reached\n"; + + return gcode.str(); +} WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool) { size_t old_tool = m_current_tool; @@ -836,9 +878,12 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool) // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool. if (tool != (unsigned int)-1){ // This is not the last change. + auto new_tool_temp = is_first_layer() ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature; + // Orca: pre-heat next tool, it's a temperary solution before impelment the proper preheat. + writer.append(set_preheat_temperature(new_tool_temp, false, tool)); toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, (is_first_layer() ? m_filpar[m_current_tool].first_layer_temperature : m_filpar[m_current_tool].temperature), - (is_first_layer() ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature)); + new_tool_temp); toolchange_Change(writer, tool, m_filpar[tool].material); // Change the tool, set a speed override for soluble and flex materials. toolchange_Load(writer, cleaning_box); writer.travel(writer.x(), writer.y()-m_perimeter_width); // cooling and loading were done a bit down the road diff --git a/src/libslic3r/GCode/WipeTower2.hpp b/src/libslic3r/GCode/WipeTower2.hpp index 07c5ca330f..1d37cbe791 100644 --- a/src/libslic3r/GCode/WipeTower2.hpp +++ b/src/libslic3r/GCode/WipeTower2.hpp @@ -255,6 +255,8 @@ private: // Goes through m_plan, calculates border and finish_layer extrusions and subtracts them from last wipe void save_on_last_wipe(); + // Orca: temp help function to set temperature + std::string set_preheat_temperature(unsigned int temperature, bool wait, int tool); // to store information about tool changes for a given layer struct WipeTowerInfo{ From 7d0fb4f42a3f6a1f43503a601491071b8e29052c Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 18 Oct 2023 10:47:11 +0200 Subject: [PATCH 22/32] preheat work - part 1 --- src/libslic3r/GCode.cpp | 1 + src/libslic3r/GCode/GCodeProcessor.cpp | 757 ++++++++++++++++++++++++- src/libslic3r/GCode/GCodeProcessor.hpp | 21 +- src/libslic3r/GCode/WipeTower2.cpp | 44 -- src/libslic3r/GCode/WipeTower2.hpp | 3 - src/libslic3r/GCodeReader.hpp | 10 + src/libslic3r/GCodeWriter.cpp | 44 +- src/libslic3r/GCodeWriter.hpp | 2 + src/libslic3r/Print.cpp | 24 + src/libslic3r/Print.hpp | 17 + src/libslic3r/PrintConfig.cpp | 16 + src/libslic3r/PrintConfig.hpp | 3 + 12 files changed, 866 insertions(+), 76 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 599292acbe..a2d4516022 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1527,6 +1527,7 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu path_tmp += ".tmp"; m_processor.initialize(path_tmp); + m_processor.set_print(print); GCodeOutputStream file(boost::nowide::fopen(path_tmp.c_str(), "wb"), m_processor); if (! file.is_open()) { BOOST_LOG_TRIVIAL(error) << std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n" << std::endl; diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 648b570d82..a2393383e9 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -1,4 +1,5 @@ #include "ExtrusionEntity.hpp" +#include "GCodeWriter.hpp" #include "PrintConfig.hpp" #include "libslic3r/libslic3r.h" #include "libslic3r/Utils.hpp" @@ -20,6 +21,7 @@ #include #include #include +#include #include #if __has_include() @@ -369,7 +371,7 @@ void GCodeProcessor::TimeMachine::calculate_time(size_t keep_last_n_blocks, floa //BBS if (block.flags.prepare_stage) prepare_time += block_time; - g1_times_cache.push_back({ block.g1_line_id, time }); + g1_times_cache.push_back({ block.g1_line_id, block.remaining_internal_g1_lines, time }); // update times for remaining time to printer stop placeholders auto it_stop_time = std::lower_bound(stop_times.begin(), stop_times.end(), block.g1_line_id, [](const StopTime& t, unsigned int value) { return t.g1_line_id < value; }); @@ -941,6 +943,7 @@ void GCodeProcessorResult::reset() { printable_height = 0.0f; settings_ids.reset(); extruders_count = 0; + backtrace_enabled = false; 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); @@ -1048,10 +1051,15 @@ void GCodeProcessor::apply_config(const PrintConfig& config) m_flavor = config.gcode_flavor; - // BBS + m_single_extruder_multi_material = config.single_extruder_multi_material; + size_t extruders_count = config.filament_diameter.values.size(); m_result.extruders_count = extruders_count; + // Orca: + m_is_XL_printer = is_XL_printer(config); + m_result.backtrace_enabled = m_is_XL_printer || ( !m_single_extruder_multi_material && extruders_count > 1); + m_extruder_offsets.resize(extruders_count); m_extruder_colors.resize(extruders_count); m_result.filament_diameters.resize(extruders_count); @@ -1061,11 +1069,19 @@ void GCodeProcessor::apply_config(const PrintConfig& config) m_result.filament_costs.resize(extruders_count); m_result.filament_flow_ratios.resize(extruders_count); m_extruder_temps.resize(extruders_count); + m_extruder_temps_config.resize(extruders_count); + m_extruder_temps_first_layer_config.resize(extruders_count); m_result.nozzle_hrc = static_cast(config.nozzle_hrc.getInt()); m_result.nozzle_type = config.nozzle_type; for (size_t i = 0; i < extruders_count; ++ i) { m_extruder_offsets[i] = to_3d(config.extruder_offset.get_at(i).cast().eval(), 0.f); m_extruder_colors[i] = static_cast(i); + m_extruder_temps_first_layer_config[i] = static_cast(config.nozzle_temperature_initial_layer.get_at(i)); + m_extruder_temps_config[i] = static_cast(config.nozzle_temperature.get_at(i)); + if (m_extruder_temps_config[i] == 0) { + // This means the value should be ignored and first layer temp should be used. + m_extruder_temps_config[i] = m_extruder_temps_first_layer_config[i]; + } m_result.filament_diameters[i] = static_cast(config.filament_diameter.get_at(i)); m_result.required_nozzle_HRC[i] = static_cast(config.required_nozzle_HRC.get_at(i)); m_result.filament_densities[i] = static_cast(config.filament_density.get_at(i)); @@ -1716,6 +1732,9 @@ void GCodeProcessor::finalize(bool post_process) #endif // ENABLE_GCODE_VIEWER_STATISTICS //BBS: update slice warning update_slice_warnings(); + + if (post_process) + run_post_process(); } float GCodeProcessor::get_time(PrintEstimatedStatistics::ETimeMode mode) const @@ -2927,7 +2946,7 @@ void GCodeProcessor::process_G0(const GCodeReader::GCodeLine& line) process_G1(line); } -void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) +void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line, const std::optional& remaining_internal_g1_lines) { 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(); float filament_flowratio = (static_cast(m_extruder_id) < m_result.filament_flow_ratios.size()) ? m_result.filament_flow_ratios[m_extruder_id] : m_result.filament_flow_ratios.back(); @@ -2959,7 +2978,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) type = (delta_pos[Z] == 0.0f) ? EMoveType::Unretract : EMoveType::Travel; else if (delta_pos[X] != 0.0f || delta_pos[Y] != 0.0f) type = EMoveType::Extrude; - } + } else if (delta_pos[X] != 0.0f || delta_pos[Y] != 0.0f || delta_pos[Z] != 0.0f) type = EMoveType::Travel; @@ -3109,6 +3128,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) block.role = (type != EMoveType::Travel || m_extrusion_role == erCustom) ? m_extrusion_role : erNone; block.distance = distance; block.g1_line_id = m_g1_line_id; + block.remaining_internal_g1_lines = remaining_internal_g1_lines.has_value() ? *remaining_internal_g1_lines : 0; block.layer_id = std::max(1, m_layer_id); block.flags.prepare_stage = m_processing_start_custom_gcode; @@ -3163,7 +3183,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) } // calculates block acceleration - float acceleration = + float acceleration = (type == EMoveType::Travel) ? get_travel_acceleration(static_cast(i)) : (is_extrusion_only_move(delta_pos) ? get_retract_acceleration(static_cast(i)) : @@ -3303,10 +3323,10 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) if (!m_seams_detector.has_first_vertex()) { m_seams_detector.set_first_vertex(new_pos); } else if (m_detect_layer_based_on_tag) { - // 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); + // 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); } } } @@ -4348,6 +4368,725 @@ void GCodeProcessor::process_T(const std::string_view command) } } } +static void update_lines_ends_and_out_file_pos(const std::string& out_string, std::vector& lines_ends, size_t* out_file_pos) +{ + for (size_t i = 0; i < out_string.size(); ++i) { + if (out_string[i] == '\n') + lines_ends.emplace_back((out_file_pos != nullptr) ? *out_file_pos + i + 1 : i + 1); + } + if (out_file_pos != nullptr) + *out_file_pos += out_string.size(); +} + +void GCodeProcessor::run_post_process() +{ + FilePtr in{ boost::nowide::fopen(m_result.filename.c_str(), "rb") }; + if (in.f == nullptr) + throw Slic3r::RuntimeError(std::string("GCode processor post process export failed.\nCannot open file for reading.\n")); + + // temporary file to contain modified gcode + std::string out_path = m_result.filename + ".postprocess"; + FilePtr out{ boost::nowide::fopen(out_path.c_str(), "wb") }; + if (out.f == nullptr) + throw Slic3r::RuntimeError(std::string("GCode processor post process export failed.\nCannot open file for writing.\n")); + + std::vector filament_mm(m_result.extruders_count, 0.0); + std::vector filament_cm3(m_result.extruders_count, 0.0); + std::vector filament_g(m_result.extruders_count, 0.0); + std::vector filament_cost(m_result.extruders_count, 0.0); + + double filament_total_g = 0.0; + double filament_total_cost = 0.0; + + for (const auto& [id, volume] : m_result.print_statistics.total_volumes_per_extruder) { + filament_mm[id] = volume / (static_cast(M_PI) * sqr(0.5 * m_result.filament_diameters[id])); + filament_cm3[id] = volume * 0.001; + filament_g[id] = filament_cm3[id] * double(m_result.filament_densities[id]); + filament_cost[id] = filament_g[id] * double(m_result.filament_costs[id]) * 0.001; + filament_total_g += filament_g[id]; + filament_total_cost += filament_cost[id]; + } + + double total_g_wipe_tower = m_print->print_statistics().total_wipe_tower_filament; + + + auto time_in_minutes = [](float time_in_seconds) { + assert(time_in_seconds >= 0.f); + return int((time_in_seconds + 0.5f) / 60.0f); + }; + + auto time_in_last_minute = [](float time_in_seconds) { + assert(time_in_seconds <= 60.0f); + return time_in_seconds / 60.0f; + }; + + auto format_line_M73_main = [](const std::string& mask, int percent, int time) { + char line_M73[64]; + sprintf(line_M73, mask.c_str(), + std::to_string(percent).c_str(), + std::to_string(time).c_str()); + return std::string(line_M73); + }; + + auto format_line_M73_stop_int = [](const std::string& mask, int time) { + char line_M73[64]; + sprintf(line_M73, mask.c_str(), std::to_string(time).c_str()); + return std::string(line_M73); + }; + + auto format_time_float = [](float time) { + return Slic3r::float_to_string_decimal_point(time, 2); + }; + + auto format_line_M73_stop_float = [format_time_float](const std::string& mask, float time) { + char line_M73[64]; + sprintf(line_M73, mask.c_str(), format_time_float(time).c_str()); + return std::string(line_M73); + }; + + std::string gcode_line; + size_t g1_lines_counter = 0; + // keeps track of last exported pair + std::array, static_cast(PrintEstimatedStatistics::ETimeMode::Count)> last_exported_main; + for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { + last_exported_main[i] = { 0, time_in_minutes(m_time_processor.machines[i].time) }; + } + + // keeps track of last exported remaining time to next printer stop + std::array(PrintEstimatedStatistics::ETimeMode::Count)> last_exported_stop; + for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { + last_exported_stop[i] = time_in_minutes(m_time_processor.machines[i].time); + } + + // Helper class to modify and export gcode to file + class ExportLines + { + public: + struct Backtrace + { + float time{ 60.0f }; + unsigned int steps{ 10 }; + float time_step() const { return time / float(steps); } + }; + + enum class EWriteType + { + BySize, + ByTime + }; + + private: + struct LineData + { + std::string line; + std::array(PrintEstimatedStatistics::ETimeMode::Count)> times{ 0.0f, 0.0f }; + }; + + enum ETimeMode + { + Normal = static_cast(PrintEstimatedStatistics::ETimeMode::Normal), + Stealth = static_cast(PrintEstimatedStatistics::ETimeMode::Stealth) + }; + +#ifndef NDEBUG + class Statistics + { + ExportLines& m_parent; + size_t m_max_size{ 0 }; + size_t m_lines_count{ 0 }; + size_t m_max_lines_count{ 0 }; + + public: + explicit Statistics(ExportLines& parent) + : m_parent(parent) + {} + + void add_line(size_t line_size) { + ++m_lines_count; + m_max_size = std::max(m_max_size, m_parent.get_size() + line_size); + m_max_lines_count = std::max(m_max_lines_count, m_lines_count); + } + + void remove_line() { --m_lines_count; } + void remove_all_lines() { m_lines_count = 0; } + }; + + Statistics m_statistics; +#endif // NDEBUG + + EWriteType m_write_type{ EWriteType::BySize }; + // Time machines containing g1 times cache + const std::array(PrintEstimatedStatistics::ETimeMode::Count)>& m_machines; + // Current time + std::array(PrintEstimatedStatistics::ETimeMode::Count)> m_times{ 0.0f, 0.0f }; + // Current size in bytes + size_t m_size{ 0 }; + + // gcode lines cache + std::deque m_lines; + size_t m_added_lines_counter{ 0 }; + // map of gcode line ids from original to final + // used to update m_result.moves[].gcode_id + std::vector> m_gcode_lines_map; + + size_t m_times_cache_id{ 0 }; + size_t m_out_file_pos{ 0 }; + + + public: + ExportLines(EWriteType type, + const std::array(PrintEstimatedStatistics::ETimeMode::Count)>& machines) +#ifndef NDEBUG + : m_statistics(*this), m_write_type(type), m_machines(machines) {} +#else + : m_write_type(type), m_machines(machines) {} +#endif // NDEBUG + + // return: number of internal G1 lines (from G2/G3 splitting) processed + unsigned int update(const std::string& line, size_t lines_counter, size_t g1_lines_counter) { + unsigned int ret = 0; + m_gcode_lines_map.push_back({ lines_counter, 0 }); + + if (GCodeReader::GCodeLine::cmd_is(line, "G0") || + GCodeReader::GCodeLine::cmd_is(line, "G1") || + GCodeReader::GCodeLine::cmd_is(line, "G2") || + GCodeReader::GCodeLine::cmd_is(line, "G3") || + GCodeReader::GCodeLine::cmd_is(line, "G28")) + ++g1_lines_counter; + else + return ret; + + auto init_it = m_machines[Normal].g1_times_cache.begin() + m_times_cache_id; + auto it = init_it; + while (it != m_machines[Normal].g1_times_cache.end() && it->id < g1_lines_counter) { + ++it; + ++m_times_cache_id; + } + + if (it == m_machines[Normal].g1_times_cache.end() || it->id > g1_lines_counter) + return ret; + + // search for internal G1 lines + if (GCodeReader::GCodeLine::cmd_is(line, "G2") || GCodeReader::GCodeLine::cmd_is(line, "G3")) { + while (it != m_machines[Normal].g1_times_cache.end() && it->remaining_internal_g1_lines > 0) { + ++it; + ++m_times_cache_id; + ++g1_lines_counter; + ++ret; + } + } + + if (it != m_machines[Normal].g1_times_cache.end() && it->id == g1_lines_counter) { + m_times[Normal] = it->elapsed_time; + if (!m_machines[Stealth].g1_times_cache.empty()) + m_times[Stealth] = (m_machines[Stealth].g1_times_cache.begin() + std::distance(m_machines[Normal].g1_times_cache.begin(), it))->elapsed_time; + } + + return ret; + } + + // add the given gcode line to the cache + void append_line(const std::string& line) { + m_lines.push_back({ line, m_times }); +#ifndef NDEBUG + m_statistics.add_line(line.length()); +#endif // NDEBUG + m_size += line.length(); + ++m_added_lines_counter; + assert(!m_gcode_lines_map.empty()); + m_gcode_lines_map.back().second = m_added_lines_counter; + } + + // Insert the gcode lines required by the command cmd by backtracing into the cache + void insert_lines(const Backtrace& backtrace, const std::string& cmd, + std::function&)> line_inserter, + std::function line_replacer) { + assert(!m_lines.empty()); + const float time_step = backtrace.time_step(); + size_t rev_it_dist = 0; // distance from the end of the cache of the starting point of the backtrace + float last_time_insertion = 0.0f; // used to avoid inserting two lines at the same time + for (unsigned int i = 0; i < backtrace.steps; ++i) { + const float backtrace_time_i = (i + 1) * time_step; + const float time_threshold_i = m_times[Normal] - backtrace_time_i; + auto rev_it = m_lines.rbegin() + rev_it_dist; + auto start_rev_it = rev_it; + + std::string curr_cmd = GCodeReader::GCodeLine::extract_cmd(rev_it->line); + // backtrace into the cache to find the place where to insert the line + while (rev_it != m_lines.rend() && rev_it->times[Normal] > time_threshold_i && curr_cmd != cmd && curr_cmd != "G28" && curr_cmd != "G29") { + rev_it->line = line_replacer(rev_it->line); + ++rev_it; + if (rev_it != m_lines.rend()) + curr_cmd = GCodeReader::GCodeLine::extract_cmd(rev_it->line); + } + + // we met the previous evenience of cmd, or a G28/G29 command. stop inserting lines + // Orca: 1. Use boost::iequals to handle g28/g29 cases + // 2. Handle PRINT_START and START_PRINT to the stop condition + if (rev_it != m_lines.rend() && (curr_cmd == cmd || boost::iequals(curr_cmd, "G28") || boost::iequals(curr_cmd, "G29") || + boost::iequals(curr_cmd, "PRINT_START") || boost::iequals(curr_cmd, "START_PRINT"))) + break; + + // insert the line for the current step + if (rev_it != m_lines.rend() && rev_it != start_rev_it && rev_it->times[Normal] != last_time_insertion) { + last_time_insertion = rev_it->times[Normal]; + std::vector time_diffs; + time_diffs.push_back(m_times[Normal] - last_time_insertion); + if (!m_machines[Stealth].g1_times_cache.empty()) + time_diffs.push_back(m_times[Stealth] - rev_it->times[Stealth]); + const std::string out_line = line_inserter(i + 1, time_diffs); + rev_it_dist = std::distance(m_lines.rbegin(), rev_it) + 1; + m_lines.insert(rev_it.base(), { out_line, rev_it->times }); +#ifndef NDEBUG + m_statistics.add_line(out_line.length()); +#endif // NDEBUG + m_size += out_line.length(); + // synchronize gcode lines map + for (auto map_it = m_gcode_lines_map.rbegin(); map_it != m_gcode_lines_map.rbegin() + rev_it_dist - 1; ++map_it) { + ++map_it->second; + } + + ++m_added_lines_counter; + } + } + } + + // write to file: + // m_write_type == EWriteType::ByTime - all lines older than m_time - backtrace_time + // m_write_type == EWriteType::BySize - all lines if current size is greater than 65535 bytes + void write(FilePtr& out, float backtrace_time, GCodeProcessorResult& result, const std::string& out_path) { + if (m_lines.empty()) + return; + + // collect lines to write into a single string + std::string out_string; + if (!m_lines.empty()) { + if (m_write_type == EWriteType::ByTime) { + while (m_lines.front().times[Normal] < m_times[Normal] - backtrace_time) { + const LineData& data = m_lines.front(); + out_string += data.line; + m_size -= data.line.length(); + m_lines.pop_front(); +#ifndef NDEBUG + m_statistics.remove_line(); +#endif // NDEBUG + } + } + else { + if (m_size > 65535) { + while (!m_lines.empty()) { + out_string += m_lines.front().line; + m_lines.pop_front(); + } + m_size = 0; +#ifndef NDEBUG + m_statistics.remove_all_lines(); +#endif // NDEBUG + } + } + } + + { + write_to_file(out, out_string, result, out_path); + update_lines_ends_and_out_file_pos(out_string, result.lines_ends, &m_out_file_pos); + } + } + + // flush the current content of the cache to file + void flush(FilePtr& out, GCodeProcessorResult& result, const std::string& out_path) { + // collect lines to flush into a single string + std::string out_string; + while (!m_lines.empty()) { + out_string += m_lines.front().line; + m_lines.pop_front(); + } + m_size = 0; +#ifndef NDEBUG + m_statistics.remove_all_lines(); +#endif // NDEBUG + + { + write_to_file(out, out_string, result, out_path); + update_lines_ends_and_out_file_pos(out_string, result.lines_ends, &m_out_file_pos); + } + } + + void synchronize_moves(GCodeProcessorResult& result) const { + auto it = m_gcode_lines_map.begin(); + for (GCodeProcessorResult::MoveVertex& move : result.moves) { + while (it != m_gcode_lines_map.end() && it->first < move.gcode_id) { + ++it; + } + if (it != m_gcode_lines_map.end() && it->first == move.gcode_id) + move.gcode_id = it->second; + } + } + + size_t get_size() const { return m_size; } + + private: + void write_to_file(FilePtr& out, const std::string& out_string, GCodeProcessorResult& result, const std::string& out_path) { + if (!out_string.empty()) { + if (true) { + fwrite((const void*)out_string.c_str(), 1, out_string.length(), out.f); + if (ferror(out.f)) { + out.close(); + boost::nowide::remove(out_path.c_str()); + throw Slic3r::RuntimeError("GCode processor post process export failed.\nIs the disk full?"); + } + } + } + } + }; + + ExportLines export_lines(m_result.backtrace_enabled ? ExportLines::EWriteType::ByTime : ExportLines::EWriteType::BySize, + m_time_processor.machines); + + // replace placeholder lines with the proper final value + // gcode_line is in/out parameter, to reduce expensive memory allocation + auto process_placeholders = [&](std::string& gcode_line) { + bool processed = false; + + // remove trailing '\n' + auto line = std::string_view(gcode_line).substr(0, gcode_line.length() - 1); + + if (line.length() > 1) { + line = line.substr(1); + if (true && + (line == reserved_tag(ETags::First_Line_M73_Placeholder) || line == reserved_tag(ETags::Last_Line_M73_Placeholder))) { + for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { + const TimeMachine& machine = m_time_processor.machines[i]; + if (machine.enabled) { + // export pair + export_lines.append_line(format_line_M73_main(machine.line_m73_main_mask.c_str(), + (line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? 0 : 100, + (line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? time_in_minutes(machine.time) : 0)); + processed = true; + + // export remaining time to next printer stop + if (line == reserved_tag(ETags::First_Line_M73_Placeholder) && !machine.stop_times.empty()) { + const int to_export_stop = time_in_minutes(machine.stop_times.front().elapsed_time); + export_lines.append_line(format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop)); + last_exported_stop[i] = to_export_stop; + } + } + } + } + else if (line == reserved_tag(ETags::Estimated_Printing_Time_Placeholder)) { + for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { + const TimeMachine& machine = m_time_processor.machines[i]; + PrintEstimatedStatistics::ETimeMode mode = static_cast(i); + if (mode == PrintEstimatedStatistics::ETimeMode::Normal || machine.enabled) { + char buf[128]; + sprintf(buf, "; estimated printing time (%s mode) = %s\n", + (mode == PrintEstimatedStatistics::ETimeMode::Normal) ? "normal" : "silent", + get_time_dhms(machine.time).c_str()); + export_lines.append_line(buf); + processed = true; + } + } + for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { + const TimeMachine& machine = m_time_processor.machines[i]; + PrintEstimatedStatistics::ETimeMode mode = static_cast(i); + if (mode == PrintEstimatedStatistics::ETimeMode::Normal || machine.enabled) { + char buf[128]; + sprintf(buf, "; estimated first layer printing time (%s mode) = %s\n", + (mode == PrintEstimatedStatistics::ETimeMode::Normal) ? "normal" : "silent", + get_time_dhms(machine.prepare_time).c_str()); + export_lines.append_line(buf); + processed = true; + } + } + } + } + + return processed; + }; + + auto process_used_filament = [&](std::string& gcode_line) { + // Prefilter for parsing speed. + if (gcode_line.size() < 8 || gcode_line[0] != ';' || gcode_line[1] != ' ') + return false; + if (const char c = gcode_line[2]; c != 'f' && c != 't') + return false; + auto process_tag = [](std::string& gcode_line, const std::string_view tag, const std::vector& values) { + if (boost::algorithm::starts_with(gcode_line, tag)) { + gcode_line = tag; + char buf[1024]; + for (size_t i = 0; i < values.size(); ++i) { + sprintf(buf, i == values.size() - 1 ? " %.2lf\n" : " %.2lf,", values[i]); + gcode_line += buf; + } + return true; + } + return false; + }; + + bool ret = false; + ret |= process_tag(gcode_line, PrintStatistics::FilamentUsedMmMask, filament_mm); + ret |= process_tag(gcode_line, PrintStatistics::FilamentUsedGMask, filament_g); + ret |= process_tag(gcode_line, PrintStatistics::TotalFilamentUsedGMask, { filament_total_g }); + ret |= process_tag(gcode_line, PrintStatistics::FilamentUsedCm3Mask, filament_cm3); + ret |= process_tag(gcode_line, PrintStatistics::FilamentCostMask, filament_cost); + ret |= process_tag(gcode_line, PrintStatistics::TotalFilamentCostMask, { filament_total_cost }); + return ret; + }; + + // check for temporary lines + auto is_temporary_decoration = [](const std::string_view gcode_line) { + // remove trailing '\n' + assert(!gcode_line.empty()); + assert(gcode_line.back() == '\n'); + + // return true for decorations which are used in processing the gcode but that should not be exported into the final gcode + // i.e.: + // bool ret = gcode_line.substr(0, gcode_line.length() - 1) == ";" + Layer_Change_Tag; + // ... + // return ret; + return false; + }; + + // Iterators for the normal and silent cached time estimate entry recently processed, used by process_line_G1. + auto g1_times_cache_it = Slic3r::reserve_vector::const_iterator>(m_time_processor.machines.size()); + for (const auto& machine : m_time_processor.machines) + g1_times_cache_it.emplace_back(machine.g1_times_cache.begin()); + + // add lines M73 to exported gcode + auto process_line_G1 = [this, + // Lambdas, mostly for string formatting, all with an empty capture block. + time_in_minutes, format_time_float, format_line_M73_main, format_line_M73_stop_int, format_line_M73_stop_float, time_in_last_minute, + // Caches, to be modified + &g1_times_cache_it, &last_exported_main, &last_exported_stop, + &export_lines] + (const size_t g1_lines_counter) { + if (true) { + for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { + const TimeMachine& machine = m_time_processor.machines[i]; + if (machine.enabled) { + // export pair + // Skip all machine.g1_times_cache below g1_lines_counter. + auto& it = g1_times_cache_it[i]; + while (it != machine.g1_times_cache.end() && it->id < g1_lines_counter) + ++it; + if (it != machine.g1_times_cache.end() && it->id == g1_lines_counter) { + std::pair to_export_main = { int(100.0f * it->elapsed_time / machine.time), + time_in_minutes(machine.time - it->elapsed_time) }; + if (last_exported_main[i] != to_export_main) { + export_lines.append_line(format_line_M73_main(machine.line_m73_main_mask.c_str(), + to_export_main.first, to_export_main.second)); + last_exported_main[i] = to_export_main; + } + // export remaining time to next printer stop + auto it_stop = std::upper_bound(machine.stop_times.begin(), machine.stop_times.end(), it->elapsed_time, + [](float value, const TimeMachine::StopTime& t) { return value < t.elapsed_time; }); + if (it_stop != machine.stop_times.end()) { + int to_export_stop = time_in_minutes(it_stop->elapsed_time - it->elapsed_time); + if (last_exported_stop[i] != to_export_stop) { + if (to_export_stop > 0) { + if (last_exported_stop[i] != to_export_stop) { + export_lines.append_line(format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop)); + last_exported_stop[i] = to_export_stop; + } + } + else { + bool is_last = false; + auto next_it = it + 1; + is_last |= (next_it == machine.g1_times_cache.end()); + + if (next_it != machine.g1_times_cache.end()) { + auto next_it_stop = std::upper_bound(machine.stop_times.begin(), machine.stop_times.end(), next_it->elapsed_time, + [](float value, const TimeMachine::StopTime& t) { return value < t.elapsed_time; }); + is_last |= (next_it_stop != it_stop); + + std::string time_float_str = format_time_float(time_in_last_minute(it_stop->elapsed_time - it->elapsed_time)); + std::string next_time_float_str = format_time_float(time_in_last_minute(it_stop->elapsed_time - next_it->elapsed_time)); + is_last |= (string_to_double_decimal_point(time_float_str) > 0. && string_to_double_decimal_point(next_time_float_str) == 0.); + } + + if (is_last) { + if (std::distance(machine.stop_times.begin(), it_stop) == static_cast(machine.stop_times.size() - 1)) + export_lines.append_line(format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop)); + else + export_lines.append_line(format_line_M73_stop_float(machine.line_m73_stop_mask.c_str(), time_in_last_minute(it_stop->elapsed_time - it->elapsed_time))); + + last_exported_stop[i] = to_export_stop; + } + } + } + } + } + } + } + } + }; + + // add lines M104 to exported gcode + auto process_line_T = [this, &export_lines](const std::string& gcode_line, const size_t g1_lines_counter, const ExportLines::Backtrace& backtrace) { + const std::string cmd = GCodeReader::GCodeLine::extract_cmd(gcode_line); + if (cmd.size() >= 2) { + std::stringstream ss(cmd.substr(1)); + int tool_number = -1; + ss >> tool_number; + if (tool_number != -1) { + if (tool_number < 0 || (int)m_extruder_temps_config.size() <= tool_number) { + // found an invalid value, clamp it to a valid one + tool_number = std::clamp(0, m_extruder_temps_config.size() - 1, tool_number); + // emit warning + std::string warning = _u8L("GCode Post-Processor encountered an invalid toolchange, maybe from a custom gcode:"); + warning += "\n> "; + warning += gcode_line; + warning += _u8L("Generated M104 lines may be incorrect."); + BOOST_LOG_TRIVIAL(error) << warning; + // Orca todo + // if (m_print != nullptr) + // m_print->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, warning); + } + } + export_lines.insert_lines( + backtrace, cmd, + // line inserter + [tool_number, this](unsigned int id, const std::vector& time_diffs) { + const int temperature = int(m_layer_id != 1 ? m_extruder_temps_config[tool_number] : + m_extruder_temps_first_layer_config[tool_number]); + // Orca: M104.1 for XL printers, I can't find the documentation for this so I copied the C++ comments from + // Prusa-Firmware-Buddy here + /** + * M104.1: Early Set Hotend Temperature (preheat, and with stealth mode support) + * + * This GCode is used to tell the XL printer the time estimate when a tool will be used next, + * so that the printer can start preheating the tool in advance. + * + * ## Parameters + * - `P` - - time in seconds till the temperature S is required (in standard mode) + * - `Q` - - time in seconds till the temperature S is required (in stealth mode) + * The rest is same as M104 + */ + if (this->m_is_XL_printer) { + std::string out = "M104.1 T" + std::to_string(tool_number); + if (time_diffs.size() > 0) + out += " P" + std::to_string(int(std::round(time_diffs[0]))); + if (time_diffs.size() > 1) + out += " Q" + std::to_string(int(std::round(time_diffs[1]))); + out += " S" + std::to_string(temperature) + "\n"; + return out; + } else { + std::string comment = "preheat tool " + std::to_string(tool_number) + + "time: " + std::to_string(std::round(time_diffs[0])) + "s"; + return GCodeWriter::set_temperature(temperature, this->m_flavor, false, tool_number, comment); + } + }, + // line replacer + [this, tool_number](const std::string& line) { + if (GCodeReader::GCodeLine::cmd_is(line, "M104")) { + GCodeReader::GCodeLine gline; + GCodeReader reader; + reader.parse_line(line, [&gline](GCodeReader& reader, const GCodeReader::GCodeLine& l) { gline = l; }); + + float val; + if (gline.has_value('T', val) && gline.raw().find("cooldown") != std::string::npos && m_is_XL_printer) { + if (static_cast(val) == tool_number) + return std::string("; removed M104\n"); + } + } + return line; + }); + } + }; + + m_result.lines_ends.clear(); + // m_result.lines_ends.emplace_back(std::vector()); + + unsigned int line_id = 0; + // Backtrace data for Tx gcode lines + static const ExportLines::Backtrace backtrace_T = { 120.0f, 10 }; + // In case there are multiple sources of backtracing, keeps track of the longest backtrack time needed + // to flush the backtrace cache accordingly + float max_backtrace_time = 120.0f; + + { + // Read the input stream 64kB at a time, extract lines and process them. + std::vector buffer(65536 * 10, 0); + // Line buffer. + assert(gcode_line.empty()); + for (;;) { + size_t cnt_read = ::fread(buffer.data(), 1, buffer.size(), in.f); + if (::ferror(in.f)) + throw Slic3r::RuntimeError(std::string("GCode processor post process export failed.\nError while reading from file.\n")); + bool eof = cnt_read == 0; + auto it = buffer.begin(); + auto it_bufend = buffer.begin() + cnt_read; + while (it != it_bufend || (eof && !gcode_line.empty())) { + // Find end of line. + bool eol = false; + auto it_end = it; + for (; it_end != it_bufend && !(eol = *it_end == '\r' || *it_end == '\n'); ++it_end); + // End of line is indicated also if end of file was reached. + eol |= eof && it_end == it_bufend; + gcode_line.insert(gcode_line.end(), it, it_end); + if (eol) { + ++line_id; + gcode_line += "\n"; + const unsigned int internal_g1_lines_counter = export_lines.update(gcode_line, line_id, g1_lines_counter); + // replace placeholder lines + bool processed = process_placeholders(gcode_line); + if (processed) + gcode_line.clear(); + if (!processed) + processed = process_used_filament(gcode_line); + if (!processed && !is_temporary_decoration(gcode_line)) { + if (GCodeReader::GCodeLine::cmd_is(gcode_line, "G0") || GCodeReader::GCodeLine::cmd_is(gcode_line, "G1")) { + export_lines.append_line(gcode_line); + // add lines M73 where needed + process_line_G1(g1_lines_counter++); + gcode_line.clear(); + } + else if (GCodeReader::GCodeLine::cmd_is(gcode_line, "G2") || GCodeReader::GCodeLine::cmd_is(gcode_line, "G3")) { + export_lines.append_line(gcode_line); + // add lines M73 where needed + process_line_G1(g1_lines_counter + internal_g1_lines_counter); + g1_lines_counter += (1 + internal_g1_lines_counter); + gcode_line.clear(); + } + else if (GCodeReader::GCodeLine::cmd_is(gcode_line, "G28")) { + ++g1_lines_counter; + } + else if (m_result.backtrace_enabled && GCodeReader::GCodeLine::cmd_starts_with(gcode_line, "T")) { + // add lines M104 where needed + process_line_T(gcode_line, g1_lines_counter, backtrace_T); + max_backtrace_time = std::max(max_backtrace_time, backtrace_T.time); + } + } + + if (!gcode_line.empty()) + export_lines.append_line(gcode_line); + export_lines.write(out, 1.1f * max_backtrace_time, m_result, out_path); + gcode_line.clear(); + } + // Skip EOL. + it = it_end; + if (it != it_bufend && *it == '\r') + ++it; + if (it != it_bufend && *it == '\n') + ++it; + } + if (eof) + break; + } + } + + export_lines.flush(out, m_result, out_path); + + + out.close(); + in.close(); + + const std::string result_filename = m_result.filename; + export_lines.synchronize_moves(m_result); + + if (rename_file(out_path, result_filename)) + throw Slic3r::RuntimeError(std::string("Failed to rename the output G-code file from ") + out_path + " to " + result_filename + '\n' + + "Is " + out_path + " locked?" + '\n'); +} void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type) { diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index a1fd5237e3..2896583786 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -17,6 +17,8 @@ namespace Slic3r { +class Print; + // slice warnings enum strings #define NOZZLE_HRC_CHECKER "the_actual_nozzle_hrc_smaller_than_the_required_nozzle_hrc" #define BED_TEMP_TOO_HIGH_THAN_FILAMENT "bed_temperature_too_high_than_filament" @@ -207,6 +209,7 @@ namespace Slic3r { float printable_height; SettingsIds settings_ids; size_t extruders_count; + bool backtrace_enabled; std::vector extruder_colors; std::vector filament_diameters; std::vector required_nozzle_HRC; @@ -377,6 +380,7 @@ namespace Slic3r { EMoveType move_type{ EMoveType::Noop }; ExtrusionRole role{ erNone }; unsigned int g1_line_id{ 0 }; + unsigned int remaining_internal_g1_lines; unsigned int layer_id{ 0 }; float distance{ 0.0f }; // mm float acceleration{ 0.0f }; // mm/s^2 @@ -425,6 +429,7 @@ namespace Slic3r { struct G1LinesCacheItem { unsigned int id; + unsigned int remaining_internal_g1_lines; float elapsed_time; }; @@ -709,6 +714,9 @@ namespace Slic3r { unsigned char m_last_extruder_id; ExtruderColors m_extruder_colors; ExtruderTemps m_extruder_temps; + ExtruderTemps m_extruder_temps_config; + ExtruderTemps m_extruder_temps_first_layer_config; + bool m_is_XL_printer = false; int m_highest_bed_temp; float m_extruded_last_z; float m_first_layer_height; // mm @@ -722,6 +730,7 @@ namespace Slic3r { size_t m_last_default_color_id; bool m_detect_layer_based_on_tag {false}; int m_seams_count; + bool m_single_extruder_multi_material; #if ENABLE_GCODE_VIEWER_STATISTICS std::chrono::time_point m_start_time; #endif // ENABLE_GCODE_VIEWER_STATISTICS @@ -746,6 +755,8 @@ namespace Slic3r { TimeProcessor m_time_processor; UsedFilaments m_used_filaments; + Print* m_print{ nullptr }; + GCodeProcessorResult m_result; static unsigned int s_result_id; @@ -759,6 +770,7 @@ namespace Slic3r { GCodeProcessor(); void apply_config(const PrintConfig& config); + void set_print(Print* print) { m_print = print; } void enable_stealth_time_estimator(bool enabled); bool is_stealth_time_estimator_enabled() const { return m_time_processor.machines[static_cast(PrintEstimatedStatistics::ETimeMode::Stealth)].enabled; @@ -815,7 +827,7 @@ namespace Slic3r { // Move void process_G0(const GCodeReader::GCodeLine& line); - void process_G1(const GCodeReader::GCodeLine& line); + void process_G1(const GCodeReader::GCodeLine& line, const std::optional& remaining_internal_g1_lines = std::nullopt); void process_G2_G3(const GCodeReader::GCodeLine& line); // BBS: handle delay command @@ -930,6 +942,11 @@ namespace Slic3r { void process_T(const GCodeReader::GCodeLine& line); void process_T(const std::string_view command); + // post process the file with the given filename to: + // 1) add remaining time lines M73 and update moves' gcode ids accordingly + // 2) update used filament data + void run_post_process(); + //BBS: different path_type is only used for arc move void store_move_vertex(EMoveType type, EMovePathType path_type = EMovePathType::Noop_move); @@ -943,7 +960,7 @@ namespace Slic3r { Vec3f get_xyz_max_jerk(PrintEstimatedStatistics::ETimeMode mode) const; float get_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode) const; void set_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode, float value); - float get_acceleration(PrintEstimatedStatistics::ETimeMode mode) const; + float get_acceleration(PrintEstimatedStatistics::ETimeMode mode) const; void set_acceleration(PrintEstimatedStatistics::ETimeMode mode, float value); float get_travel_acceleration(PrintEstimatedStatistics::ETimeMode mode) const; void set_travel_acceleration(PrintEstimatedStatistics::ETimeMode mode, float value); diff --git a/src/libslic3r/GCode/WipeTower2.cpp b/src/libslic3r/GCode/WipeTower2.cpp index 71e532122b..521dd9b746 100644 --- a/src/libslic3r/GCode/WipeTower2.cpp +++ b/src/libslic3r/GCode/WipeTower2.cpp @@ -781,49 +781,7 @@ std::vector WipeTower2::prime( return results; } -#define FLAVOR_IS(val) this->m_gcode_flavor == val -#define FLAVOR_IS_NOT(val) this->m_gcode_flavor != val -std::string WipeTower2::set_preheat_temperature(unsigned int temperature, bool wait, int tool) -{ - if (wait && (FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish))) - return ""; - - std::string code, comment; - if (wait && FLAVOR_IS_NOT(gcfTeacup) && FLAVOR_IS_NOT(gcfRepRapFirmware)) { - code = "M109"; - comment = "set nozzle temperature and wait for it to be reached"; - } else { - if (FLAVOR_IS(gcfRepRapFirmware)) { // M104 is deprecated on RepRapFirmware - code = "G10"; - } else { - code = "M104"; - } - comment = "preheat next nozzle"; - } - - std::ostringstream gcode; - gcode << code << " "; - if (FLAVOR_IS(gcfMach3) || FLAVOR_IS(gcfMachinekit)) { - gcode << "P"; - } else { - gcode << "S"; - } - gcode << temperature; - if (tool != -1) { - if (FLAVOR_IS(gcfRepRapFirmware)) { - gcode << " P" << tool; - } else { - gcode << " T" << tool; - } - } - gcode << " ; " << comment << "\n"; - - if ((FLAVOR_IS(gcfTeacup) || FLAVOR_IS(gcfRepRapFirmware)) && wait) - gcode << "M116 ; wait for temperature to be reached\n"; - - return gcode.str(); -} WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool) { size_t old_tool = m_current_tool; @@ -879,8 +837,6 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool) // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool. if (tool != (unsigned int)-1){ // This is not the last change. auto new_tool_temp = is_first_layer() ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature; - // Orca: pre-heat next tool, it's a temperary solution before impelment the proper preheat. - writer.append(set_preheat_temperature(new_tool_temp, false, tool)); toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, (is_first_layer() ? m_filpar[m_current_tool].first_layer_temperature : m_filpar[m_current_tool].temperature), new_tool_temp); diff --git a/src/libslic3r/GCode/WipeTower2.hpp b/src/libslic3r/GCode/WipeTower2.hpp index 1d37cbe791..0f377d00f7 100644 --- a/src/libslic3r/GCode/WipeTower2.hpp +++ b/src/libslic3r/GCode/WipeTower2.hpp @@ -255,9 +255,6 @@ private: // Goes through m_plan, calculates border and finish_layer extrusions and subtracts them from last wipe void save_on_last_wipe(); - // Orca: temp help function to set temperature - std::string set_preheat_temperature(unsigned int temperature, bool wait, int tool); - // to store information about tool changes for a given layer struct WipeTowerInfo{ struct ToolChange { diff --git a/src/libslic3r/GCodeReader.hpp b/src/libslic3r/GCodeReader.hpp index 52a37dde55..5d3b6a39ed 100644 --- a/src/libslic3r/GCodeReader.hpp +++ b/src/libslic3r/GCodeReader.hpp @@ -79,6 +79,16 @@ public: return strncmp(cmd, cmd_test, len) == 0 && GCodeReader::is_end_of_word(cmd[len]); } + static bool cmd_starts_with(const std::string& gcode_line, const char* cmd_test) { + return strncmp(GCodeReader::skip_whitespaces(gcode_line.c_str()), cmd_test, strlen(cmd_test)) == 0; + } + + static std::string extract_cmd(const std::string& gcode_line) { + GCodeLine temp; + temp.m_raw = gcode_line; + const std::string_view cmd = temp.cmd(); + return { cmd.begin(), cmd.end() }; + } private: std::string m_raw; float m_axis[NUM_AXES]; diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index d4ebb64362..f60d81a95a 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -90,48 +90,56 @@ std::string GCodeWriter::postamble() const return gcode.str(); } -std::string GCodeWriter::set_temperature(unsigned int temperature, bool wait, int tool) const -{ - if (wait && (FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish))) +std::string GCodeWriter::set_temperature(unsigned int temperature, GCodeFlavor flavor, bool wait, int tool, std::string comment){ + if (wait && (flavor == gcfMakerWare || flavor == gcfSailfish)) return ""; - - std::string code, comment; - if (wait && FLAVOR_IS_NOT(gcfTeacup) && FLAVOR_IS_NOT(gcfRepRapFirmware)) { - code = "M109"; - comment = "set nozzle temperature and wait for it to be reached"; + + std::string code; + if (wait && flavor != gcfTeacup && flavor != gcfRepRapFirmware) { + code = "M109"; + if(comment.empty()) + comment = "set nozzle temperature and wait for it to be reached"; } else { - if (FLAVOR_IS(gcfRepRapFirmware)) { // M104 is deprecated on RepRapFirmware + if (flavor == gcfRepRapFirmware) { // M104 is deprecated on RepRapFirmware code = "G10"; } else { code = "M104"; } - comment = "set nozzle temperature"; + if(comment.empty()) + comment = "set nozzle temperature"; } - + std::ostringstream gcode; gcode << code << " "; - if (FLAVOR_IS(gcfMach3) || FLAVOR_IS(gcfMachinekit)) { + if (flavor == gcfMach3 || flavor == gcfMachinekit) { gcode << "P"; } else { gcode << "S"; } gcode << temperature; - bool multiple_tools = this->multiple_extruders && ! m_single_extruder_multi_material; - if (tool != -1 && (multiple_tools || FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish)) ) { - if (FLAVOR_IS(gcfRepRapFirmware)) { + if (tool != -1) { + if (flavor == gcfRepRapFirmware) { gcode << " P" << tool; } else { gcode << " T" << tool; } } gcode << " ; " << comment << "\n"; - - if ((FLAVOR_IS(gcfTeacup) || FLAVOR_IS(gcfRepRapFirmware)) && wait) + + if ((flavor == gcfTeacup || flavor == gcfRepRapFirmware) && wait) gcode << "M116 ; wait for temperature to be reached\n"; - + return gcode.str(); } +std::string GCodeWriter::set_temperature(unsigned int temperature, bool wait, int tool) const +{ + // set tool to -1 to make sure we won't emit T parameter for single extruder or SEMM + if (!this->multiple_extruders || m_single_extruder_multi_material) + tool = -1; + return set_temperature(temperature, this->config.gcode_flavor, wait, tool); +} + // BBS std::string GCodeWriter::set_bed_temperature(int temperature, bool wait) { diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index 8e1effcc4e..df68f549fd 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -43,6 +43,8 @@ public: } std::string preamble(); std::string postamble() const; + static std::string set_temperature(unsigned int temperature, GCodeFlavor flavor, bool wait = false, int tool = -1, std::string comment = std::string()); + std::string set_temperature(unsigned int temperature, bool wait = false, int tool = -1) const; std::string set_bed_temperature(int temperature, bool wait = false); std::string set_chamber_temperature(int temperature, bool wait = false); diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 3650b4ef90..dd401776a4 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -2935,6 +2935,30 @@ std::string PrintStatistics::finalize_output_path(const std::string &path_in) co return final_path; } +const std::string PrintStatistics::FilamentUsedG = "filament used [g]"; +const std::string PrintStatistics::FilamentUsedGMask = "; filament used [g] ="; + +const std::string PrintStatistics::TotalFilamentUsedG = "total filament used [g]"; +const std::string PrintStatistics::TotalFilamentUsedGMask = "; total filament used [g] ="; +const std::string PrintStatistics::TotalFilamentUsedGValueMask = "; total filament used [g] = %.2lf\n"; + +const std::string PrintStatistics::FilamentUsedCm3 = "filament used [cm3]"; +const std::string PrintStatistics::FilamentUsedCm3Mask = "; filament used [cm3] ="; + +const std::string PrintStatistics::FilamentUsedMm = "filament used [mm]"; +const std::string PrintStatistics::FilamentUsedMmMask = "; filament used [mm] ="; + +const std::string PrintStatistics::FilamentCost = "filament cost"; +const std::string PrintStatistics::FilamentCostMask = "; filament cost ="; + +const std::string PrintStatistics::TotalFilamentCost = "total filament cost"; +const std::string PrintStatistics::TotalFilamentCostMask = "; total filament cost ="; +const std::string PrintStatistics::TotalFilamentCostValueMask = "; total filament cost = %.2lf\n"; + +const std::string PrintStatistics::TotalFilamentUsedWipeTower = "total filament used for wipe tower [g]"; +const std::string PrintStatistics::TotalFilamentUsedWipeTowerValueMask = "; total filament used for wipe tower [g] = %.2lf\n"; + + /*add json export/import related functions */ #define JSON_POLYGON_CONTOUR "contour" #define JSON_POLYGON_HOLES "holes" diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index bd7b867b99..aebb46899f 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -771,6 +771,23 @@ struct PrintStatistics initial_tool = 0; filament_stats.clear(); } + static const std::string FilamentUsedG; + static const std::string FilamentUsedGMask; + static const std::string TotalFilamentUsedG; + static const std::string TotalFilamentUsedGMask; + static const std::string TotalFilamentUsedGValueMask; + static const std::string FilamentUsedCm3; + static const std::string FilamentUsedCm3Mask; + static const std::string FilamentUsedMm; + static const std::string FilamentUsedMmMask; + static const std::string FilamentCost; + static const std::string FilamentCostMask; + static const std::string TotalFilamentCost; + static const std::string TotalFilamentCostMask; + static const std::string TotalFilamentCostValueMask; + static const std::string TotalFilamentUsedWipeTower; + static const std::string TotalFilamentUsedWipeTowerValueMask; + }; typedef std::vector PrintObjectPtrs; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 57697dd8d1..7856bd6ba6 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -7677,6 +7677,22 @@ bool has_skirt(const DynamicPrintConfig& cfg) float get_real_skirt_dist(const DynamicPrintConfig& cfg) { return has_skirt(cfg) ? cfg.opt_float("skirt_distance") : 0; } +static bool is_XL_printer(const std::string& printer_notes) +{ + return boost::algorithm::contains(printer_notes, "PRINTER_VENDOR_PRUSA3D") + && boost::algorithm::contains(printer_notes, "PRINTER_MODEL_XL"); +} + +bool is_XL_printer(const DynamicPrintConfig &cfg) +{ + auto *printer_notes = cfg.opt("printer_notes"); + return printer_notes && is_XL_printer(printer_notes->value); +} + +bool is_XL_printer(const PrintConfig &cfg) +{ + return is_XL_printer(cfg.printer_notes.value); +} } // namespace Slic3r #include diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 89a020774e..620a24b381 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1651,6 +1651,9 @@ private: static PrintAndCLIConfigDef s_def; }; +bool is_XL_printer(const DynamicPrintConfig &cfg); +bool is_XL_printer(const PrintConfig &cfg); + Points get_bed_shape(const DynamicPrintConfig &cfg); Points get_bed_shape(const PrintConfig &cfg); Points get_bed_shape(const SLAPrinterConfig &cfg); From 447cc0140519ee98eb289e7ebd3d5146903bd744 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Sun, 21 Jul 2024 17:58:37 +0800 Subject: [PATCH 23/32] preheat work - done --- resources/profiles/Custom.json | 2 +- .../machine/fdm_toolchanger_common.json | 2 +- .../fdm_process_mytoolchanger_common.json | 6 ++- resources/profiles/Prusa.json | 2 +- .../Prusa/process/process_common_xl_5t.json | 4 +- src/libslic3r/GCode/GCodeProcessor.cpp | 37 ++++++++++++------- src/libslic3r/GCode/GCodeProcessor.hpp | 2 + src/libslic3r/Preset.cpp | 2 +- src/libslic3r/Print.cpp | 2 + src/libslic3r/PrintConfig.cpp | 20 ++++++++++ src/libslic3r/PrintConfig.hpp | 2 + src/slic3r/GUI/ConfigManipulation.cpp | 7 +++- src/slic3r/GUI/Tab.cpp | 2 + 13 files changed, 69 insertions(+), 21 deletions(-) diff --git a/resources/profiles/Custom.json b/resources/profiles/Custom.json index 9aa9bfde7b..e4dae5bd72 100644 --- a/resources/profiles/Custom.json +++ b/resources/profiles/Custom.json @@ -1,6 +1,6 @@ { "name": "Custom Printer", - "version": "02.01.03.00", + "version": "02.01.04.00", "force_update": "0", "description": "My configurations", "machine_model_list": [ diff --git a/resources/profiles/Custom/machine/fdm_toolchanger_common.json b/resources/profiles/Custom/machine/fdm_toolchanger_common.json index 9d724ed88f..0d1fe9c165 100644 --- a/resources/profiles/Custom/machine/fdm_toolchanger_common.json +++ b/resources/profiles/Custom/machine/fdm_toolchanger_common.json @@ -182,7 +182,7 @@ "purge_in_prime_tower": "0", "machine_pause_gcode": "M601", "machine_start_gcode": "PRINT_START TOOL_TEMP={first_layer_temperature[initial_tool]} {if is_extruder_used[0]}T0_TEMP={first_layer_temperature[0]}{endif} {if is_extruder_used[1]}T1_TEMP={first_layer_temperature[1]}{endif} {if is_extruder_used[2]}T2_TEMP={first_layer_temperature[2]}{endif} {if is_extruder_used[3]}T3_TEMP={first_layer_temperature[3]}{endif} {if is_extruder_used[4]}T4_TEMP={first_layer_temperature[4]}{endif} {if is_extruder_used[5]}T5_TEMP={first_layer_temperature[5]}{endif} BED_TEMP=[first_layer_bed_temperature] TOOL=[initial_tool]\n\n", - "change_filament_gcode": "M104 S{nozzle_temperature[next_extruder]} T[next_extruder] ; set new tool temperature so it can start heating while changing", + "change_filament_gcode": "", "scan_first_layer": "0", "nozzle_type": "undefine", "auxiliary_fan": "0" diff --git a/resources/profiles/Custom/process/fdm_process_mytoolchanger_common.json b/resources/profiles/Custom/process/fdm_process_mytoolchanger_common.json index 9d6e497afe..88a499c8d6 100644 --- a/resources/profiles/Custom/process/fdm_process_mytoolchanger_common.json +++ b/resources/profiles/Custom/process/fdm_process_mytoolchanger_common.json @@ -23,5 +23,9 @@ "enable_prime_tower": "1", "wipe_tower_cone_angle": "25", "wipe_tower_extra_spacing": "150%", - "wipe_tower_rotation_angle": "90" + "wipe_tower_rotation_angle": "90", + "ooze_prevention": "1", + "standby_temperature_delta": "-40", + "preheat_time": "30", + "preheat_steps": "1" } \ No newline at end of file diff --git a/resources/profiles/Prusa.json b/resources/profiles/Prusa.json index 071bf1bfb0..b6b8322c6d 100644 --- a/resources/profiles/Prusa.json +++ b/resources/profiles/Prusa.json @@ -1,6 +1,6 @@ { "name": "Prusa", - "version": "02.01.01.30", + "version": "02.01.02.30", "force_update": "0", "description": "Prusa configurations", "machine_model_list": [ diff --git a/resources/profiles/Prusa/process/process_common_xl_5t.json b/resources/profiles/Prusa/process/process_common_xl_5t.json index f624f7780a..1fe313aabe 100644 --- a/resources/profiles/Prusa/process/process_common_xl_5t.json +++ b/resources/profiles/Prusa/process/process_common_xl_5t.json @@ -10,5 +10,7 @@ "wipe_tower_rotation_angle": "90", "single_extruder_multi_material_priming": "0", "ooze_prevention": "1", - "standby_temperature_delta": "-40" + "standby_temperature_delta": "-40", + "preheat_time": "120", + "preheat_steps": "10" } \ No newline at end of file diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index a2393383e9..7506a105d7 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -1058,7 +1058,12 @@ void GCodeProcessor::apply_config(const PrintConfig& config) // Orca: m_is_XL_printer = is_XL_printer(config); - m_result.backtrace_enabled = m_is_XL_printer || ( !m_single_extruder_multi_material && extruders_count > 1); + m_preheat_time = config.preheat_time; + m_preheat_steps = config.preheat_steps; + // sanity check + if(m_preheat_steps < 1) + m_preheat_steps = 1; + m_result.backtrace_enabled = m_preheat_time > 0 && (m_is_XL_printer || (!m_single_extruder_multi_material && extruders_count > 1)); m_extruder_offsets.resize(extruders_count); m_extruder_colors.resize(extruders_count); @@ -1570,6 +1575,8 @@ void GCodeProcessor::reset() m_detect_layer_based_on_tag = false; m_seams_count = 0; + m_preheat_time = 0.f; + m_preheat_steps = 1; #if ENABLE_GCODE_VIEWER_DATA_CHECKING m_mm3_per_mm_compare.reset(); @@ -4465,7 +4472,7 @@ void GCodeProcessor::run_post_process() struct Backtrace { float time{ 60.0f }; - unsigned int steps{ 10 }; + int steps{ 10 }; float time_step() const { return time / float(steps); } }; @@ -4601,11 +4608,18 @@ void GCodeProcessor::run_post_process() void insert_lines(const Backtrace& backtrace, const std::string& cmd, std::function&)> line_inserter, std::function line_replacer) { + // Orca: find start pos by seaching G28/G29/PRINT_START/START_PRINT commands + auto is_start_pos = [](const std::string& curr_cmd) { + return boost::iequals(curr_cmd, "G28") + || boost::iequals(curr_cmd, "G29") + || boost::iequals(curr_cmd, "PRINT_START") + || boost::iequals(curr_cmd, "START_PRINT"); + }; assert(!m_lines.empty()); const float time_step = backtrace.time_step(); size_t rev_it_dist = 0; // distance from the end of the cache of the starting point of the backtrace float last_time_insertion = 0.0f; // used to avoid inserting two lines at the same time - for (unsigned int i = 0; i < backtrace.steps; ++i) { + for (int i = 0; i < backtrace.steps; ++i) { const float backtrace_time_i = (i + 1) * time_step; const float time_threshold_i = m_times[Normal] - backtrace_time_i; auto rev_it = m_lines.rbegin() + rev_it_dist; @@ -4613,18 +4627,15 @@ void GCodeProcessor::run_post_process() std::string curr_cmd = GCodeReader::GCodeLine::extract_cmd(rev_it->line); // backtrace into the cache to find the place where to insert the line - while (rev_it != m_lines.rend() && rev_it->times[Normal] > time_threshold_i && curr_cmd != cmd && curr_cmd != "G28" && curr_cmd != "G29") { + while (rev_it != m_lines.rend() && rev_it->times[Normal] > time_threshold_i && curr_cmd != cmd && !is_start_pos(curr_cmd)) { rev_it->line = line_replacer(rev_it->line); ++rev_it; if (rev_it != m_lines.rend()) curr_cmd = GCodeReader::GCodeLine::extract_cmd(rev_it->line); } - // we met the previous evenience of cmd, or a G28/G29 command. stop inserting lines - // Orca: 1. Use boost::iequals to handle g28/g29 cases - // 2. Handle PRINT_START and START_PRINT to the stop condition - if (rev_it != m_lines.rend() && (curr_cmd == cmd || boost::iequals(curr_cmd, "G28") || boost::iequals(curr_cmd, "G29") || - boost::iequals(curr_cmd, "PRINT_START") || boost::iequals(curr_cmd, "START_PRINT"))) + // we met the previous evenience of cmd, or the start position, stop inserting lines + if (rev_it != m_lines.rend() && (curr_cmd == cmd || is_start_pos(curr_cmd))) break; // insert the line for the current step @@ -4970,8 +4981,8 @@ void GCodeProcessor::run_post_process() out += " S" + std::to_string(temperature) + "\n"; return out; } else { - std::string comment = "preheat tool " + std::to_string(tool_number) + - "time: " + std::to_string(std::round(time_diffs[0])) + "s"; + std::string comment = "preheat T" + std::to_string(tool_number) + + " time: " + std::to_string((int) std::round(time_diffs[0])) + "s"; return GCodeWriter::set_temperature(temperature, this->m_flavor, false, tool_number, comment); } }, @@ -4983,7 +4994,7 @@ void GCodeProcessor::run_post_process() reader.parse_line(line, [&gline](GCodeReader& reader, const GCodeReader::GCodeLine& l) { gline = l; }); float val; - if (gline.has_value('T', val) && gline.raw().find("cooldown") != std::string::npos && m_is_XL_printer) { + if (gline.has_value('T', val) && gline.raw().find("cooldown") != std::string::npos) { if (static_cast(val) == tool_number) return std::string("; removed M104\n"); } @@ -4998,7 +5009,7 @@ void GCodeProcessor::run_post_process() unsigned int line_id = 0; // Backtrace data for Tx gcode lines - static const ExportLines::Backtrace backtrace_T = { 120.0f, 10 }; + const ExportLines::Backtrace backtrace_T = { m_preheat_time, m_preheat_steps }; // In case there are multiple sources of backtracing, keeps track of the longest backtrack time needed // to flush the backtrace cache accordingly float max_backtrace_time = 120.0f; diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index 2896583786..a89ba785c9 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -731,6 +731,8 @@ class Print; bool m_detect_layer_based_on_tag {false}; int m_seams_count; bool m_single_extruder_multi_material; + float m_preheat_time; + int m_preheat_steps; #if ENABLE_GCODE_VIEWER_STATISTICS std::chrono::time_point m_start_time; #endif // ENABLE_GCODE_VIEWER_STATISTICS diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 1a3a984a74..f3d34aab9d 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -784,7 +784,7 @@ static std::vector s_Preset_print_options { "support_top_z_distance", "support_on_build_plate_only","support_critical_regions_only", "bridge_no_support", "thick_bridges", "thick_internal_bridges","dont_filter_internal_bridges", "max_bridge_length", "print_sequence", "print_order", "support_remove_small_overhang", "filename_format", "wall_filament", "support_bottom_z_distance", "sparse_infill_filament", "solid_infill_filament", "support_filament", "support_interface_filament","support_interface_not_for_body", - "ooze_prevention", "standby_temperature_delta", "interface_shells", "line_width", "initial_layer_line_width", + "ooze_prevention", "standby_temperature_delta", "preheat_time","preheat_steps", "interface_shells", "line_width", "initial_layer_line_width", "inner_wall_line_width", "outer_wall_line_width", "sparse_infill_line_width", "internal_solid_infill_line_width", "top_surface_line_width", "support_line_width", "infill_wall_overlap","top_bottom_infill_wall_overlap", "bridge_flow", "internal_bridge_flow", "elefant_foot_compensation", "elefant_foot_compensation_layers", "xy_contour_compensation", "xy_hole_compensation", "resolution", "enable_prime_tower", diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index dd401776a4..b4bc6dadab 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -161,6 +161,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n "use_firmware_retraction", "slow_down_layer_time", "standby_temperature_delta", + "preheat_time", + "preheat_steps", "machine_start_gcode", "filament_start_gcode", "change_filament_gcode", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 7856bd6ba6..2b320b331d 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -4079,6 +4079,26 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionInt(-5)); + def = this->add("preheat_time", coFloat); + def->label = L("Preheat time"); + def->tooltip = L("To reduce the waiting time after tool change, Orca can preheat the next tool while the current tool is still in use. " + "This setting specifies the time in seconds to preheat the next tool. Orca will insert a M104 command to preheat the tool in advance."); + def->sidetext = "s"; + def->min = 0; + def->max = 120; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(30.0)); + + def = this->add("preheat_steps", coInt); + def->label = L("Preheat steps"); + def->tooltip = L("Insert multiple preheat commands(e.g. M104.1). Only useful for Prusa XL. For other printers, please set it to 1."); + // def->sidetext = ""; + def->min = 1; + def->max = 10; + def->mode = comDevelop; + def->set_default_value(new ConfigOptionInt(1)); + + def = this->add("machine_start_gcode", coString); def->label = L("Start G-code"); def->tooltip = L("Start G-code when start the whole printing"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 620a24b381..6fc3491862 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1225,6 +1225,8 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionBool, spiral_mode_smooth)) ((ConfigOptionFloatOrPercent, spiral_mode_max_xy_smoothing)) ((ConfigOptionInt, standby_temperature_delta)) + ((ConfigOptionFloat, preheat_time)) + ((ConfigOptionInt, preheat_steps)) ((ConfigOptionInts, nozzle_temperature)) ((ConfigOptionBools, wipe)) // BBS diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 39f8591ec8..ddf34bf7b9 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -667,8 +667,11 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co toggle_field("print_order", !have_sequential_printing); bool have_ooze_prevention = config->opt_bool("ooze_prevention"); - toggle_field("standby_temperature_delta", have_ooze_prevention); - + toggle_line("standby_temperature_delta", have_ooze_prevention); + toggle_line("preheat_time", have_ooze_prevention); + int preheat_steps = config->opt_int("preheat_steps"); + toggle_line("preheat_steps", have_ooze_prevention && (preheat_steps > 0)); + bool have_prime_tower = config->opt_bool("enable_prime_tower"); for (auto el : { "prime_tower_width", "prime_tower_brim_width"}) toggle_line(el, have_prime_tower); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index fab5980700..b7d3e3d5c9 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2299,6 +2299,8 @@ void TabPrint::build() optgroup = page->new_optgroup(L("Ooze prevention")); optgroup->append_single_option_line("ooze_prevention"); optgroup->append_single_option_line("standby_temperature_delta"); + optgroup->append_single_option_line("preheat_time"); + optgroup->append_single_option_line("preheat_steps"); optgroup = page->new_optgroup(L("Flush options"), L"param_flush"); optgroup->append_single_option_line("flush_into_infill", "reduce-wasting-during-filament-change#wipe-into-infill"); From 13ddb38119f7e86b2ff60916e73a80790649815c Mon Sep 17 00:00:00 2001 From: SoftFever Date: Sun, 21 Jul 2024 23:29:06 +0800 Subject: [PATCH 24/32] force restore Z --- src/libslic3r/GCode.cpp | 9 +++++++-- src/libslic3r/GCodeWriter.hpp | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index a2d4516022..f5c27e949c 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -762,8 +762,13 @@ static std::vector get_path_of_change_filament(const Print& print) if (is_ramming) gcodegen.m_wipe.reset_path(); // We don't want wiping on the ramming lines. toolchange_gcode_str = gcodegen.set_extruder(new_extruder_id, tcr.print_z); // TODO: toolchange_z vs print_z - if (gcodegen.config().enable_prime_tower) - deretraction_str = gcodegen.unretract(); + if (gcodegen.config().enable_prime_tower) { + deretraction_str += gcodegen.writer().travel_to_z(z, "restore layer Z"); + Vec3d position{gcodegen.writer().get_position()}; + position.z() = z; + gcodegen.writer().set_position(position); + deretraction_str += gcodegen.unretract(); + } } // Insert the toolchange and deretraction gcode into the generated gcode. diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index df68f549fd..ccdd460fe0 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -82,7 +82,7 @@ public: std::string lift(LiftType lift_type = LiftType::NormalLift, bool spiral_vase = false); std::string unlift(); Vec3d get_position() const { return m_pos; } - void set_position(const Vec3d& in) { m_pos = in; } + void set_position(const Vec3d& in) { m_pos = in; } double get_zhop() const { return m_lifted; } //BBS: set offset for gcode writer From b4cc526ae405db5f8f76c8ef7cda9fc5d6a8cdc7 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Mon, 22 Jul 2024 08:54:01 +0800 Subject: [PATCH 25/32] Fixed an issue that tall skirt is generated when ooze prevention and skirt are both enabled. --- src/libslic3r/Print.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index b4bc6dadab..8292e576ef 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -499,7 +499,10 @@ std::vector Print::print_object_ids() const bool Print::has_infinite_skirt() const { - return (m_config.draft_shield == dsEnabled && m_config.skirt_loops > 0) || (m_config.ooze_prevention && this->extruders().size() > 1); + // Orca: unclear why (m_config.ooze_prevention && this->extruders().size() > 1) logic is here, removed. + // return (m_config.draft_shield == dsEnabled && m_config.skirt_loops > 0) || (m_config.ooze_prevention && this->extruders().size() > 1); + + return (m_config.draft_shield == dsEnabled && m_config.skirt_loops > 0); } bool Print::has_skirt() const From c36d4ad7c94b972b0bef2295c864f450008e91e5 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Tue, 23 Jul 2024 00:12:54 +0800 Subject: [PATCH 26/32] Fix misc bugs --- .../0.20mm Standard @Artillery X3Plus 0.4 nozzle.json | 2 +- .../0.20mm Standard @Artillery X3Pro 0.4 nozzle.json | 2 +- .../0.20mm Standard @Artillery X4Plus 0.4 nozzle.json | 2 +- .../0.20mm Standard @Artillery X4Pro 0.4 nozzle.json | 2 +- .../Comgrow/process/fdm_process_comgrow_common.json | 2 +- .../0.20mm Standard @Flashforge G3U 0.4 Nozzle.json | 2 +- .../FlyingBear/process/S1/fdm_process_common_S1.json | 2 +- .../profiles/FlyingBear/process/fdm_process_common.json | 2 +- .../Ginger Additive/process/fdm_process_common.json | 2 +- .../InfiMech/process/HSN/fdm_process_common_HSN.json | 2 +- .../profiles/InfiMech/process/fdm_process_common.json | 2 +- src/libslic3r/GCode.cpp | 8 +------- src/libslic3r/GCode/ToolOrdering.cpp | 2 +- src/libslic3r/PlaceholderParser.cpp | 2 +- src/libslic3r/Print.cpp | 5 +++-- src/libslic3r/PrintConfig.cpp | 2 +- src/slic3r/GUI/GLCanvas3D.cpp | 2 -- 17 files changed, 18 insertions(+), 25 deletions(-) diff --git a/resources/profiles/Artillery/process/0.20mm Standard @Artillery X3Plus 0.4 nozzle.json b/resources/profiles/Artillery/process/0.20mm Standard @Artillery X3Plus 0.4 nozzle.json index ca2afafa24..cd1de6b7e4 100644 --- a/resources/profiles/Artillery/process/0.20mm Standard @Artillery X3Plus 0.4 nozzle.json +++ b/resources/profiles/Artillery/process/0.20mm Standard @Artillery X3Plus 0.4 nozzle.json @@ -156,7 +156,7 @@ "seam_slope_start_height": "0", "seam_slope_steps": "10", "seam_slope_type": "none", - "single_extruder_multi_material_priming": "1", + "single_extruder_multi_material_priming": "0", "skirt_distance": "2", "skirt_height": "1", "skirt_loops": "0", diff --git a/resources/profiles/Artillery/process/0.20mm Standard @Artillery X3Pro 0.4 nozzle.json b/resources/profiles/Artillery/process/0.20mm Standard @Artillery X3Pro 0.4 nozzle.json index 63c52ab260..bab2091fdd 100644 --- a/resources/profiles/Artillery/process/0.20mm Standard @Artillery X3Pro 0.4 nozzle.json +++ b/resources/profiles/Artillery/process/0.20mm Standard @Artillery X3Pro 0.4 nozzle.json @@ -156,7 +156,7 @@ "seam_slope_start_height": "0", "seam_slope_steps": "10", "seam_slope_type": "none", - "single_extruder_multi_material_priming": "1", + "single_extruder_multi_material_priming": "0", "skirt_distance": "2", "skirt_height": "1", "skirt_loops": "0", diff --git a/resources/profiles/Artillery/process/0.20mm Standard @Artillery X4Plus 0.4 nozzle.json b/resources/profiles/Artillery/process/0.20mm Standard @Artillery X4Plus 0.4 nozzle.json index 6541d48fb2..e72063a41c 100644 --- a/resources/profiles/Artillery/process/0.20mm Standard @Artillery X4Plus 0.4 nozzle.json +++ b/resources/profiles/Artillery/process/0.20mm Standard @Artillery X4Plus 0.4 nozzle.json @@ -156,7 +156,7 @@ "seam_slope_start_height": "0", "seam_slope_steps": "10", "seam_slope_type": "none", - "single_extruder_multi_material_priming": "1", + "single_extruder_multi_material_priming": "0", "skirt_distance": "2", "skirt_height": "1", "skirt_loops": "0", diff --git a/resources/profiles/Artillery/process/0.20mm Standard @Artillery X4Pro 0.4 nozzle.json b/resources/profiles/Artillery/process/0.20mm Standard @Artillery X4Pro 0.4 nozzle.json index 3f2e3ca406..59b4db5f67 100644 --- a/resources/profiles/Artillery/process/0.20mm Standard @Artillery X4Pro 0.4 nozzle.json +++ b/resources/profiles/Artillery/process/0.20mm Standard @Artillery X4Pro 0.4 nozzle.json @@ -156,7 +156,7 @@ "seam_slope_start_height": "0", "seam_slope_steps": "10", "seam_slope_type": "none", - "single_extruder_multi_material_priming": "1", + "single_extruder_multi_material_priming": "0", "skirt_distance": "2", "skirt_height": "1", "skirt_loops": "0", diff --git a/resources/profiles/Comgrow/process/fdm_process_comgrow_common.json b/resources/profiles/Comgrow/process/fdm_process_comgrow_common.json index 8f144ff59a..194e40a196 100644 --- a/resources/profiles/Comgrow/process/fdm_process_comgrow_common.json +++ b/resources/profiles/Comgrow/process/fdm_process_comgrow_common.json @@ -128,7 +128,7 @@ "role_based_wipe_speed": "1", "seam_gap": "5%", "seam_position": "aligned", - "single_extruder_multi_material_priming": "1", + "single_extruder_multi_material_priming": "0", "skirt_distance": "3", "skirt_height": "2", "skirt_loops": "0", diff --git a/resources/profiles/Flashforge/process/0.20mm Standard @Flashforge G3U 0.4 Nozzle.json b/resources/profiles/Flashforge/process/0.20mm Standard @Flashforge G3U 0.4 Nozzle.json index 6995772a4d..15f4fa3add 100644 --- a/resources/profiles/Flashforge/process/0.20mm Standard @Flashforge G3U 0.4 Nozzle.json +++ b/resources/profiles/Flashforge/process/0.20mm Standard @Flashforge G3U 0.4 Nozzle.json @@ -136,7 +136,7 @@ "role_based_wipe_speed": "1", "seam_gap": "10%", "seam_position": "aligned", - "single_extruder_multi_material_priming": "1", + "single_extruder_multi_material_priming": "0", "skirt_distance": "2", "skirt_height": "1", "skirt_loops": "2", diff --git a/resources/profiles/FlyingBear/process/S1/fdm_process_common_S1.json b/resources/profiles/FlyingBear/process/S1/fdm_process_common_S1.json index 43964daced..e116191460 100644 --- a/resources/profiles/FlyingBear/process/S1/fdm_process_common_S1.json +++ b/resources/profiles/FlyingBear/process/S1/fdm_process_common_S1.json @@ -115,7 +115,7 @@ "role_based_wipe_speed": "1", "seam_gap": "10%", "seam_position": "aligned", - "single_extruder_multi_material_priming": "1", + "single_extruder_multi_material_priming": "0", "skirt_distance": "2", "skirt_height": "1", "skirt_loops": "0", diff --git a/resources/profiles/FlyingBear/process/fdm_process_common.json b/resources/profiles/FlyingBear/process/fdm_process_common.json index 6f9e1e1fcb..8e20a992b1 100644 --- a/resources/profiles/FlyingBear/process/fdm_process_common.json +++ b/resources/profiles/FlyingBear/process/fdm_process_common.json @@ -115,7 +115,7 @@ "role_based_wipe_speed": "1", "seam_gap": "10%", "seam_position": "aligned", - "single_extruder_multi_material_priming": "1", + "single_extruder_multi_material_priming": "0", "skirt_distance": "2", "skirt_height": "1", "skirt_loops": "0", diff --git a/resources/profiles/Ginger Additive/process/fdm_process_common.json b/resources/profiles/Ginger Additive/process/fdm_process_common.json index 11b16c1391..81075c236f 100644 --- a/resources/profiles/Ginger Additive/process/fdm_process_common.json +++ b/resources/profiles/Ginger Additive/process/fdm_process_common.json @@ -154,7 +154,7 @@ "seam_slope_start_height": "0", "seam_slope_steps": "10", "seam_slope_type": "external", - "single_extruder_multi_material_priming": "1", + "single_extruder_multi_material_priming": "0", "skirt_distance": "2", "skirt_height": "1", "skirt_loops": "1", diff --git a/resources/profiles/InfiMech/process/HSN/fdm_process_common_HSN.json b/resources/profiles/InfiMech/process/HSN/fdm_process_common_HSN.json index fc457c76d8..2afeaf2cb0 100644 --- a/resources/profiles/InfiMech/process/HSN/fdm_process_common_HSN.json +++ b/resources/profiles/InfiMech/process/HSN/fdm_process_common_HSN.json @@ -114,7 +114,7 @@ "role_based_wipe_speed": "1", "seam_gap": "10%", "seam_position": "aligned", - "single_extruder_multi_material_priming": "1", + "single_extruder_multi_material_priming": "0", "skirt_distance": "2", "skirt_height": "1", "skirt_loops": "0", diff --git a/resources/profiles/InfiMech/process/fdm_process_common.json b/resources/profiles/InfiMech/process/fdm_process_common.json index cb944ca97d..0bb51b5c68 100644 --- a/resources/profiles/InfiMech/process/fdm_process_common.json +++ b/resources/profiles/InfiMech/process/fdm_process_common.json @@ -114,7 +114,7 @@ "role_based_wipe_speed": "1", "seam_gap": "10%", "seam_position": "aligned", - "single_extruder_multi_material_priming": "1", + "single_extruder_multi_material_priming": "0", "skirt_distance": "2", "skirt_height": "1", "skirt_loops": "0", diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index f5c27e949c..535c304389 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2147,7 +2147,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato throw Slic3r::SlicingError(_(L("No object can be printed. Maybe too small"))); has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower(); // Orca: support all extruder priming - initial_extruder_id = (has_wipe_tower && !print.config().single_extruder_multi_material_priming) ? + initial_extruder_id = (!is_bbl_printers && has_wipe_tower && !print.config().single_extruder_multi_material_priming) ? // The priming towers will be skipped. tool_ordering.all_extruders().back() : // Don't skip the priming towers. @@ -6157,13 +6157,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z, bool b std::string toolchange_gcode_parsed; //Orca: Ignore change_filament_gcode if is the first call for a tool change and manual_filament_change is enabled if (!change_filament_gcode.empty() && !(m_config.manual_filament_change.value && m_toolchange_count == 1)) { - dyn_config.set_key_value("previous_extruder", - new ConfigOptionInt((int) (m_writer.extruder() != nullptr ? m_writer.extruder()->id() : -1))); - dyn_config.set_key_value("next_extruder", new ConfigOptionInt((int) extruder_id)); - dyn_config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index)); - dyn_config.set_key_value("layer_z", new ConfigOptionFloat(print_z)); dyn_config.set_key_value("toolchange_z", new ConfigOptionFloat(print_z)); - dyn_config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z)); toolchange_gcode_parsed = placeholder_parser_process("change_filament_gcode", change_filament_gcode, extruder_id, &dyn_config); check_add_eol(toolchange_gcode_parsed); diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index e5c3260084..7f270b69c2 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -875,7 +875,7 @@ void ToolOrdering::reorder_extruders_for_minimum_flush_volume() return false; }; - std::optionalcurrent_extruder_id; + std::optionalcurrent_extruder_id(-1); for (int i = 0; i < m_layer_tools.size(); ++i) { LayerTools& lt = m_layer_tools[i]; if (lt.extruders.empty()) diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index c6e4bc525d..04935ae481 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -1063,7 +1063,7 @@ namespace client case coPercents: output.set_d(static_cast(opt.opt)->values[idx]); break; case coPoints: output.set_s(to_string(static_cast(opt.opt)->values[idx])); break; case coBools: output.set_b(static_cast(opt.opt)->values[idx] != 0); break; - //case coEnums: output.set_s(opt.opt->vserialize()[idx]); break; + case coEnums: output.set_i(static_cast(opt.opt)->values[idx]); break; default: ctx->throw_exception("Unsupported vector variable type", opt.it_range); } diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 8292e576ef..b7b99f7a51 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -2581,6 +2581,7 @@ void Print::_make_wipe_tower() for (unsigned int i = 0; i(flush_matrix.begin()+i*number_of_extruders, flush_matrix.begin()+(i+1)*number_of_extruders)); + const auto bUseWipeTower2 = is_BBL_printer() ? false : true; // Orca: itertate over wipe_volumes and change the non-zero values to the prime_volume if (!m_config.purge_in_prime_tower && !is_BBL_printer()) { for (unsigned int i = 0; i < number_of_extruders; ++i) { @@ -2593,7 +2594,7 @@ void Print::_make_wipe_tower() } // Let the ToolOrdering class know there will be initial priming extrusions at the start of the print. - m_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int)-1, true); + m_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int) -1, bUseWipeTower2 ? true : false); if (!m_wipe_tower_data.tool_ordering.has_wipe_tower()) // Don't generate any wipe tower. @@ -2636,7 +2637,7 @@ void Print::_make_wipe_tower() } this->throw_if_canceled(); - if (is_BBL_printer()) { + if (!bUseWipeTower2) { // in BBL machine, wipe tower is only use to prime extruder. So just use a global wipe volume. WipeTower wipe_tower(m_config, m_plate_index, m_origin, m_config.prime_volume, m_wipe_tower_data.tool_ordering.first_extruder(), m_wipe_tower_data.tool_ordering.empty() ? 0.f : m_wipe_tower_data.tool_ordering.back().print_z); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 2b320b331d..7eea47014a 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -4156,7 +4156,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Prime all printing extruders"); def->tooltip = L("If enabled, all printing extruders will be primed at the front edge of the print bed at the start of the print."); def->mode = comAdvanced; - def->set_default_value(new ConfigOptionBool(true)); + def->set_default_value(new ConfigOptionBool(false)); def = this->add("slice_closing_radius", coFloat); def->label = L("Slice gap closing radius"); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a378f63970..e6d841d102 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -9186,8 +9186,6 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con ctxt.print = print; ctxt.tool_colors = tool_colors.empty() ? nullptr : &tool_colors; - //BBS: has no single_extruder_multi_material_priming - //if (print->wipe_tower_data().priming && print->config().single_extruder_multi_material_priming) if (print->wipe_tower_data().priming) for (int i=0; i<(int)print->wipe_tower_data().priming.get()->size(); ++i) ctxt.priming.emplace_back(print->wipe_tower_data().priming.get()->at(i)); From b0bd16e908605f0fd5613a885faf5ecd1e24a5d9 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Tue, 23 Jul 2024 00:43:12 +0800 Subject: [PATCH 27/32] hide/disable options accordingly --- src/libslic3r/GCode.cpp | 6 +++--- src/slic3r/GUI/ConfigManipulation.cpp | 10 ++++++---- src/slic3r/GUI/Tab.cpp | 14 ++++++++++---- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 535c304389..ec400c1ae6 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2233,7 +2233,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato this->placeholder_parser().set("current_object_idx", 0); // For the start / end G-code to do the priming and final filament pull in case there is no wipe tower provided. this->placeholder_parser().set("has_wipe_tower", has_wipe_tower); - this->placeholder_parser().set("has_single_extruder_multi_material_priming", has_wipe_tower && print.config().single_extruder_multi_material_priming); + this->placeholder_parser().set("has_single_extruder_multi_material_priming", !is_bbl_printers && has_wipe_tower && print.config().single_extruder_multi_material_priming); this->placeholder_parser().set("total_toolchanges", std::max(0, print.wipe_tower_data().number_of_toolchanges)); // Check for negative toolchanges (single extruder mode) and set to 0 (no tool change). this->placeholder_parser().set("num_extruders", int(print.config().nozzle_diameter.values.size())); this->placeholder_parser().set("retract_length", new ConfigOptionFloats(print.config().retraction_length)); @@ -2475,7 +2475,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato } // Orca: support extruder priming - if (! (has_wipe_tower && print.config().single_extruder_multi_material_priming)) + if (is_bbl_printers || ! (has_wipe_tower && print.config().single_extruder_multi_material_priming)) { // Set initial extruder only after custom start G-code. // Ugly hack: Do not set the initial extruder if the extruder is primed using the MMU priming towers at the edge of the print bed. @@ -2606,7 +2606,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato //BBS file.write(m_writer.travel_to_z(initial_layer_print_height + m_config.z_offset.value, "Move to the first layer height")); - if (print.config().single_extruder_multi_material_priming) { + if (!is_bbl_printers && print.config().single_extruder_multi_material_priming) { file.write(m_wipe_tower->prime(*this)); // Verify, whether the print overaps the priming extrusions. BoundingBoxf bbox_print(get_print_extrusions_extents(print)); diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index ddf34bf7b9..a9fd41f8b8 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -665,7 +665,12 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co // for (auto el : { "extruder_clearance_radius", "extruder_clearance_height_to_rod", "extruder_clearance_height_to_lid" }) // toggle_field(el, have_sequential_printing); toggle_field("print_order", !have_sequential_printing); + + toggle_field("single_extruder_multi_material", !is_BBL_Printer); + auto bSEMM = preset_bundle->printers.get_edited_preset().config.opt_bool("single_extruder_multi_material"); + + toggle_field("ooze_prevention", !bSEMM); bool have_ooze_prevention = config->opt_bool("ooze_prevention"); toggle_line("standby_temperature_delta", have_ooze_prevention); toggle_line("preheat_time", have_ooze_prevention); @@ -676,9 +681,6 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co for (auto el : { "prime_tower_width", "prime_tower_brim_width"}) toggle_line(el, have_prime_tower); - auto bSEMM = preset_bundle->printers.get_edited_preset().config.opt_bool("single_extruder_multi_material"); - toggle_field("purge_in_prime_tower", bSEMM); - for (auto el : {"wall_filament", "sparse_infill_filament", "solid_infill_filament", "wipe_tower_filament"}) toggle_line(el, !bSEMM); @@ -689,7 +691,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co "wipe_tower_bridging", "wipe_tower_extra_flow", "wipe_tower_no_sparse_layers", "single_extruder_multi_material_priming"}) - toggle_line(el, have_prime_tower); + toggle_line(el, have_prime_tower && !is_BBL_Printer); toggle_line("prime_volume",have_prime_tower && (!purge_in_primetower || !bSEMM)); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index b7d3e3d5c9..a59803efe7 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -4447,9 +4447,15 @@ void TabPrinter::toggle_options() if (m_active_page->title() == L("Multimaterial")) { // SoftFever: hide specific settings for BBL printer - for (auto el : - {"purge_in_prime_tower", "enable_filament_ramming", "cooling_tube_retraction", "cooling_tube_length", "parking_pos_retraction", "extra_loading_move", "high_current_on_filament_swap", }) - toggle_option(el, !is_BBL_printer); + for (auto el : { + "enable_filament_ramming", + "cooling_tube_retraction", + "cooling_tube_length", + "parking_pos_retraction", + "extra_loading_move", + "high_current_on_filament_swap", + }) + toggle_option(el, !is_BBL_printer); auto bSEMM = m_config->opt_bool("single_extruder_multi_material"); if (!bSEMM && m_config->opt_bool("manual_filament_change")) { @@ -4459,7 +4465,7 @@ void TabPrinter::toggle_options() } toggle_option("extruders_count", !bSEMM); toggle_option("manual_filament_change", bSEMM); - toggle_option("purge_in_prime_tower", bSEMM); + toggle_option("purge_in_prime_tower", bSEMM && !is_BBL_printer); } wxString extruder_number; long val = 1; From f490d2ca9f15ced993164b82ffe8b2992e9ac62e Mon Sep 17 00:00:00 2001 From: SoftFever Date: Tue, 23 Jul 2024 18:18:27 +0800 Subject: [PATCH 28/32] fix flatpak build --- src/libslic3r/GCode/GCodeProcessor.cpp | 8 ++++---- src/libslic3r/PrintBase.hpp | 21 ++++++++++----------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 7506a105d7..70e8a9d91d 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -4943,14 +4943,14 @@ void GCodeProcessor::run_post_process() // found an invalid value, clamp it to a valid one tool_number = std::clamp(0, m_extruder_temps_config.size() - 1, tool_number); // emit warning - std::string warning = _u8L("GCode Post-Processor encountered an invalid toolchange, maybe from a custom gcode:"); + std::string warning = "GCode Post-Processor encountered an invalid toolchange, maybe from a custom gcode:"; warning += "\n> "; warning += gcode_line; - warning += _u8L("Generated M104 lines may be incorrect."); + warning += "Generated M104 lines may be incorrect."; BOOST_LOG_TRIVIAL(error) << warning; // Orca todo - // if (m_print != nullptr) - // m_print->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, warning); + if (m_print != nullptr) + m_print->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, warning); } } export_lines.insert_lines( diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index aecef8a238..b680ac274e 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -583,7 +583,16 @@ public: bool is_step_done(PrintStepEnum step) const { return m_state.is_done(step, this->state_mutex()); } PrintStateBase::StateWithTimeStamp step_state_with_timestamp(PrintStepEnum step) const { return m_state.state_with_timestamp(step, this->state_mutex()); } PrintStateBase::StateWithWarnings step_state_with_warnings(PrintStepEnum step) const { return m_state.state_with_warnings(step, this->state_mutex()); } - + // Add a slicing warning to the active Print step and send a status notification. + // This method could be called multiple times between this->set_started() and this->set_done(). + void active_step_add_warning(PrintStateBase::WarningLevel warning_level, const std::string &message, + PrintStateBase::SlicingNotificationType message_id = PrintStateBase::SlicingDefaultNotification) + { + std::pair active_step = m_state.active_step_add_warning(warning_level, message, (int)message_id, this->state_mutex()); + if (active_step.second) + // Update UI. + this->status_update_warnings(static_cast(active_step.first), warning_level, message, nullptr, message_id); + } protected: bool set_started(PrintStepEnum step) { return m_state.set_started(step, this->state_mutex(), [this](){ this->throw_if_canceled(); }); } PrintStateBase::TimeStamp set_done(PrintStepEnum step) { @@ -605,16 +614,6 @@ protected: bool is_step_started_unguarded(PrintStepEnum step) const { return m_state.is_started_unguarded(step); } bool is_step_done_unguarded(PrintStepEnum step) const { return m_state.is_done_unguarded(step); } - // Add a slicing warning to the active Print step and send a status notification. - // This method could be called multiple times between this->set_started() and this->set_done(). - void active_step_add_warning(PrintStateBase::WarningLevel warning_level, const std::string &message, - PrintStateBase::SlicingNotificationType message_id = PrintStateBase::SlicingDefaultNotification) - { - std::pair active_step = m_state.active_step_add_warning(warning_level, message, (int)message_id, this->state_mutex()); - if (active_step.second) - // Update UI. - this->status_update_warnings(static_cast(active_step.first), warning_level, message, nullptr, message_id); - } private: PrintState m_state; From 6d7071bf2dc8782b4c48c77a5864d582bdc7b7f7 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Wed, 24 Jul 2024 19:58:34 +0800 Subject: [PATCH 29/32] add "temperature" variable support --- src/libslic3r/GCode.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index ec400c1ae6..3d54ffe0cc 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2221,9 +2221,11 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato this->placeholder_parser().set("initial_no_support_tool", initial_non_support_extruder_id); this->placeholder_parser().set("initial_no_support_extruder", initial_non_support_extruder_id); this->placeholder_parser().set("current_extruder", initial_extruder_id); - //set the key for compatibilty + //Orca: set the key for compatibilty this->placeholder_parser().set("retraction_distance_when_cut", m_config.retraction_distances_when_cut.get_at(initial_extruder_id)); this->placeholder_parser().set("long_retraction_when_cut", m_config.long_retractions_when_cut.get_at(initial_extruder_id)); + this->placeholder_parser().set("temperature", new ConfigOptionInts(print.config().nozzle_temperature)); + this->placeholder_parser().set("retraction_distances_when_cut", new ConfigOptionFloats(m_config.retraction_distances_when_cut)); this->placeholder_parser().set("long_retractions_when_cut",new ConfigOptionBools(m_config.long_retractions_when_cut)); From 37b955082cc6d6ccd38628026a41548fc7f02280 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Wed, 24 Jul 2024 19:59:23 +0800 Subject: [PATCH 30/32] update "change_filament_gcode" for Prusa XL, fix extra tool park issue after final purge --- resources/profiles/Prusa.json | 2 +- resources/profiles/Prusa/machine/fdm_machine_common_xl_5t.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/profiles/Prusa.json b/resources/profiles/Prusa.json index b6b8322c6d..b9a7435e4b 100644 --- a/resources/profiles/Prusa.json +++ b/resources/profiles/Prusa.json @@ -1,6 +1,6 @@ { "name": "Prusa", - "version": "02.01.02.30", + "version": "02.01.02.40", "force_update": "0", "description": "Prusa configurations", "machine_model_list": [ diff --git a/resources/profiles/Prusa/machine/fdm_machine_common_xl_5t.json b/resources/profiles/Prusa/machine/fdm_machine_common_xl_5t.json index eedd38b152..7bdc573b39 100644 --- a/resources/profiles/Prusa/machine/fdm_machine_common_xl_5t.json +++ b/resources/profiles/Prusa/machine/fdm_machine_common_xl_5t.json @@ -14,7 +14,7 @@ "machine_pause_gcode": "M601", "machine_start_gcode": "M17 ; enable steppers\nM862.3 P \"XL\" ; printer model check\nM862.5 P2 ; g-code level check\nM862.6 P\"Input shaper\" ; FW feature check\nM115 U6.0.3+14902\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\n; set print area\nM555 X{first_layer_print_min[0]} Y{first_layer_print_min[1]} W{(first_layer_print_max[0]) - (first_layer_print_min[0])} H{(first_layer_print_max[1]) - (first_layer_print_min[1])}\n; inform about nozzle diameter\n{if (is_extruder_used[0])}M862.1 T0 P{nozzle_diameter[0]}{endif}\n{if (is_extruder_used[1])}M862.1 T1 P{nozzle_diameter[1]}{endif}\n{if (is_extruder_used[2])}M862.1 T2 P{nozzle_diameter[2]}{endif}\n{if (is_extruder_used[3])}M862.1 T3 P{nozzle_diameter[3]}{endif}\n{if (is_extruder_used[4])}M862.1 T4 P{nozzle_diameter[4]}{endif}\n\n; turn off unused heaters\n{if ! is_extruder_used[0]} M104 T0 S0 {endif}\n{if ! is_extruder_used[1]} M104 T1 S0 {endif}\n{if num_extruders > 2 and ! is_extruder_used[2]} M104 T2 S0 {endif}\n{if num_extruders > 3 and ! is_extruder_used[3]} M104 T3 S0 {endif}\n{if num_extruders > 4 and ! is_extruder_used[4]} M104 T4 S0 {endif}\n\nM217 Z{max(zhop, 2.0)} ; set toolchange z hop to 2mm, or zhop variable from slicer if higher\n; set bed and extruder temp for MBL\nM140 S[first_layer_bed_temperature] ; set bed temp\nG0 Z5 ; add Z clearance\nM109 T{initial_tool} S{((filament_notes[initial_tool]=~/.*HT_MBL10.*/) ? (first_layer_temperature[initial_tool] - 10) : (filament_type[initial_tool] == \"PC\" or filament_type[initial_tool] == \"PA\") ? (first_layer_temperature[initial_tool] - 25) : (filament_type[initial_tool] == \"FLEX\") ? 210 : (filament_type[initial_tool]=~/.*PET.*/) ? 175 : 170)} ; wait for temp\n\n; Home XY\nG28 XY\n; try picking tools used in print\nG1 F{travel_speed * 60}\n{if (is_extruder_used[0]) and (initial_tool != 0)}T0 S1 L0 D0{endif}\n{if (is_extruder_used[1]) and (initial_tool != 1)}T1 S1 L0 D0{endif}\n{if (is_extruder_used[2]) and (initial_tool != 2)}T2 S1 L0 D0{endif}\n{if (is_extruder_used[3]) and (initial_tool != 3)}T3 S1 L0 D0{endif}\n{if (is_extruder_used[4]) and (initial_tool != 4)}T4 S1 L0 D0{endif}\n; select tool that will be used to home & MBL\nT{initial_tool} S1 L0 D0\n; home Z with MBL tool\nM84 E ; turn off E motor\nG28 Z\nG0 Z5 ; add Z clearance\n\nM104 T{initial_tool} S{if idle_temperature[initial_tool] == 0}70{else}{idle_temperature[initial_tool]}{endif} ; set idle temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\n\nG29 G ; absorb heat\n\nM109 T{initial_tool} S{((filament_notes[initial_tool]=~/.*HT_MBL10.*/) ? (first_layer_temperature[initial_tool] - 10) : (filament_type[initial_tool] == \"PC\" or filament_type[initial_tool] == \"PA\") ? (first_layer_temperature[initial_tool] - 25) : (filament_type[initial_tool] == \"FLEX\") ? 210 : (filament_type[initial_tool]=~/.*PET.*/) ? 175 : 170)} ; wait for temp\n\n; move to the nozzle cleanup area\nG1 X{(min(((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32))), first_layer_print_min[0])) + 32} Y{(min((first_layer_print_min[1] - 7), first_layer_print_min[1]))} Z{5} F{(travel_speed * 60)}\nM302 S160 ; lower cold extrusion limit to 160C\nG1 E{-(filament_type[0] == \"FLEX\" ? 4 : 2)} F2400 ; retraction for nozzle cleanup\n; nozzle cleanup\nM84 E ; turn off E motor\nG29 P9 X{((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)))} Y{(first_layer_print_min[1] - 7)} W{32} H{7}\nG0 Z5 F480 ; move away in Z\nM107 ; turn off the fan\n; MBL\nM84 E ; turn off E motor\nG29 P1 ; invalidate mbl & probe print area\nG29 P1 X30 Y0 W{(((is_extruder_used[4]) or ((is_extruder_used[3]) or (is_extruder_used[2]))) ? \"300\" : ((is_extruder_used[1]) ? \"130\" : \"50\"))} H20 C ; probe near purge place\nG29 P3.2 ; interpolate mbl probes\nG29 P3.13 ; extrapolate mbl outside probe area\nG29 A ; activate mbl\nG1 Z10 F720 ; move away in Z\nG1 F{travel_speed * 60}\nP0 S1 L1 D0; park the tool\n; set extruder temp\n{if first_layer_temperature[0] > 0 and (is_extruder_used[0])}M104 T0 S{first_layer_temperature[0]}{endif}\n{if first_layer_temperature[1] > 0 and (is_extruder_used[1])}M104 T1 S{first_layer_temperature[1]}{endif}\n{if first_layer_temperature[2] > 0 and (is_extruder_used[2])}M104 T2 S{first_layer_temperature[2]}{endif}\n{if first_layer_temperature[3] > 0 and (is_extruder_used[3])}M104 T3 S{first_layer_temperature[3]}{endif}\n{if first_layer_temperature[4] > 0 and (is_extruder_used[4])}M104 T4 S{first_layer_temperature[4]}{endif}\n{if (is_extruder_used[0]) and initial_tool != 0}\n;\n; purge first tool\n;\nG1 F{travel_speed * 60}\nP0 S1 L2 D0; park the tool\nM109 T0 S{first_layer_temperature[0]}\nT0 S1 L0 D0; pick the tool\nG92 E0 ; reset extruder position\n\nG0 X{(0 == 0 ? 30 : (0 == 1 ? 150 : (0 == 2 ? 210 : 330)))} Y{(0 < 4 ? -7 : -4.5)} Z10 F{(travel_speed * 60)} ; move close to the sheet's edge\nG0 E{if filament_multitool_ramming[0]}10{else}30{endif} X40 Z0.2 F{if filament_multitool_ramming[0]}500{else}170{endif} ; purge while moving towards the sheet\nG0 X70 E9 F800 ; continue purging and wipe the nozzle\nG0 X{70 + 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{70 + 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG1 E{- 1.5 * retract_length[0]} F2400 ; retract\n{e_retracted[0] = 1.5 * retract_length[0]} ; update slicer internal retract variable\nG92 E0 ; reset extruder position\n\nM104 S{(idle_temperature[0] == 0 ? (first_layer_temperature[0] + standby_temperature_delta) : (idle_temperature[0]))} T0\n{endif}\n{if (is_extruder_used[1]) and initial_tool != 1}\n;\n; purge second tool\n;\nG1 F{travel_speed * 60}\nP0 S1 L2 D0; park the tool\nM109 T1 S{first_layer_temperature[1]}\nT1 S1 L0 D0; pick the tool\nG92 E0 ; reset extruder position\n\nG0 X{(1 == 0 ? 30 : (1 == 1 ? 150 : (1 == 2 ? 210 : 330)))} Y{(1 < 4 ? -7 : -4.5)} Z10 F{(travel_speed * 60)} ; move close to the sheet's edge\nG0 E{if filament_multitool_ramming[1]}10{else}30{endif} X140 Z0.2 F{if filament_multitool_ramming[1]}500{else}170{endif} ; purge while moving towards the sheet\nG0 X110 E9 F800 ; continue purging and wipe the nozzle\nG0 X{110 - 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{110 - 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG1 E{- 1.5 * retract_length[1]} F2400 ; retract\n{e_retracted[1] = 1.5 * retract_length[1]} ; update slicer internal retract variable\nG92 E0 ; reset extruder position\n\nM104 S{(idle_temperature[1] == 0 ? (first_layer_temperature[1] + standby_temperature_delta) : (idle_temperature[1]))} T1\n{endif}\n{if (is_extruder_used[2]) and initial_tool != 2}\n;\n; purge third tool\n;\nG1 F{travel_speed * 60}\nP0 S1 L2 D0; park the tool\nM109 T2 S{first_layer_temperature[2]}\nT2 S1 L0 D0; pick the tool\nG92 E0 ; reset extruder position\n\nG0 X{(2 == 0 ? 30 : (2 == 1 ? 150 : (2 == 2 ? 210 : 330)))} Y{(2 < 4 ? -7 : -4.5)} Z10 F{(travel_speed * 60)} ; move close to the sheet's edge\nG0 E{if filament_multitool_ramming[2]}10{else}30{endif} X220 Z0.2 F{if filament_multitool_ramming[2]}500{else}170{endif} ; purge while moving towards the sheet\nG0 X250 E9 F800 ; continue purging and wipe the nozzle\nG0 X{250 + 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{250 + 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG1 E{- 1.5 * retract_length[2]} F2400 ; retract\n{e_retracted[2] = 1.5 * retract_length[2]} ; update slicer internal retract variable\nG92 E0 ; reset extruder position\n\nM104 S{(idle_temperature[2] == 0 ? (first_layer_temperature[2] + standby_temperature_delta) : (idle_temperature[2]))} T2\n{endif}\n{if (is_extruder_used[3]) and initial_tool != 3}\n;\n; purge fourth tool\n;\nG1 F{travel_speed * 60}\nP0 S1 L2 D0; park the tool\nM109 T3 S{first_layer_temperature[3]}\nT3 S1 L0 D0; pick the tool\nG92 E0 ; reset extruder position\n\nG0 X{(3 == 0 ? 30 : (3 == 1 ? 150 : (3 == 2 ? 210 : 330)))} Y{(3 < 4 ? -7 : -4.5)} Z10 F{(travel_speed * 60)} ; move close to the sheet's edge\nG0 E{if filament_multitool_ramming[3]}10{else}30{endif} X320 Z0.2 F{if filament_multitool_ramming[3]}500{else}170{endif} ; purge while moving towards the sheet\nG0 X290 E9 F800 ; continue purging and wipe the nozzle\nG0 X{290 - 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{290 - 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG1 E{- 1.5 * retract_length[3]} F2400 ; retract\n{e_retracted[3] = 1.5 * retract_length[3]} ; update slicer internal retract variable\nG92 E0 ; reset extruder position\n\nM104 S{(idle_temperature[3] == 0 ? (first_layer_temperature[3] + standby_temperature_delta) : (idle_temperature[3]))} T3\n{endif}\n{if (is_extruder_used[4]) and initial_tool != 4}\n;\n; purge fifth tool\n;\nG1 F{travel_speed * 60}\nP0 S1 L2 D0; park the tool\nM109 T4 S{first_layer_temperature[4]}\nT4 S1 L0 D0; pick the tool\nG92 E0 ; reset extruder position\n\nG0 X{(4 == 0 ? 30 : (4 == 1 ? 150 : (4 == 2 ? 210 : 330)))} Y{(4 < 4 ? -7 : -4.5)} Z10 F{(travel_speed * 60)} ; move close to the sheet's edge\nG0 E{if filament_multitool_ramming[4]}10{else}30{endif} X320 Z0.2 F{if filament_multitool_ramming[4]}500{else}170{endif} ; purge while moving towards the sheet\nG0 X290 E9 F800 ; continue purging and wipe the nozzle\nG0 X{290 - 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{290 - 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG1 E{- 1.5 * retract_length[4]} F2400 ; retract\n{e_retracted[4] = 1.5 * retract_length[4]} ; update slicer internal retract variable\nG92 E0 ; reset extruder position\n\nM104 S{(idle_temperature[4] == 0 ? (first_layer_temperature[4] + standby_temperature_delta) : (idle_temperature[4]))} T4\n{endif}\n;\n; purge initial tool\n;\nG1 F{travel_speed * 60}\nP0 S1 L2 D0; park the tool\nM109 T{initial_tool} S{first_layer_temperature[initial_tool]}\nT{initial_tool} S1 L0 D0; pick the tool\nG92 E0 ; reset extruder position\n\nG0 X{(initial_tool == 0 ? 30 : (initial_tool == 1 ? 150 : (initial_tool == 2 ? 210 : 330)))} Y{(initial_tool < 4 ? -7 : -4.5)} Z10 F{(travel_speed * 60)} ; move close to the sheet's edge\nG0 E{if filament_multitool_ramming[initial_tool]}10{else}30{endif} X{(initial_tool == 0 ? 30 : (initial_tool == 1 ? 150 : (initial_tool == 2 ? 210 : 330))) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 10)} Z0.2 F{if filament_multitool_ramming[initial_tool]}500{else}170{endif} ; purge while moving towards the sheet\nG0 X{(initial_tool == 0 ? 30 : (initial_tool == 1 ? 150 : (initial_tool == 2 ? 210 : 330))) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 40)} E9 F800 ; continue purging and wipe the nozzle\nG0 X{(initial_tool == 0 ? 30 : (initial_tool == 1 ? 150 : (initial_tool == 2 ? 210 : 330))) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 40) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 3)} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{(initial_tool == 0 ? 30 : (initial_tool == 1 ? 150 : (initial_tool == 2 ? 210 : 330))) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 40) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 3 * 2)} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG1 E{- 1.5 * retract_length[initial_tool]} F2400 ; retract\n{e_retracted[initial_tool] = 1.5 * retract_length[initial_tool]}\nG92 E0 ; reset extruder position\n", "machine_end_gcode": "G4 ; wait\n\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+5, max_print_height)}{endif} ; Move bed down\n\nP0 S1 ; park tool\n\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+97, max_print_height)} F300{endif} ; Move bed further down\n\n; turn off extruder heaters\n{if is_extruder_used[0]} M104 T0 S0 {endif}\n{if is_extruder_used[1]} M104 T1 S0 {endif}\n{if is_extruder_used[2]} M104 T2 S0 {endif}\n{if is_extruder_used[3]} M104 T3 S0 {endif}\n{if is_extruder_used[4]} M104 T4 S0 {endif}\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM221 S100 ; reset flow percentage\nM84 ; disable motors\nM77 ; stop print timer\n; max_layer_z = [max_layer_z]", - "change_filament_gcode": "; Change Tool[previous_extruder] -> Tool[next_extruder] (layer [layer_num])\n{\nposition[2] = position[2] + 2.0;\n}\n{if travel_speed > 350.0}\nG1 F{350.0 * 60} \n{else}\nG1 F{travel_speed * 60} \n{endif}\nP0 S1 L2 D0\n; [layer_num]\n{if layer_num == 0}\nM109 S{first_layer_temperature[next_extruder]} T[next_extruder]\n{else}\nM109 S{nozzle_temperature[next_extruder]} T[next_extruder]\n{endif}\nT[next_extruder] S1 L0 D0\n", + "change_filament_gcode": "; Change Tool[previous_extruder] -> Tool[next_extruder] (layer [layer_num])\n{\nlocal max_speed_toolchange = 350.0;\nlocal wait_for_extruder_temp = true;\nposition[2] = position[2] + 2.0;\n\nlocal speed_toolchange = max_speed_toolchange;\nif travel_speed < max_speed_toolchange then\n speed_toolchange = travel_speed;\nendif\n\"G1 F\" + (speed_toolchange * 60) + \"\n\";\nif wait_for_extruder_temp and not((layer_num < 0) and (next_extruder == initial_tool)) then\n \"P0 S1 L2 D0\n\";\n \"; \" + layer_num + \"\n\";\n if layer_num == 0 then\n \"M109 S\" + first_layer_temperature[next_extruder] + \" T\" + next_extruder + \"\n\";\n else\n \"M109 S\" + temperature[next_extruder] + \" T\" + next_extruder + \"\n\";\n endif\nendif\n\"T\" + next_extruder + \" S1 L0 D0\n\";\n}", "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\nG92 E0.0\n;[layer_z]\n", "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", From 99c7b856fe53bfb78459cea29a6feb01cea959bd Mon Sep 17 00:00:00 2001 From: SoftFever Date: Mon, 29 Jul 2024 23:12:47 +0800 Subject: [PATCH 31/32] fix build error --- src/libslic3r/Print.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 3ca8bd020f..c6417e700c 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -2044,7 +2044,6 @@ void Print::process(long long *time_cost_with_cache, bool use_cache) //BBS: get the objects' indices when GCodes are generated ToolOrdering tool_ordering; unsigned int initial_extruder_id = (unsigned int)-1; - unsigned int final_extruder_id = (unsigned int)-1; bool has_wipe_tower = false; std::vector print_object_instances_ordering; std::vector::const_iterator print_object_instance_sequential_active; @@ -2752,7 +2751,7 @@ void Print::_make_wipe_tower() for (auto &layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) { // for all layers if (!layer_tools.has_wipe_tower) continue; - // bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front(); + bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front(); wipe_tower.plan_toolchange((float) layer_tools.print_z, (float) layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id, false); for (const auto extruder_id : layer_tools.extruders) { From f83dd4f0a7ad0591df92763c629c57809f49c142 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Mon, 29 Jul 2024 23:19:28 +0800 Subject: [PATCH 32/32] fix flatpak --- src/libslic3r/Fill/FillCrossHatch.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libslic3r/Fill/FillCrossHatch.cpp b/src/libslic3r/Fill/FillCrossHatch.cpp index a6f05b65d5..7b9f96fa78 100644 --- a/src/libslic3r/Fill/FillCrossHatch.cpp +++ b/src/libslic3r/Fill/FillCrossHatch.cpp @@ -1,3 +1,4 @@ +#include "../ClipperUtils.hpp" #include "../ShortestPath.hpp" #include