diff --git a/CMakeLists.txt b/CMakeLists.txt index f2fe7fd414..162763621c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -346,7 +346,7 @@ if(WIN32) if (DEFINED ENV{WindowsSdkDir} AND DEFINED ENV{WindowsSDKVersion}) set(WIN10SDK_INCLUDE_PATH "$ENV{WindowsSdkDir}/Include/$ENV{WindowsSDKVersion}") else () - set(WIN10SDK_INCLUDE_PATH "C:/Program Files (x86)/Windows Kits/10/Include/10.0.22000.0") + set(WIN10SDK_INCLUDE_PATH "C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0") endif () if (NOT EXISTS "${WIN10SDK_INCLUDE_PATH}/winrt/windows.graphics.printing3d.h") message("${WIN10SDK_INCLUDE_PATH}/winrt/windows.graphics.printing3d.h was not found") diff --git a/README.md b/README.md index b70b7cc431..59fb76034b 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ If you come across any of these in search results, please report them as Use varied infill [patterns](https://github.com/OrcaSlicer/OrcaSlicer/wiki/strength_settings_patterns) and accurate hole shapes for improved clarity. - **[Overhang](https://github.com/OrcaSlicer/OrcaSlicer/wiki/quality_settings_overhangs) and [Support Optimization](https://github.com/OrcaSlicer/OrcaSlicer/wiki#support-settings)** Modify geometry for printable overhangs with precise support placement. -- **[Granular Controls](https://github.com/OrcaSlicer/OrcaSlicer/wiki#process-settings and Customization)** +- **[Granular Controls and Customization](https://github.com/OrcaSlicer/OrcaSlicer/wiki#process-settings)** Fine-tune print speed, layer height, pressure, and temperature with precision. - **Network Printer Support** Seamless integration with Klipper, PrusaLink, and OctoPrint for remote control. diff --git a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po index d52a68ee1b..73fcdb50ea 100644 --- a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po +++ b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po @@ -2057,7 +2057,7 @@ msgid "Replace the selected part with new STL" msgstr "Substituir a peça selecionada por novo STL" msgid "Replace all with STL" -msgstr "" +msgstr "Substituir tudo por STL" msgid "Replace all selected parts with STL from folder" msgstr "Substituir todas peças selecionadas com STL da pasta" @@ -3406,7 +3406,7 @@ msgid "Step" msgstr "Passo" msgid "Unmapped" -msgstr "" +msgstr "Não mapeado" msgid "" "Upper half area: Original\n" @@ -4267,7 +4267,7 @@ msgid "Auto Check: Material" msgstr "Verificação Automática: Material" msgid "Live View Camera Calibration" -msgstr "" +msgstr "Calibração da Câmera ao Vivo" msgid "Waiting for heatbed to reach target temperature" msgstr "Aguardando mesa aquecida atingir a temperatura desejada" @@ -6785,7 +6785,7 @@ msgid "Monitor if the waste is piled up in the purge chute." msgstr "Verifique se os resíduos estão se acumulando na calha de purga." msgid "Nozzle Clumping Detection" -msgstr "Detecção de acúmulo no bico" +msgstr "Detecção de Aglomeração no Bico" msgid "Check if the nozzle is clumping by filaments or other foreign objects." msgstr "" @@ -8037,10 +8037,12 @@ msgid "All" msgstr "Todos" msgid "Auto flush after changing..." -msgstr "" +msgstr "Auto purga depois da troca..." msgid "Auto calculate flushing volumes when selected values changed" msgstr "" +"Calcula automaticamente os volumes de purga quando os valores selecionados " +"são alterados" msgid "Auto arrange plate after cloning" msgstr "Organizar automaticamente a placa após a clonagem" @@ -8100,7 +8102,7 @@ msgid "If enabled, reverses the direction of zoom with mouse wheel." msgstr "Se ativo, inverte a direção de zoom com a roda do mouse." msgid "Clear my choice on..." -msgstr "" +msgstr "Limpar minha escolha em..." msgid "Unsaved projects" msgstr "Projetos não salvos" @@ -8158,7 +8160,7 @@ msgid "Update built-in Presets automatically." msgstr "Atualizar automaticamente Predefinições integradas." msgid "Network plugin" -msgstr "" +msgstr "Plugin de rede" msgid "Enable network plugin" msgstr "Ativar plugin de rede" @@ -8882,15 +8884,20 @@ msgid "" "You have selected both external and AMS filaments for an extruder. You will " "need to manually switch the external filament during printing." msgstr "" +"Você selecionou filamentos externos e AMS para uma extrusora. Será " +"necessário trocar manualmente o filamento externo durante a impressão." msgid "" "TPU 90A/TPU 85A is too soft and does not support automatic Flow Dynamics " "calibration." -msgstr "" +msgstr "TPU 90A/TPU 85A é muito mole e não suporta calibração automática de " +"Dinâmica de Fluxo." msgid "" "Set dynamic flow calibration to 'OFF' to enable custom dynamic flow value." msgstr "" +"Desative a calibração de fluxo dinâmico para habilitar o valor de fluxo " +"dinâmico personalizado." msgid "This printer does not support printing all plates." msgstr "Esta impressora não suporta a imprimir todas as placas." @@ -8899,6 +8906,9 @@ msgid "" "Please cold pull before printing TPU to avoid clogging. You may use cold " "pull maintenance on the printer." msgstr "" +"Recomenda-se realizar um processo de 'cold pull' antes de imprimir em TPU " +"para evitar entupimentos. Você pode utilizar esse processo de manutenção na " +"impressora." msgid "High chamber temperature is required. Please close the door." msgstr "É necessária uma temperatura elevada na câmara. Feche a porta." @@ -8916,8 +8926,9 @@ msgid "click to retry" msgstr "clique para tentar novamente" msgid "Upload file timeout, please check if the firmware version supports it." -msgstr "Limite de tempo de envio exedido, verifique se a versão do firmware " -"tem suporte." +msgstr "" +"Limite de tempo de envio de arquivo excedido, verifique se a versão do " +"firmware tem suporte." msgid "" "No available external storage was obtained. Please confirm and try again." @@ -8936,6 +8947,8 @@ msgid "" "Please check the network and try again, You can restart or update the " "printer if the issue persists." msgstr "" +"Verifique a rede e tente novamente. Se o problema persistir, você pode " +"reiniciar ou atualizar a impressora." msgid "Sending..." msgstr "Enviando…" @@ -8952,7 +8965,7 @@ msgid "Sending failed, please try again!" msgstr "Falha no envio, tente novamente!" msgid "Connection failed. Click the icon to retry" -msgstr "" +msgstr "Falha na coexão. Clique no icon para tentar novamente" msgid "Cannot send the print task when the upgrade is in progress" msgstr "" @@ -9653,7 +9666,7 @@ msgid "Wipe tower parameters" msgstr "Parâmetros da torre de limpeza" msgid "Multi Filament" -msgstr "" +msgstr "Multi Filamento" msgid "Tool change parameters with single extruder MM printers" msgstr "" @@ -9723,7 +9736,7 @@ msgid "Timelapse G-code" msgstr "G-code de timelapse" msgid "Clumping Detection G-code" -msgstr "" +msgstr "G-code para detecção de aglomeração" msgid "Change filament G-code" msgstr "G-code de mudança de filamento" @@ -9862,11 +9875,11 @@ msgstr "Tem certeza de %1% a predefinição selecionada?" #, c-format, boost-format msgid "Left: %s" -msgstr "" +msgstr "Esquerda: %s" #, c-format, boost-format msgid "Right: %s" -msgstr "" +msgstr "Direita: %s" msgid "Click to reset current value and attach to the global value." msgstr "Clique para redefinir o valor atual e anexá-lo ao valor global." @@ -10102,25 +10115,25 @@ msgid "The configuration is up to date." msgstr "A configuração está atualizada." msgid "Open Wiki for more information >" -msgstr "" +msgstr "Abra o Wiki para mais informações >" msgid "OBJ file import color" msgstr "Importar cor de arquivo Obj" msgid "Some faces don't have color defined." -msgstr "" +msgstr "Algumas faces não têm a cor definida." msgid "MTL file exist error, could not find the material:" msgstr "" msgid "Please check OBJ or MTL file." -msgstr "" +msgstr "Verifique o arquivo OBJ ou MTL." msgid "Specify number of colors:" msgstr "Especifique a quantidade de cores:" msgid "Enter or click the adjustment button to modify number again" -msgstr "" +msgstr "Digite ou clique no botão de ajuste para modificar o número novamente" msgid "Recommended " msgstr "Recomendado " @@ -10129,10 +10142,10 @@ msgid "view" msgstr "" msgid "Current filament colors" -msgstr "" +msgstr "Cores de filamento atuais" msgid "Matching" -msgstr "" +msgstr "Correspondendo" msgid "Quick set" msgstr "" @@ -10147,7 +10160,7 @@ msgid "Append" msgstr "Adicionar" msgid "Append to existing filaments" -msgstr "" +msgstr "Adicionar aos filamentos existentes" msgid "Reset mapped extruders." msgstr "Redefinir extrusoras mapeadas." @@ -10389,6 +10402,9 @@ msgid "" "changed or filaments changed. You could disable the auto-calculate in Orca " "Slicer > Preferences" msgstr "" +"O Orca recalculará seus volumes de purga toda vez que a cor dos filamentos " +"ou os filamentos forem alterados. Você pode desativar o cálculo automático " +"em OrcaSlicer > Preferências" msgid "Flushing volume (mm³) for each filament pair." msgstr "Volume de purga (mm³) para cada par de filamentos." @@ -10405,10 +10421,10 @@ msgid "Re-calculate" msgstr "Recalcular" msgid "Left extruder" -msgstr "" +msgstr "Extrusora esquerda" msgid "Right extruder" -msgstr "" +msgstr "Extrusora direita" msgid "Multiplier" msgstr "Multiplicador" @@ -10417,7 +10433,7 @@ msgid "Flushing volumes for filament change" msgstr "Volumes de purga para troca de filamento" msgid "Please choose the filament colour" -msgstr "" +msgstr "Escolha a cor do filamento" msgid "" "Windows Media Player is required for this task! Do you want to enable " @@ -10732,19 +10748,27 @@ msgid "" "Try the following methods to update the connection parameters and reconnect " "to the printer." msgstr "" +"Tente os seguintes métodos para atualizar os parâmetros de conexão e " +"reconectar à impressora." msgid "1. Please confirm Orca Slicer and your printer are in the same LAN." msgstr "" +"1. Confirme se o Orca Slicer e sua impressora estão na mesma rede local." msgid "" "2. If the IP and Access Code below are different from the actual values on " "your printer, please correct them." msgstr "" +"2. Se o IP e o Código de Acesso abaixo forem diferentes dos valores reais da " +"sua impressora, corrija-os." msgid "" "3. Please obtain the device SN from the printer side; it is usually found in " "the device information on the printer screen." msgstr "" +"3. Obtenha o número de série (SN) do dispositivo na própria impressora; " +"geralmente ele pode ser encontrado nas informações do dispositivo na tela da " +"impressora." msgid "IP" msgstr "IP" @@ -10800,7 +10824,7 @@ msgstr "" "por favor passe para o passo 3 para resolver problemas de rede" msgid "Connection failed! Please refer to the wiki page." -msgstr "" +msgstr "Falha na conexão! Consulte a página da wiki." msgid "sending failed" msgstr "falha no envio" @@ -10809,9 +10833,11 @@ msgid "" "Failed to send. Click Retry to attempt sending again. If retrying does not " "work, please check the reason." msgstr "" +"Falha ao enviar. Clique em Tentar Novamente para tentar enviar de novo. Se " +"tentar novamente não funcionar, verifique o motivo." msgid "reconnect" -msgstr "" +msgstr "reconectar" msgid "Air Pump" msgstr "Bomba de Ar" @@ -10826,7 +10852,7 @@ msgid "Cutting Module" msgstr "Módulo de Corte" msgid "Auto Fire Extinguishing System" -msgstr "" +msgstr "Sistema Automático de Extinção de Incêndio" msgid "Model:" msgstr "Modelo:" @@ -10988,13 +11014,13 @@ msgid "Generating G-code: layer %1%" msgstr "Gerando G-code: camada %1%" msgid "Flush volumes matrix do not match to the correct size!" -msgstr "" +msgstr "A matriz de volumes de descarga não corresponde ao tamanho correto!" msgid "Grouping error: " -msgstr "" +msgstr "Erro de agrupamento: " msgid " can not be placed in the " -msgstr "" +msgstr " não pode ser colocado na " msgid "Inner wall" msgstr "Parede interna" @@ -11162,6 +11188,8 @@ msgid "" " is too close to clumping detection area, there may be collisions when " "printing." msgstr "" +" está muito perto da área de detecção de aglomeração, podendo haver colisões " +"durante a impressão." msgid "Prime Tower" msgstr "Torre de Preparo" @@ -11175,32 +11203,44 @@ msgstr " está muito perto da área de exclusão, e ocorrerão colisões.\n" msgid "" " is too close to clumping detection area, and collisions will be caused.\n" msgstr "" +" está muito perto da área de detecção de aglomeração, e ocorrerão colisões.\n" msgid "" "Printing high-temp and low-temp filaments together may cause nozzle clogging " "or printer damage." msgstr "" +"A impressão simultânea de filamentos de alta e baixa temperatura pode causar " +"entupimento do bico ou danos à impressora." msgid "" "Printing high-temp and low-temp filaments together may cause nozzle clogging " "or printer damage. If you still want to print, you can enable the option in " "Preferences." msgstr "" +"A impressão simultânea de filamentos de alta e baixa temperatura pode causar " +"entupimento do bico ou danos à impressora. Se ainda assim desejar imprimir, " +"você pode ativar a opção em Preferências." msgid "" "Printing different-temp filaments together may cause nozzle clogging or " "printer damage." msgstr "" +"Imprimir filamentos com temperaturas diferentes simultaneamente pode causar " +"entupimento dos bicos ou danos à impressora." msgid "" "Printing high-temp and mid-temp filaments together may cause nozzle clogging " "or printer damage." msgstr "" +"A impressão simultânea de filamentos de alta e média temperatura pode causar " +"entupimento do bico ou danos à impressora." msgid "" "Printing mid-temp and low-temp filaments together may cause nozzle clogging " "or printer damage." msgstr "" +"A impressão simultânea de filamentos de temperatura média e baixa pode causar " +"entupimento do bico ou danos à impressora." msgid "No extrusions under current settings." msgstr "Nenhuma extrusão com as configurações atuais." @@ -11215,6 +11255,8 @@ msgstr "" msgid "" "Clumping detection is not supported when \"by object\" sequence is enabled." msgstr "" +"A detecção de aglomeração não é suportada quando a sequência \"por objeto\" " +"está ativada." msgid "" "Prime tower is required for clumping detection; otherwise, there may be " @@ -11528,7 +11570,7 @@ msgid "Printable area" msgstr "Área de impressão" msgid "Extruder printable area" -msgstr "" +msgstr "Área de impressão da extrusora" msgid "Bed exclude area" msgstr "Área de exclusão da mesa" @@ -11590,12 +11632,14 @@ msgid "Maximum printable height which is limited by mechanism of printer." msgstr "Altura máxima de impressão limitada pelo mecanismo da impressora." msgid "Extruder printable height" -msgstr "" +msgstr "Altura de impressão da extrusora" msgid "" "Maximum printable height of this extruder which is limited by mechanism of " "printer." msgstr "" +"Altura máxima de impressão desta extrusora, limitada pelo mecanismo da " +"impressora." msgid "Preferred orientation" msgstr "Orientação preferida" @@ -14908,19 +14952,19 @@ msgstr "" "diâmetro do bico." msgid "Enable clumping detection" -msgstr "" +msgstr "Habilitar detecção de aglomeração" msgid "Clumping detection layers" -msgstr "" +msgstr "Camadas de detecção de aglomeração" msgid "Clumping detection layers." -msgstr "" +msgstr "Camadas de detecção de aglomeração." msgid "Probing exclude area of clumping" -msgstr "" +msgstr "Sondagem exclui área de aglomeração" msgid "Probing exclude area of clumping." -msgstr "" +msgstr "Sondagem exclui área de aglomeração." msgid "Filament to print internal sparse infill." msgstr "Filamento para imprimir preenchimento esparso interno." diff --git a/resources/profiles/BBL.json b/resources/profiles/BBL.json index 28ce9d1e90..9425300cb4 100644 --- a/resources/profiles/BBL.json +++ b/resources/profiles/BBL.json @@ -1,7 +1,7 @@ { "name": "Bambulab", "url": "http://www.bambulab.com/Parameters/vendor/BBL.json", - "version": "02.00.00.55", + "version": "02.00.00.56", "force_update": "0", "description": "the initial version of BBL configurations", "machine_model_list": [ diff --git a/resources/profiles/BBL/machine/fdm_machine_common.json b/resources/profiles/BBL/machine/fdm_machine_common.json index e33d6b9f9b..0073ac6a8a 100644 --- a/resources/profiles/BBL/machine/fdm_machine_common.json +++ b/resources/profiles/BBL/machine/fdm_machine_common.json @@ -136,6 +136,7 @@ "60" ], "scan_first_layer": "0", + "enable_power_loss_recovery": "1", "silent_mode": "0", "single_extruder_multi_material": "1", "support_air_filtration": "0", diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index a5af72f4c9..3e3fd6f9cf 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -3084,11 +3084,10 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato m_sorted_layer_filaments.emplace_back(lt.extruders); } - //BBS: close powerlost recovery + // Orca: finish tracking power lost recovery { - if (is_bbl_printers && m_second_layer_things_done) { - file.write("; close powerlost recovery\n"); - file.write("M1003 S0\n"); + if (m_second_layer_things_done && print.config().enable_power_loss_recovery.value == true) { + file.write(m_writer.enable_power_loss_recovery(false)); } } ++ finished_objects; @@ -3166,12 +3165,9 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato m_sorted_layer_filaments.emplace_back(lt.extruders); } - //BBS: close powerlost recovery - { - if (is_bbl_printers && m_second_layer_things_done) { - file.write("; close powerlost recovery\n"); - file.write("M1003 S0\n"); - } + // Orca: finish tracking power lost recovery + if (m_second_layer_things_done && print.config().enable_power_loss_recovery.value == true) { + file.write(m_writer.enable_power_loss_recovery(false)); } if (m_wipe_tower) // Purge the extruder, pull out the active filament. @@ -4386,21 +4382,21 @@ LayerResult GCode::process_layer( } if (!first_layer && !m_second_layer_things_done) { - if (print.is_BBL_printer()) { - // BBS: open powerlost recovery - { - gcode += "; open powerlost recovery\n"; - gcode += "M1003 S1\n"; + // Orca: start tracking power lost recovery + if (print.config().enable_power_loss_recovery.value == true) { + gcode += m_writer.enable_power_loss_recovery(true); } - // BBS: open first layer inspection at second layer - if (print.config().scan_first_layer.value) { - // BBS: retract first to avoid droping when scan model - gcode += this->retract(); - gcode += "M976 S1 P1 ; scan model before printing 2nd layer\n"; - gcode += "M400 P100\n"; - gcode += this->unretract(); + + if (print.is_BBL_printer()) { + // BBS: open first layer inspection at second layer + if (print.config().scan_first_layer.value) { + // BBS: retract first to avoid droping when scan model + gcode += this->retract(); + gcode += "M976 S1 P1 ; scan model before printing 2nd layer\n"; + gcode += "M400 P100\n"; + gcode += this->unretract(); + } } - } // Reset acceleration at sencond layer // Orca: only set once, don't need to call set_accel_and_jerk if (m_config.default_acceleration.value > 0 && m_config.initial_layer_acceleration.value > 0) { diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index 2e4627590f..6340a7af5c 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -1,5 +1,6 @@ #include "GCodeWriter.hpp" #include "CustomGCode.hpp" +#include "PrintConfig.hpp" #include #include #include @@ -442,6 +443,23 @@ std::string GCodeWriter::reset_e(bool force) } } +std::string GCodeWriter::enable_power_loss_recovery(bool enable) +{ + std::ostringstream gcode; + + if (m_is_bbl_printers) { + gcode << "; start tracking Power Loss Recovery https://wiki.bambulab.com/en/knowledge-sharing/power-loss-recovery\n"; + gcode << "M1003 S" << (enable ? "1" : "0") << "\n"; + } + else if (FLAVOR_IS(gcfMarlinFirmware)) { + gcode << "; start tracking Power-loss Recovery https://marlinfw.org/docs/gcode/M413.html\n"; + gcode << "M413 S" << (enable ? "1" : "0") << "\n"; + } + + return gcode.str(); +} + + std::string GCodeWriter::update_progress(unsigned int num, unsigned int tot, bool allow_100) const { if (FLAVOR_IS_NOT(gcfMakerWare) && FLAVOR_IS_NOT(gcfSailfish)) diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index 2c68c921d8..729c89263e 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -61,6 +61,7 @@ public: std::string set_input_shaping(char axis, float damp, float freq, std::string type) const; std::string reset_e(bool force = false); std::string update_progress(unsigned int num, unsigned int tot, bool allow_100 = false) const; + std::string enable_power_loss_recovery(bool enable); // return false if this extruder was already selected bool need_toolchange(unsigned int filament_id) const; std::string set_extruder(unsigned int filament_id); diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 1dcdd83000..f5b0d1c713 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1007,7 +1007,7 @@ static std::vector s_Preset_printer_options { "nozzle_height", "master_extruder_id", "default_print_profile", "inherits", "silent_mode", - "scan_first_layer", "wrapping_detection_layers", "wrapping_exclude_area", "machine_load_filament_time", "machine_unload_filament_time", "machine_tool_change_time", "time_cost", "machine_pause_gcode", "template_custom_gcode", + "scan_first_layer", "enable_power_loss_recovery", "wrapping_detection_layers", "wrapping_exclude_area", "machine_load_filament_time", "machine_unload_filament_time", "machine_tool_change_time", "time_cost", "machine_pause_gcode", "template_custom_gcode", "nozzle_type", "nozzle_hrc","auxiliary_fan", "nozzle_volume","upward_compatible_machine", "z_hop_types", "travel_slope", "retract_lift_enforce","support_chamber_temp_control","support_air_filtration","printer_structure", "best_object_pos", "head_wrap_detect_zone", "host_type", "print_host", "printhost_apikey", "bbl_use_printhost", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index bcb2f833c7..3e48103915 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -3365,6 +3365,12 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(false)); + // Orca + def = this->add("enable_power_loss_recovery", coBool); + def->label = L("Turn on Power Loss Recovery"); + def->tooltip = L("Enable this to insert power loss recovery commands in generated G-code.(Only for Bambu Lab printers and Marlin firmware based printers)"); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); //BBS // def = this->add("spaghetti_detector", coBool); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 338fd5c1a7..3e34a8362b 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1271,6 +1271,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionIntsNullable, filament_flush_temp)) // BBS ((ConfigOptionBool, scan_first_layer)) + ((ConfigOptionBool, enable_power_loss_recovery)) ((ConfigOptionBool, enable_wrapping_detection)) ((ConfigOptionInt, wrapping_detection_layers)) ((ConfigOptionPoints, wrapping_exclude_area)) diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 7686356bfb..0148f695aa 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -751,8 +751,14 @@ wxMenuItem* MenuFactory::append_menu_item_change_type(wxMenu* menu) return append_menu_item(menu, wxID_ANY, _L("Change type"), "", [](wxCommandEvent&) { obj_list()->change_part_type(); }, "", menu, []() { - wxDataViewItem item = obj_list()->GetSelection(); - return item.IsOk() || obj_list()->GetModel()->GetItemType(item) == itVolume; + wxDataViewItemArray selections; + obj_list()->GetSelections(selections); + if (selections.empty()) return false; + for (const auto& it : selections) { + if (!(obj_list()->GetModel()->GetItemType(it) & itVolume)) + return false; // non-volume present -> disable + } + return true; }, m_parent); } @@ -864,14 +870,14 @@ void MenuFactory::append_menu_item_reload_from_disk(wxMenu* menu) void MenuFactory::append_menu_item_replace_with_stl(wxMenu *menu) { - append_menu_item(menu, wxID_ANY, _L("Replace with STL") + dots, _L("Replace the selected part with new STL"), + append_menu_item(menu, wxID_ANY, _L("Replace 3D file") + dots, _L("Replace the selected part with a new 3D file"), [](wxCommandEvent &) { plater()->replace_with_stl(); }, "", menu, []() { return plater()->can_replace_with_stl(); }, m_parent); } void MenuFactory::append_menu_item_replace_all_with_stl(wxMenu *menu) { - append_menu_item(menu, wxID_ANY, _L("Replace all with STL") + dots, _L("Replace all selected parts with STL from folder"), + append_menu_item(menu, wxID_ANY, _L("Replace all with 3D files") + dots, _L("Replace all selected parts with 3D files from folder"), [](wxCommandEvent &) { plater()->replace_all_with_stl(); }, "", menu, []() { return plater()->can_replace_all_with_stl(); }, m_parent); } @@ -1798,6 +1804,7 @@ wxMenu* MenuFactory::multi_selection_menu() } append_menu_item_per_object_process(menu); menu->AppendSeparator(); + append_menu_item_change_type(menu); append_menu_item_change_filament(menu); } return menu; diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 5b5e0bd77a..1cea62ece8 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -24,6 +24,10 @@ #include "SingleChoiceDialog.hpp" #include "StepMeshDialog.hpp" + +#include +#include +#include #include #include #include @@ -5337,26 +5341,32 @@ ModelVolume* ObjectList::get_selected_model_volume() void ObjectList::change_part_type() { - ModelVolume* volume = get_selected_model_volume(); - if (!volume) - return; + wxDataViewItemArray selections; + GetSelections(selections); - const int obj_idx = get_selected_obj_idx(); - if (obj_idx < 0) return; + if (selections.size() <= 1) { + int obj_idx = get_selected_obj_idx(); + if (obj_idx < 0) { + return; + } + + ModelVolume* volume = get_selected_model_volume(); + if (!volume) { + return; + } const ModelVolumeType type = volume->type(); - if (type == ModelVolumeType::MODEL_PART) - { - int model_part_cnt = 0; - for (auto vol : (*m_objects)[obj_idx]->volumes) { - if (vol->type() == ModelVolumeType::MODEL_PART) - ++model_part_cnt; - } + if (type == ModelVolumeType::MODEL_PART) { + int model_part_cnt = 0; + for (auto vol : (*m_objects)[obj_idx]->volumes) { + if (vol->type() == ModelVolumeType::MODEL_PART) + ++model_part_cnt; + } - if (model_part_cnt == 1) { - Slic3r::GUI::show_error(nullptr, _(L("The type of the last solid object part is not to be changed."))); - return; - } + if (model_part_cnt == 1) { + Slic3r::GUI::show_error(nullptr, _(L("The type of the last solid object part is not to be changed."))); + return; + } } // ORCA: Fix crash when changing type of svg / text modifier @@ -5365,22 +5375,165 @@ void ObjectList::change_part_type() names.Add(_L("Negative Part")); names.Add(_L("Modifier")); if (!volume->is_svg() && !volume->is_text()) { - names.Add(_L("Support Blocker")); - names.Add(_L("Support Enforcer")); + names.Add(_L("Support Blocker")); + names.Add(_L("Support Enforcer")); } SingleChoiceDialog dlg(_L("Type:"), _L("Choose part type"), names, int(type)); auto new_type = ModelVolumeType(dlg.GetSingleChoiceIndex()); - if (new_type == type || new_type == ModelVolumeType::INVALID) - return; + if (new_type == type || new_type == ModelVolumeType::INVALID) { + return; + } take_snapshot("Change part type"); volume->set_type(new_type); wxDataViewItemArray sel = reorder_volumes_and_get_selection(obj_idx, [volume](const ModelVolume* vol) { return vol == volume; }); - if (!sel.IsEmpty()) - select_item(sel.front()); + if (!sel.IsEmpty()) { + select_item(sel.front()); + } + + return; + } + + // --- Multi Selection --- + struct Target { int obj_idx; Slic3r::ModelVolume* vol; }; + std::vector targets; + targets.reserve(selections.size()); + bool any_text_or_svg = false; + + for (const auto& item : selections) { + auto typeMask = m_objects_model->GetItemType(item); + if (!(typeMask & itVolume)) { + continue; + } + + int obj_idx = -1, vol_idx = -1; + get_selected_item_indexes(obj_idx, vol_idx, item); + if (obj_idx < 0 || vol_idx < 0) { + continue; + } + + ModelVolume* vol = (*m_objects)[obj_idx]->volumes[vol_idx]; + if (!vol) { + continue; + } + + targets.push_back({ obj_idx, vol }); + if (vol->is_svg() || vol->is_text()) + any_text_or_svg = true; + } + + if (targets.empty()) { + return; + } + + wxArrayString names; + names.Add(_L("Part")); + names.Add(_L("Negative Part")); + names.Add(_L("Modifier")); + if (!any_text_or_svg) { + names.Add(_L("Support Blocker")); + names.Add(_L("Support Enforcer")); + } + + // Preselect current type of the first selected volume + ModelVolumeType initial_type = targets.front().vol->type(); + SingleChoiceDialog dlg(_L("Type:"), _L("Choose part type"), names, int(initial_type)); + auto new_type = ModelVolumeType(dlg.GetSingleChoiceIndex()); + if (new_type == ModelVolumeType::INVALID) { + return; + } + + if (new_type != ModelVolumeType::MODEL_PART) { + // Count initial MODEL_PARTs per object + std::unordered_map parts_initial; + for (const auto& t : targets) { + int cnt = 0; + for (auto v : (*m_objects)[t.obj_idx]->volumes) + if (v->type() == ModelVolumeType::MODEL_PART) ++cnt; + parts_initial[t.obj_idx] = cnt; + } + + // Count how many selected MODEL_PARTs would be converted away, per object + std::unordered_map parts_to_remove; + for (const auto& t : targets) { + if (t.vol->type() == ModelVolumeType::MODEL_PART) { + ++parts_to_remove[t.obj_idx]; + } + } + + // If for any object: initial_parts > 0 and removals == initial_parts => would remove all + bool would_remove_all_for_any = false; + for (const auto& kv : parts_to_remove) { + const int obj_idx = kv.first; + const int removing = kv.second; + const int initial = parts_initial[obj_idx]; + if (initial > 0 && removing == initial) { + would_remove_all_for_any = true; + break; + } + } + + if (would_remove_all_for_any) { + Slic3r::GUI::show_error(nullptr, _(L("The type of the last solid object part is not to be changed."))); + return; + } + } + + take_snapshot("Change part type (multi)"); + + // Apply changes + size_t applied = 0, skipped_same = 0; + std::unordered_map> changed_per_object; + for (const auto& t : targets) { + const auto current = t.vol->type(); + if (current == new_type) { + ++skipped_same; + continue; + } + t.vol->set_type(new_type); + changed_per_object[t.obj_idx].push_back(t.vol); + ++applied; + } + + if (applied == 0) { + // Nothing changed; keep the original selection as-is + select_items(selections); + return; + } + + // Reorder per object and rebuild selection to follow changed volumes + wxDataViewItemArray new_selection; + for (const auto& kv : changed_per_object) { + const int obj_idx = kv.first; + const auto& changed_vols = kv.second; + + std::unordered_set changed_set; + changed_set.reserve(changed_vols.size()); + for (const auto* v : changed_vols) { + changed_set.insert(v); + } + + wxDataViewItemArray sel = reorder_volumes_and_get_selection( + obj_idx, + [&changed_set](const ModelVolume* v) -> bool { + return changed_set.find(v) != changed_set.end(); + } + ); + + // Append to new_selection + for (const auto& it : sel) new_selection.Add(it); + } + + if (!new_selection.IsEmpty()) { + select_items(new_selection); + } else { + select_items(selections); + } + + return; } void ObjectList::last_volume_is_deleted(const int obj_idx) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index d489beecbd..25c7129783 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -7766,7 +7766,38 @@ bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const Model new_model; try { - new_model = Model::read_from_file(path, nullptr, nullptr, LoadStrategy::AddDefaultInstances | LoadStrategy::LoadModel); + const bool is_step = boost::algorithm::iends_with(path, ".stp") || boost::algorithm::iends_with(path, ".step"); + if (is_step) { + auto config = wxGetApp().app_config; + double linear = std::max(0.003, string_to_double_decimal_point(config->get("linear_defletion"))); + double angle = std::max(0.5, string_to_double_decimal_point(config->get("angle_defletion"))); + bool split_compound = config->get_bool("is_split_compound"); + bool is_user_cancel = false; + + auto callback = [&is_user_cancel, linear, angle, split_compound](Slic3r::Step &file, double &linear_value, double &angle_value, bool &is_split) -> int { + if (wxGetApp().app_config->get_bool("enable_step_mesh_setting")) { + StepMeshDialog mesh_dlg(nullptr, file, linear, angle); + if (mesh_dlg.ShowModal() == wxID_OK) { + linear_value = mesh_dlg.get_linear_defletion(); + angle_value = mesh_dlg.get_angle_defletion(); + is_split = mesh_dlg.get_split_compound_value(); + return 1; + } + } else { + linear_value = linear; + angle_value = angle; + is_split = split_compound; + return 1; + } + is_user_cancel = true; + return -1; + }; + + new_model = Model::read_from_step(path, LoadStrategy::AddDefaultInstances | LoadStrategy::LoadModel, nullptr, nullptr, callback, linear, angle, split_compound); + if (is_user_cancel) return false; + } else { + new_model = Model::read_from_file(path, nullptr, nullptr, LoadStrategy::AddDefaultInstances | LoadStrategy::LoadModel); + } for (ModelObject* model_object : new_model.objects) { model_object->center_around_origin(); model_object->ensure_on_bed(); @@ -7865,7 +7896,7 @@ void Plater::priv::replace_with_stl() return; } - if (!replace_volume_with_stl(object_idx, volume_idx, out_path, "Replace with STL")) + if (!replace_volume_with_stl(object_idx, volume_idx, out_path, "Replace with 3D file")) return; // update 3D scene @@ -7949,7 +7980,7 @@ void Plater::priv::replace_all_with_stl() return; } - std::string status = _L("Replaced with STLs from directory:\n").ToStdString() + out_path.string() + "\n\n"; + std::string status = _L("Replaced with 3D files from directory:\n").ToStdString() + out_path.string() + "\n\n"; for (unsigned int idx : volume_idxs) { const GLVolume* v = selection.get_volume(idx); @@ -7982,7 +8013,7 @@ void Plater::priv::replace_all_with_stl() BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " replacing volume : " << input_path << " with " << new_path; - if (!replace_volume_with_stl(object_idx, volume_idx, new_path, "Replace with STL")) { + if (!replace_volume_with_stl(object_idx, volume_idx, new_path, "Replace with 3D file")) { status += boost::str(boost::format(_L("✖ Skipped %1%: failed to replace.\n").ToStdString()) % volume_name); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " cannot replace volume : failed to replace with " << new_path; continue; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 253a76a286..b98bb91ec3 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2482,7 +2482,7 @@ void TabPrint::build() optgroup->append_single_option_line("slowdown_for_curled_perimeters", "speed_settings_overhang_speed#slow-down-for-curled-perimeters"); Line line = { L("Overhang speed"), L("This is the speed for various overhang degrees. Overhang degrees are expressed as a percentage of line width. 0 speed means no slowing down for the overhang degree range and wall speed is used") }; - line.label_path = "slow-down-for-overhang"; + line.label_path = "speed_settings_overhang_speed#speed"; line.append_option(optgroup->get_option("overhang_1_4_speed")); line.append_option(optgroup->get_option("overhang_2_4_speed")); line.append_option(optgroup->get_option("overhang_3_4_speed")); @@ -3866,7 +3866,7 @@ void TabFilament::build() // Orca: adaptive pressure advance and calibration model optgroup->append_single_option_line("adaptive_pressure_advance", "material_flow_ratio_and_pressure_advance#enable-adaptive-pressure-advance-beta"); - optgroup->append_single_option_line("adaptive_pressure_advance_overhangs", "material_flow_ratio_and_pressure_advance##enable-adaptive-pressure-advance-for-overhangs-beta"); + optgroup->append_single_option_line("adaptive_pressure_advance_overhangs", "material_flow_ratio_and_pressure_advance#enable-adaptive-pressure-advance-for-overhangs-beta"); optgroup->append_single_option_line("adaptive_pressure_advance_bridges", "material_flow_ratio_and_pressure_advance#pressure-advance-for-bridges"); Option option = optgroup->get_option("adaptive_pressure_advance_model"); @@ -4360,11 +4360,13 @@ void TabPrinter::build_fff() optgroup->append_single_option_line("preferred_orientation", "printer_basic_information_printable_space#preferred-orientation"); optgroup = page->new_optgroup(L("Advanced"), L"param_advanced"); + optgroup->append_single_option_line("printer_structure", "printer_basic_information_advanced#printer-structure"); optgroup->append_single_option_line("gcode_flavor", "printer_basic_information_advanced#g-code-flavor"); optgroup->append_single_option_line("pellet_modded_printer", "printer_basic_information_advanced#pellet-modded-printer"); optgroup->append_single_option_line("bbl_use_printhost", "printer_basic_information_advanced#use-3rd-party-print-host"); optgroup->append_single_option_line("scan_first_layer" , "printer_basic_information_advanced#scan-first-layer"); + optgroup->append_single_option_line("enable_power_loss_recovery", "printer_basic_information_advanced#power-loss-recovery"); //option = optgroup->get_option("wrapping_exclude_area"); //option.opt.full_width = true; //optgroup->append_single_option_line(option); @@ -4712,11 +4714,11 @@ PageShp TabPrinter::build_kinematics_page() // resonance avoidance ported over from qidi slicer optgroup = page->new_optgroup(L("Resonance Avoidance"), "param_resonance_avoidance"); - optgroup->append_single_option_line("resonance_avoidance", "printer_motion_ability_resonance_avoidance#resonance-avoidance"); + optgroup->append_single_option_line("resonance_avoidance", "printer_motion_ability#resonance-avoidance"); // Resonance‑avoidance speed inputs { Line resonance_line = {L("Resonance Avoidance Speed"), L""}; - resonance_line.label_path = "printer_motion_ability_resonance_avoidance#resonance-avoidance-speed"; + resonance_line.label_path = "printer_motion_ability#resonance-avoidance-speed"; resonance_line.append_option(optgroup->get_option("min_resonance_avoidance_speed")); resonance_line.append_option(optgroup->get_option("max_resonance_avoidance_speed")); optgroup->append_line(resonance_line); @@ -4894,7 +4896,7 @@ if (is_marlin_flavor) optgroup = page->new_optgroup(L("Single extruder multi-material parameters"), "param_settings"); optgroup->append_single_option_line("cooling_tube_retraction", "printer_multimaterial_semm_parameters#cooling-tube-position"); optgroup->append_single_option_line("cooling_tube_length", "printer_multimaterial_semm_parameters#cooling-tube-length"); - optgroup->append_single_option_line("parking_pos_retraction", "printer_multimaterial_semm_parameters#filament-parking-positions"); + optgroup->append_single_option_line("parking_pos_retraction", "printer_multimaterial_semm_parameters#filament-parking-position"); optgroup->append_single_option_line("extra_loading_move", "printer_multimaterial_semm_parameters#extra-loading-distance"); optgroup->append_single_option_line("high_current_on_filament_swap", "printer_multimaterial_semm_parameters#high-extruder-current-on-filament-swap"); @@ -5199,7 +5201,11 @@ void TabPrinter::toggle_options() // SoftFever: hide non-BBL settings for (auto el : {"use_firmware_retraction", "use_relative_e_distances", "support_multi_bed_types", "pellet_modded_printer", "bed_mesh_max", "bed_mesh_min", "bed_mesh_probe_distance", "adaptive_bed_mesh_margin", "thumbnails"}) toggle_line(el, !is_BBL_printer); + + auto gcf = m_config->option>("gcode_flavor")->value; + toggle_line("enable_power_loss_recovery", is_BBL_printer || gcf == gcfMarlinFirmware); } + if (m_active_page->title() == L("Machine G-code")) { PresetBundle *preset_bundle = wxGetApp().preset_bundle; diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index bcb9dda915..e10115b1f7 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -189,7 +189,6 @@ Http::priv::priv(const std::string &url) #ifdef __WINDOWS__ ::curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_MAX_TLSv1_2); #endif - ::curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);