From d981097cc3f1b5c88323ddedf57bd31fa1fe8cae Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 27 Oct 2021 04:08:15 +0200 Subject: [PATCH] Add a menu option to import prusa config. Add infill_anchor_max==0 => not connected if from prusa config supermerill/SuperSlicer#1705 --- resources/icons/export_prusa_config.svg | 24 +++++++ resources/icons/import_prusa_config.svg | 29 ++++++++ .../icons/import_prusa_config_bundle.svg | 66 +++++++++++++++++++ src/libslic3r/Format/3mf.cpp | 37 ++--------- src/libslic3r/PresetBundle.cpp | 17 +++-- src/libslic3r/PresetBundle.hpp | 6 +- src/libslic3r/PrintConfig.cpp | 46 +++++++++++++ src/libslic3r/PrintConfig.hpp | 10 +++ src/slic3r/GUI/ConfigManipulation.cpp | 4 +- src/slic3r/GUI/MainFrame.cpp | 23 +++++-- src/slic3r/GUI/MainFrame.hpp | 6 +- 11 files changed, 218 insertions(+), 50 deletions(-) create mode 100644 resources/icons/export_prusa_config.svg create mode 100644 resources/icons/import_prusa_config.svg create mode 100644 resources/icons/import_prusa_config_bundle.svg diff --git a/resources/icons/export_prusa_config.svg b/resources/icons/export_prusa_config.svg new file mode 100644 index 000000000..f3225e29a --- /dev/null +++ b/resources/icons/export_prusa_config.svg @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/resources/icons/import_prusa_config.svg b/resources/icons/import_prusa_config.svg new file mode 100644 index 000000000..567ffaf53 --- /dev/null +++ b/resources/icons/import_prusa_config.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + diff --git a/resources/icons/import_prusa_config_bundle.svg b/resources/icons/import_prusa_config_bundle.svg new file mode 100644 index 000000000..14224e96a --- /dev/null +++ b/resources/icons/import_prusa_config_bundle.svg @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 105db05c9..bd7296a29 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -5,6 +5,7 @@ #include "../GCode.hpp" #include "../Geometry.hpp" #include "../GCode/ThumbnailData.hpp" +#include "../PrintConfig.hpp" #include "../Time.hpp" #include "../I18N.hpp" @@ -592,34 +593,6 @@ namespace Slic3r { XML_StopParser(m_xml_parser, false); } - template - void convert_from_prusa(CONFIG_CLASS& conf, const DynamicPrintConfig& global_config) { - //void convert_from_prusa(DynamicPrintConfig& conf, const DynamicPrintConfig & global_config) { - //void convert_from_prusa(ModelConfigObject& conf, const DynamicPrintConfig& global_config) { - for (const t_config_option_key& opt_key : conf.keys()) { - const ConfigOption* opt = conf.option(opt_key); - std::string serialized = opt->serialize(); - std::string key = opt_key; - std::map result = PrintConfigDef::from_prusa(key, serialized, global_config); - if (key != opt_key) { - conf.erase(opt_key); - } - if (!key.empty() && serialized != opt->serialize()) { - ConfigOption* opt_new = opt->clone(); - opt_new->deserialize(serialized); - conf.set_key_value(key, opt_new); - } - for (auto entry : result) { - const ConfigOptionDef* def = print_config_def.get(entry.first); - if (def) { - ConfigOption* opt_new = def->default_value.get()->clone(); - opt_new->deserialize(entry.second); - conf.set_key_value(entry.first, opt_new); - } - } - } - } - bool _3MF_Importer::_load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions) { mz_zip_archive archive; @@ -761,7 +734,7 @@ namespace Slic3r { return false; else { use_prusa_config = true; - convert_from_prusa(config, config); + config.convert_from_prusa(); } close_zip_reader(&archive); @@ -841,11 +814,11 @@ namespace Slic3r { return false; if (use_prusa_config) { - convert_from_prusa(model_object->config, config); + model_object->config.convert_from_prusa(config); for (ModelVolume* volume : model_object->volumes) - convert_from_prusa(volume->config, config); + volume->config.convert_from_prusa(config); for (auto entry : model_object->layer_config_ranges) - convert_from_prusa(entry.second, config); + entry.second.convert_from_prusa(config); } } diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index 61788dbe1..8cd6e164e 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -5,6 +5,7 @@ #include "Utils.hpp" #include "Model.hpp" #include "format.hpp" +#include "PrintConfig.hpp" #include #include @@ -679,13 +680,15 @@ DynamicPrintConfig PresetBundle::full_sla_config() const // Instead of a config file, a G-code may be loaded containing the full set of parameters. // In the future the configuration will likely be read from an AMF file as well. // If the file is loaded successfully, its print / filament / printer profiles will be activated. -ConfigSubstitutions PresetBundle::load_config_file(const std::string &path, ForwardCompatibilitySubstitutionRule compatibility_rule) +ConfigSubstitutions PresetBundle::load_config_file(const std::string &path, ForwardCompatibilitySubstitutionRule compatibility_rule, bool from_prusa) { if (is_gcode_file(path)) { DynamicPrintConfig config; config.apply(FullPrintConfig::defaults()); ConfigSubstitutions config_substitutions = config.load_from_gcode_file(path, compatibility_rule); Preset::normalize(config); + if(from_prusa) + config.convert_from_prusa(); load_config_file_config(path, true, std::move(config)); return config_substitutions; } @@ -720,11 +723,13 @@ ConfigSubstitutions PresetBundle::load_config_file(const std::string &path, Forw config.apply(FullPrintConfig::defaults()); config_substitutions = config.load(tree, compatibility_rule); Preset::normalize(config); + if (from_prusa) + config.convert_from_prusa(); load_config_file_config(path, true, std::move(config)); return config_substitutions; } case CONFIG_FILE_TYPE_CONFIG_BUNDLE: - return load_config_file_config_bundle(path, tree, compatibility_rule); + return load_config_file_config_bundle(path, tree, compatibility_rule, from_prusa); } } catch (const ConfigurationError &e) { throw Slic3r::RuntimeError(format("Invalid configuration file %1%: %2%", path, e.what())); @@ -906,11 +911,11 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool // Load the active configuration of a config bundle from a boost property_tree. This is a private method called from load_config_file. // Note: only called when using --load from cli. Will load the bundle like with the menu but wihtout saving it. ConfigSubstitutions PresetBundle::load_config_file_config_bundle( - const std::string &path, const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule) + const std::string &path, const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule, bool from_prusa) { // Load the config bundle, but don't save the loaded presets to user profile directory // [PresetsConfigSubstitutions, size_t] - auto [presets_substitutions, presets_imported] = this->load_configbundle(path, { }, compatibility_rule); + auto [presets_substitutions, presets_imported] = this->load_configbundle(path, (from_prusa ? LoadConfigBundleAttributes{ LoadConfigBundleAttribute::ConvertFromPrusa } : LoadConfigBundleAttribute{ }), compatibility_rule); ConfigSubstitutions config_substitutions; this->update_compatible(PresetSelectCompatibleType::Never); for (PresetConfigSubstitutions &sub : presets_substitutions) @@ -1205,7 +1210,7 @@ std::pair PresetBundle::load_configbundle( std::string alias_name; std::vector renamed_from; try { - auto parse_config_section = [§ion, &alias_name, &renamed_from, &substitution_context, &path](DynamicPrintConfig &config) { + auto parse_config_section = [§ion, &alias_name, &renamed_from, &substitution_context, &path, &flags](DynamicPrintConfig &config) { substitution_context.substitutions.clear(); for (auto &kvp : section.second) { if (kvp.first == "alias") @@ -1219,6 +1224,8 @@ std::pair PresetBundle::load_configbundle( // Throws on parsing error. For system presets, no substituion is being done, but an exception is thrown. config.set_deserialize(kvp.first, kvp.second.data(), substitution_context); } + if (flags.has(LoadConfigBundleAttribute::ConvertFromPrusa)) + config.convert_from_prusa(); }; if (presets == &this->printers) { // Select the default config based on the printer_technology field extracted from kvp. diff --git a/src/libslic3r/PresetBundle.hpp b/src/libslic3r/PresetBundle.hpp index d54cec73a..a974f6ed2 100644 --- a/src/libslic3r/PresetBundle.hpp +++ b/src/libslic3r/PresetBundle.hpp @@ -85,7 +85,7 @@ public: // Instead of a config file, a G-code may be loaded containing the full set of parameters. // In the future the configuration will likely be read from an AMF file as well. // If the file is loaded successfully, its print / filament / printer profiles will be activated. - ConfigSubstitutions load_config_file(const std::string &path, ForwardCompatibilitySubstitutionRule compatibility_rule); + ConfigSubstitutions load_config_file(const std::string &path, ForwardCompatibilitySubstitutionRule compatibility_rule, bool from_prusa = false); // Load a config bundle file, into presets and store the loaded presets into separate files // of the local configuration directory. @@ -100,6 +100,8 @@ public: // Load a system config bundle. LoadSystem, LoadVendorOnly, + //apply import rule from prusa + ConvertFromPrusa, }; using LoadConfigBundleAttributes = enum_bitmask; // Load the config bundle based on the flags. @@ -162,7 +164,7 @@ private: // If it is not an external config, then the config will be stored into the user profile directory. void load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config); ConfigSubstitutions load_config_file_config_bundle( - const std::string &path, const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule); + const std::string &path, const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule, bool from_prusa = false); DynamicPrintConfig full_fff_config() const; DynamicPrintConfig full_sla_config() const; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index dec20cb1b..53800ee86 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -5724,9 +5724,49 @@ std::map PrintConfigDef::from_prusa(t_config_option_key if ("xy_size_compensation" == opt_key) { output["xy_inner_size_compensation"] = value; } + if ("infill_anchor_max" == opt_key) { + if(value == "0") + output["infill_connection"] = "notconnected"; + } return output; } + +template +void _convert_from_prusa(CONFIG_CLASS& conf, const DynamicPrintConfig& global_config) { + //void convert_from_prusa(DynamicPrintConfig& conf, const DynamicPrintConfig & global_config) { + //void convert_from_prusa(ModelConfigObject& conf, const DynamicPrintConfig& global_config) { + for (const t_config_option_key& opt_key : conf.keys()) { + const ConfigOption* opt = conf.option(opt_key); + std::string serialized = opt->serialize(); + std::string key = opt_key; + std::map result = PrintConfigDef::from_prusa(key, serialized, global_config); + if (key != opt_key) { + conf.erase(opt_key); + } + if (!key.empty() && serialized != opt->serialize()) { + ConfigOption* opt_new = opt->clone(); + opt_new->deserialize(serialized); + conf.set_key_value(key, opt_new); + } + for (auto entry : result) { + const ConfigOptionDef* def = print_config_def.get(entry.first); + if (def) { + ConfigOption* opt_new = def->default_value.get()->clone(); + opt_new->deserialize(entry.second); + conf.set_key_value(entry.first, opt_new); + } + } + } +} + +void DynamicPrintConfig::convert_from_prusa() { + _convert_from_prusa(*this, *this); +} +void ModelConfig::convert_from_prusa(const DynamicPrintConfig& global_config) { + _convert_from_prusa(*this, global_config); +} + std::unordered_set prusa_export_to_remove_keys = { "allow_empty_layers", "avoid_crossing_not_first_layer", @@ -5972,6 +6012,12 @@ void PrintConfigDef::to_prusa(t_config_option_key& opt_key, std::string& value, } } } + if ("infill_anchor_max" == opt_key) { + //it's infill_anchor == 0 that disable it for prusa + if (all_conf.opt_serialize("infill_connection") == "notconnected") { + value = "0"; + } + } } diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index a9690d221..592b576ab 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -425,6 +425,8 @@ private: std::vector m_milling_option_keys; }; + + // The one and only global definition of SLic3r configuration options. // This definition is constant. extern const PrintConfigDef print_config_def; @@ -477,6 +479,8 @@ public: void to_prusa(t_config_option_key& opt_key, std::string& value) const override { PrintConfigDef::to_prusa(opt_key, value, *this); } + // utilities to help convert from prusa config. + void convert_from_prusa(); /// /// callback to changed other settings that are linked (like width & spacing) @@ -1986,6 +1990,10 @@ public: // Not thread safe! Should not be called from other than the main thread! void touch() { m_timestamp = ++ s_last_timestamp; } + + // utilities to help convert from prusa config. + void convert_from_prusa(const DynamicPrintConfig& global_config); + private: friend class cereal::access; template void serialize(Archive& ar) { ar(m_timestamp); ar(m_data); } @@ -1996,6 +2004,8 @@ private: static uint64_t s_last_timestamp; }; + + } // namespace Slic3r // Serialization through the Cereal library diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index f4373eb54..e862a385d 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -388,7 +388,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) "solid_infill_every_layers", "solid_infill_below_area", "infill_extruder", "infill_anchor_max" }) toggle_field(el, have_infill); // Only allow configuration of open anchors if the anchoring is enabled. - bool has_infill_anchors = have_infill && config->option("infill_anchor_max")->value > 0; + bool has_infill_anchors = have_infill && config->option>("infill_connection")->value != InfillConnection::icNotConnected; + toggle_field("infill_anchor_max", has_infill_anchors); + has_infill_anchors = has_infill_anchors && config->option("infill_anchor_max")->value > 0; toggle_field("infill_anchor", has_infill_anchors); bool can_have_infill_dense = config->option("fill_density")->value < 50; diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index c7aceb01b..60b46ce5f 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -1277,6 +1277,9 @@ void MainFrame::init_menubar_as_editor() append_menu_item(import_menu, wxID_ANY, _L("Import &Config") + dots + "\tCtrl+L", _L("Load exported configuration file"), [this](wxCommandEvent&) { load_config_file(); }, "import_config", nullptr, []() {return true; }, this); + append_menu_item(import_menu, wxID_ANY, _L("Import Prusa Config") + dots, _L("Load configuration file exported from PrusaSlicer"), + [this](wxCommandEvent&) { load_config_file(true); }, "import_prusa_config", nullptr, + []() {return true; }, this); append_menu_item(import_menu, wxID_ANY, _L("Import Config from &project") + dots +"\tCtrl+Alt+L", _L("Load configuration from project file"), [this](wxCommandEvent&) { if (m_plater) m_plater->extract_config_from_project(); }, "import_config", nullptr, []() {return true; }, this); @@ -1284,6 +1287,9 @@ void MainFrame::init_menubar_as_editor() append_menu_item(import_menu, wxID_ANY, _L("Import Config &Bundle") + dots, _L("Load presets from a bundle"), [this](wxCommandEvent&) { load_configbundle(); }, "import_config_bundle", nullptr, []() {return true; }, this); + append_menu_item(import_menu, wxID_ANY, _L("Import Prusa Config Bundle") + dots, _L("Load presets from a PrusaSlicer bundle"), + [this](wxCommandEvent&) { load_configbundle(wxEmptyString, true); }, "import_prusa_config_bundle", nullptr, + []() {return true; }, this); append_submenu(fileMenu, import_menu, wxID_ANY, _L("&Import"), ""); wxMenu* export_menu = new wxMenu(); @@ -1324,7 +1330,7 @@ void MainFrame::init_menubar_as_editor() []() {return true; }, this); export_menu->AppendSeparator(); append_menu_item(export_menu, wxID_ANY, _L("Export to &Prusa Config") + dots, _L("Export current configuration to file, with only settings compatible with PrusaSlicer"), - [this](wxCommandEvent&) { export_config(true); }, "export_config", nullptr, + [this](wxCommandEvent&) { export_config(true); }, "export_prusa_config", nullptr, []() {return true; }, this); append_submenu(fileMenu, export_menu, wxID_ANY, _L("&Export"), ""); @@ -1812,7 +1818,7 @@ void MainFrame::export_config(bool to_prusa) } // Load a config file containing a Print, Filament & Printer preset. -void MainFrame::load_config_file() +void MainFrame::load_config_file(bool from_prusa) { if (!wxGetApp().check_unsaved_changes()) return; @@ -1822,17 +1828,17 @@ void MainFrame::load_config_file() wxString file; if (dlg.ShowModal() == wxID_OK) file = dlg.GetPath(); - if (! file.IsEmpty() && this->load_config_file(file.ToUTF8().data())) { + if (! file.IsEmpty() && this->load_config_file(file.ToUTF8().data(), from_prusa)) { wxGetApp().app_config->update_config_dir(get_dir_name(file)); m_last_config = file; } } // Load a config file containing a Print, Filament & Printer preset from command line. -bool MainFrame::load_config_file(const std::string &path) +bool MainFrame::load_config_file(const std::string &path, bool from_prusa) { try { - ConfigSubstitutions config_substitutions = wxGetApp().preset_bundle->load_config_file(path, ForwardCompatibilitySubstitutionRule::Enable); + ConfigSubstitutions config_substitutions = wxGetApp().preset_bundle->load_config_file(path, ForwardCompatibilitySubstitutionRule::Enable, from_prusa); if (!config_substitutions.empty()) show_substitutions_info(config_substitutions, path); } catch (const std::exception& ex) { @@ -1875,7 +1881,7 @@ void MainFrame::export_configbundle(bool export_physical_printers /*= false*/) // Loading a config bundle with an external file name used to be used // to auto - install a config bundle on a fresh user account, // but that behavior was not documented and likely buggy. -void MainFrame::load_configbundle(wxString file/* = wxEmptyString, const bool reset_user_profile*/) +void MainFrame::load_configbundle(wxString file/* = wxEmptyString*/, bool from_prusa/* = false*/) { if (!wxGetApp().check_unsaved_changes()) return; @@ -1893,9 +1899,12 @@ void MainFrame::load_configbundle(wxString file/* = wxEmptyString, const bool re size_t presets_imported = 0; PresetsConfigSubstitutions config_substitutions; try { + PresetBundle::LoadConfigBundleAttributes lcba{ PresetBundle::LoadConfigBundleAttribute::SaveImported }; // Report all substitutions. std::tie(config_substitutions, presets_imported) = wxGetApp().preset_bundle->load_configbundle( - file.ToUTF8().data(), PresetBundle::LoadConfigBundleAttribute::SaveImported, ForwardCompatibilitySubstitutionRule::Enable); + file.ToUTF8().data(), + (from_prusa ? lcba | PresetBundle::LoadConfigBundleAttribute::ConvertFromPrusa : lcba), + ForwardCompatibilitySubstitutionRule::Enable); } catch (const std::exception &ex) { show_error(this, ex.what()); return; diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 167f86d72..2fab1c6db 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -192,11 +192,11 @@ public: void repair_stl(); void export_config(bool to_prusa = false); // Query user for the config file and open it. - void load_config_file(); + void load_config_file(bool from_prusa = false); // Open a config file. Return true if loaded. - bool load_config_file(const std::string &path); + bool load_config_file(const std::string &path, bool from_prusa = false); void export_configbundle(bool export_physical_printers = false); - void load_configbundle(wxString file = wxEmptyString); + void load_configbundle(wxString file = wxEmptyString, bool from_prusa = false); void load_config(const DynamicPrintConfig& config); // Select tab in m_tabpanel // When tab == -1, will be selected last selected tab