diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 937213f17..fb77e85e5 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -355,9 +355,12 @@ public: // This function is useful to split values from multiple extrder / filament settings into separate configurations. virtual void set_at(const ConfigOption *rhs, size_t i, size_t j) = 0; //BBS + virtual void set_at_to_nil(size_t i) = 0; virtual void append(const ConfigOption *rhs) = 0; virtual void set(const ConfigOption* rhs, size_t start, size_t len) = 0; - virtual void set_with_keep(const ConfigOptionVectorBase* rhs, std::vector& keep_index, int stride) = 0; + virtual void set_with_restore(const ConfigOptionVectorBase* rhs, std::vector& restore_index, int stride) = 0; + virtual void set_only_diff(const ConfigOptionVectorBase* rhs, std::vector& diff_index, int stride) = 0; + virtual void set_with_nil(const ConfigOptionVectorBase* rhs, const ConfigOptionVectorBase* inherits, int stride) = 0; // Resize the vector of values, copy the newly added values from opt_default if provided. virtual void resize(size_t n, const ConfigOption *opt_default = nullptr) = 0; // Clear the values vector. @@ -446,6 +449,8 @@ public: } //BBS + virtual void set_at_to_nil(size_t i) override {} + void append(const ConfigOption *rhs) override { if (rhs->type() == this->type()) { @@ -480,7 +485,10 @@ public: throw ConfigurationError("ConfigOptionVector::set_with(): Assigning an incompatible type"); } - virtual void set_with_keep(const ConfigOptionVectorBase* rhs, std::vector& keep_index, int stride) override + //set a item related with extruder variants when loading config from 3mf, restore the non change values to system config + //rhs: item from systemconfig(inherits) + //keep_index: which index in this vector need to be restored + virtual void set_with_restore(const ConfigOptionVectorBase* rhs, std::vector& restore_index, int stride) override { if (rhs->type() == this->type()) { //backup original ones @@ -489,13 +497,13 @@ public: auto other = static_cast*>(rhs); this->values = other->values; - if (other->values.size() != keep_index.size()) - throw ConfigurationError("ConfigOptionVector::set_with_keep(): Assigning from an vector with invalid keep_index size"); + if (other->values.size() != (restore_index.size()*stride)) + throw ConfigurationError("ConfigOptionVector::set_with_restore(): Assigning from an vector with invalid restore_index size"); - for (size_t i = 0; i < keep_index.size(); i++) { - if (keep_index[i] != -1) { + for (size_t i = 0; i < restore_index.size(); i++) { + if (restore_index[i] != -1) { for (size_t j = 0; j < stride; j++) - this->values[i * stride +j] = backup_values[keep_index[i] * stride +j]; + this->values[i * stride +j] = backup_values[restore_index[i] * stride +j]; } } } @@ -503,6 +511,67 @@ public: throw ConfigurationError("ConfigOptionVector::set_with_keep(): Assigning an incompatible type"); } + //set a item related with extruder variants when loading user config, only set the different value of some extruder + //rhs: item from user config + //diff_index: which index in this vector need to be set + virtual void set_only_diff(const ConfigOptionVectorBase* rhs, std::vector& diff_index, int stride) override + { + if (rhs->type() == this->type()) { + // Assign the first value of the rhs vector. + auto other = static_cast*>(rhs); + + if (this->values.size() != (diff_index.size()*stride)) + throw ConfigurationError("ConfigOptionVector::set_only_diff(): Assigning from an vector with invalid diff_index size"); + + for (size_t i = 0; i < diff_index.size(); i++) { + if (diff_index[i] != -1) { + for (size_t j = 0; j < stride; j++) + { + if (!other->is_nil(diff_index[i])) + this->values[i * stride +j] = other->values[diff_index[i] * stride +j]; + } + } + } + } + else + throw ConfigurationError("ConfigOptionVector::set_only_diff(): Assigning an incompatible type"); + } + + //set a item related with extruder variants when saving user config, set the non-diff value of some extruder to nill + //this item has different value with inherit config + //rhs: item from userconfig + //inherits: item from inherit config + virtual void set_with_nil(const ConfigOptionVectorBase* rhs, const ConfigOptionVectorBase* inherits, int stride) override + { + if ((rhs->type() == this->type()) && (inherits->type() == this->type())) { + auto rhs_opt = static_cast*>(rhs); + auto inherits_opt = static_cast*>(inherits); + + if (inherits->size() != rhs->size()) + throw ConfigurationError("ConfigOptionVector::set_with_nil(): rhs size different with inherits size"); + + for (size_t i = 0; i < inherits_opt->size(); i= i+stride) { + bool set_nil = true; + for (size_t j = 0; j < stride; j++) { + if (inherits_opt->values[i +j] != rhs_opt->values[i +j]) { + set_nil = false; + break; + } + } + + for (size_t j = 0; j < stride; j++) { + if (set_nil) { + this->set_at_to_nil(i +j); + } + else + this->values[i +j] = rhs_opt->values[i +j]; + } + } + } + else + throw ConfigurationError("ConfigOptionVector::set_with_nil(): Assigning an incompatible type"); + } + const T& get_at(size_t i) const { assert(! this->values.empty()); @@ -701,6 +770,11 @@ public: // A scalar is nil, or all values of a vector are nil. bool is_nil() const override { for (auto v : this->values) if (! std::isnan(v)) return false; return true; } bool is_nil(size_t idx) const override { return std::isnan(this->values[idx]); } + virtual void set_at_to_nil(size_t i) override + { + assert(nullable() && (i < this->values.size())); + this->values[i] = nil_value(); + } std::string serialize() const override { @@ -862,6 +936,11 @@ public: // A scalar is nil, or all values of a vector are nil. bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; } bool is_nil(size_t idx) const override { return this->values[idx] == nil_value(); } + virtual void set_at_to_nil(size_t i) override + { + assert(nullable() && (i < this->values.size())); + this->values[i] = nil_value(); + } std::string serialize() const override { @@ -1186,6 +1265,11 @@ public: // A scalar is nil, or all values of a vector are nil. bool is_nil() const override { for (auto v : this->values) if (! std::isnan(v.value)) return false; return true; } bool is_nil(size_t idx) const override { return std::isnan(this->values[idx].value); } + virtual void set_at_to_nil(size_t i) override + { + assert(nullable() && (i < this->values.size())); + this->values[i] = nil_value(); + } std::string serialize() const override { @@ -1502,6 +1586,11 @@ public: // A scalar is nil, or all values of a vector are nil. bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; } bool is_nil(size_t idx) const override { return this->values[idx] == nil_value(); } + virtual void set_at_to_nil(size_t i) override + { + assert(nullable() && (i < this->values.size())); + this->values[i] = nil_value(); + } bool& get_at(size_t i) { assert(! this->values.empty()); @@ -2171,6 +2260,7 @@ public: // An UnknownOptionException is thrown in case some option keys are not defined by this->def(), // or this ConfigBase is of a StaticConfig type and it does not support some of the keys, and ignore_nonexistent is not set. void apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false); + // Are the two configs equal? Ignoring options not present in both configs. //BBS: add skipped_keys logic bool equals(const ConfigBase &other, const std::set* skipped_keys = nullptr) const; diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 30662cdd0..ca3cc2c8f 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -523,11 +523,36 @@ bool Preset::save(DynamicPrintConfig* parent_config) DynamicPrintConfig temp_config; std::vector dirty_options = config.diff(*parent_config); + std::string extruder_id_name, extruder_variant_name; + std::set *key_set1 = nullptr, *key_set2 = nullptr; + Preset::get_extruder_names_and_keysets(type, extruder_id_name, extruder_variant_name, &key_set1, &key_set2); + + if (!extruder_id_name.empty()) { + dirty_options.emplace_back(extruder_id_name); + } + if (!extruder_variant_name.empty()) { + dirty_options.emplace_back(extruder_variant_name); + } + for (auto option: dirty_options) { ConfigOption *opt_src = config.option(option); ConfigOption *opt_dst = temp_config.option(option, true); - opt_dst->set(opt_src); + if (opt_dst->is_scalar() || !(opt_dst->nullable())) + opt_dst->set(opt_src); + else { + ConfigOptionVectorBase* opt_vec_src = static_cast(opt_src); + ConfigOptionVectorBase* opt_vec_dst = static_cast(opt_dst); + ConfigOptionVectorBase* opt_vec_inherit = static_cast(parent_config->option(option)); + if (key_set1->find(option) != key_set1->end()) { + opt_vec_dst->set_with_nil(opt_vec_src, opt_vec_inherit, 1); + } + else if (key_set2->find(option) != key_set2->end()) { + opt_vec_dst->set_with_nil(opt_vec_src, opt_vec_inherit, 2); + } + else + opt_dst->set(opt_src); + } } temp_config.save_to_json(this->file, this->name, from_str, this->version.to_string(), this->custom_defined); } else if (!filament_id.empty() && inherits().empty()) { @@ -709,6 +734,31 @@ std::string Preset::get_current_printer_type(PresetBundle *preset_bundle) return ""; } +void Preset::get_extruder_names_and_keysets(Type type, std::string& extruder_id_name, std::string& extruder_variant_name, std::set** p_key_set1, std::set** p_key_set2) +{ + if (type == Preset::TYPE_PRINT) { + extruder_id_name = "print_extruder_id"; + extruder_variant_name = "print_extruder_variant"; + *p_key_set1 = &print_options_with_variant; + *p_key_set2 = &empty_options; + } + else if (type == Preset::TYPE_PRINTER) { + extruder_id_name = "printer_extruder_id"; + extruder_variant_name = "printer_extruder_variant"; + *p_key_set1 = &printer_options_with_variant_1; + *p_key_set2 = &printer_options_with_variant_2; + } + else if (type == Preset::TYPE_FILAMENT) { + extruder_variant_name = "filament_extruder_variant"; + *p_key_set1 = &filament_options_with_variant; + *p_key_set2 = &empty_options; + } + else { + *p_key_set1 = &empty_options; + *p_key_set2 = &empty_options; + } +} + bool Preset::has_lidar(PresetBundle *preset_bundle) { bool has_lidar = false; @@ -1114,6 +1164,12 @@ void PresetCollection::load_presets( // Store the loaded presets into a new vector, otherwise the binary search for already existing presets would be broken. // (see the "Preset already present, not loading" message). std::deque presets_loaded; + + //BBS: get the extruder related info for this preset collection + std::string extruder_id_name, extruder_variant_name; + std::set *key_set1 = nullptr, *key_set2 = nullptr; + Preset::get_extruder_names_and_keysets(m_type, extruder_id_name, extruder_variant_name, &key_set1, &key_set2); + //BBS: change to json format for (auto &dir_entry : boost::filesystem::directory_iterator(dir)) { @@ -1192,6 +1248,7 @@ void PresetCollection::load_presets( if (inherit_preset) { preset.config = inherit_preset->config; preset.filament_id = inherit_preset->filament_id; + preset.config.update_diff_values_to_child_config(config, extruder_id_name, extruder_variant_name, *key_set1, *key_set2); } else { // We support custom root preset now @@ -1202,9 +1259,10 @@ void PresetCollection::load_presets( } // Find a default preset for the config. The PrintPresetCollection provides different default preset based on the "printer_technology" field. preset.config = default_preset.config; + preset.config.apply(std::move(config)); } BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " load preset: " << name << " and filament_id: " << preset.filament_id << " and base_id: " << preset.base_id; - preset.config.apply(std::move(config)); + Preset::normalize(preset.config); // Report configuration fields, which are misplaced into a wrong group. std::string incorrect_keys = Preset::remove_invalid_keys(preset.config, default_preset.config); @@ -1733,7 +1791,15 @@ bool PresetCollection::load_user_preset(std::string name, std::map *key_set1 = nullptr, *key_set2 = nullptr; + Preset::get_extruder_names_and_keysets(m_type, extruder_id_name, extruder_variant_name, &key_set1, &key_set2); + + new_config.update_diff_values_to_child_config(cloud_config, extruder_id_name, extruder_variant_name, *key_set1, *key_set2); + } + else + new_config.apply(std::move(cloud_config)); Preset::normalize(new_config); // Report configuration fields, which are misplaced into a wrong group. std::string incorrect_keys = Preset::remove_invalid_keys(new_config, default_preset.config); @@ -1910,24 +1976,9 @@ std::pair PresetCollection::load_external_preset( } std::string extruder_id_name, extruder_variant_name; - std::set *key_set1 = nullptr, *key_set2 = nullptr, empty_set; - if (m_type == Preset::TYPE_PRINT) { - extruder_id_name = "print_extruder_id"; - extruder_variant_name = "print_extruder_variant"; - key_set1 = &print_options_with_variant; - key_set2 = &empty_set; - } - else if (m_type == Preset::TYPE_PRINTER) { - extruder_id_name = "printer_extruder_id"; - extruder_variant_name = "printer_extruder_variant"; - key_set1 = &printer_options_with_variant_1; - key_set2 = &printer_options_with_variant_2; - } - else if (m_type == Preset::TYPE_FILAMENT) { - extruder_variant_name = "filament_extruder_variant"; - key_set1 = &filament_options_with_variant; - key_set2 = &empty_set; - } + std::set *key_set1 = nullptr, *key_set2 = nullptr; + Preset::get_extruder_names_and_keysets(m_type, extruder_id_name, extruder_variant_name, &key_set1, &key_set2); + if (!inherits.empty() && (different_settings_list.size() > 0)) { auto iter = this->find_preset_internal(inherits); if (iter != m_presets.end() && iter->name == inherits) { diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp index edac28dc9..6846e4898 100644 --- a/src/libslic3r/Preset.hpp +++ b/src/libslic3r/Preset.hpp @@ -243,7 +243,7 @@ public: std::string base_id; // base id of preset std::string sync_info; // enum: "delete", "create", "update", "" std::string custom_defined; // enum: "1", "0", "" - std::string description; // + std::string description; // long long updated_time{0}; //last updated time std::map key_values; @@ -315,6 +315,8 @@ public: std::string get_printer_type(PresetBundle *preset_bundle); // get edited preset type std::string get_current_printer_type(PresetBundle *preset_bundle); // get current preset type + static void get_extruder_names_and_keysets(Type type, std::string& extruder_id_name, std::string& extruder_variant_name, std::set** p_key_set1, std::set** p_key_set2); + bool has_lidar(PresetBundle *preset_bundle); bool is_custom_defined(); diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index 046c1d75a..a150851a7 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -2039,6 +2039,9 @@ DynamicPrintConfig PresetBundle::full_fff_config(bool apply_extruder, std::vecto if (filament_maps.empty()) { filament_maps.resize(num_filaments, 1); } + else { + assert(filament_maps.size() == num_filaments); + } auto* extruder_diameter = dynamic_cast(out.option("nozzle_diameter")); // Collect the "compatible_printers_condition" and "inherits" values over all presets (print, filaments, printers) into a single vector. diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index f710952f0..33daa9c60 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -5112,6 +5112,8 @@ std::set printer_options_with_variant_2 = { "machine_max_jerk_e" }; +std::set empty_options; + DynamicPrintConfig DynamicPrintConfig::full_print_config() { return DynamicPrintConfig((const PrintRegionConfig&)FullPrintConfig::defaults()); @@ -5819,7 +5821,7 @@ void DynamicPrintConfig::update_non_diff_values_to_base_config(DynamicPrintConfi int stride = 1; if (key_set2.find(opt) != key_set2.end()) stride = 2; - opt_vec_src->set_with_keep(opt_vec_dest, variant_index, stride); + opt_vec_src->set_with_restore(opt_vec_dest, variant_index, stride); } } } @@ -5827,6 +5829,81 @@ void DynamicPrintConfig::update_non_diff_values_to_base_config(DynamicPrintConfi return; } +void DynamicPrintConfig::update_diff_values_to_child_config(DynamicPrintConfig& new_config, std::string extruder_id_name, std::string extruder_variant_name, std::set& key_set1, std::set& key_set2) +{ + std::vector cur_extruder_ids, target_extruder_ids, variant_index; + std::vector cur_extruder_variants, target_extruder_variants; + + if (!extruder_id_name.empty()) { + if (this->option(extruder_id_name)) + cur_extruder_ids = this->option(extruder_id_name)->values; + if (new_config.option(extruder_id_name)) + target_extruder_ids = new_config.option(extruder_id_name)->values; + } + if (this->option(extruder_variant_name)) + cur_extruder_variants = this->option(extruder_variant_name, true)->values; + if (new_config.option(extruder_variant_name)) + target_extruder_variants = new_config.option(extruder_variant_name, true)->values; + + int cur_variant_count = cur_extruder_variants.size(); + int target_variant_count = target_extruder_variants.size(); + + variant_index.resize(cur_variant_count, -1); + if (target_variant_count == 0) { + variant_index[0] = 0; + } + else if ((cur_extruder_ids.size() > 0) && cur_variant_count != cur_extruder_ids.size()){ + //should not happen + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" size of %1% = %2%, not equal to size of %3% = %4%") + %extruder_variant_name %cur_variant_count %extruder_id_name %cur_extruder_ids.size(); + } + else if ((target_extruder_ids.size() > 0) && target_variant_count != target_extruder_ids.size()){ + //should not happen + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" size of %1% = %2%, not equal to size of %3% = %4%") + %extruder_variant_name %target_variant_count %extruder_id_name %target_extruder_ids.size(); + } + else { + for (int i = 0; i < cur_variant_count; i++) + { + for (int j = 0; j < target_variant_count; j++) + { + if ((cur_extruder_variants[i] == target_extruder_variants[j]) + &&(cur_extruder_ids.empty() || (cur_extruder_ids[i] == target_extruder_ids[j]))) + { + variant_index[i] = j; + break; + } + } + } + } + + const t_config_option_keys &keys = new_config.keys(); + for (auto& opt : keys) { + if ((opt == extruder_id_name) || (opt == extruder_variant_name)) + continue; + ConfigOption *opt_src = this->option(opt); + const ConfigOption *opt_target = new_config.option(opt); + if (opt_src && opt_target && (*opt_src != *opt_target)) { + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" change key %1% from base_value %2% to child's value %3%") + %opt %(opt_src->serialize()) %(opt_target->serialize()); + if (opt_target->is_scalar() + || ((key_set1.find(opt) == key_set1.end()) && (key_set2.empty() || (key_set2.find(opt) == key_set2.end())))) { + //nothing to do, keep the original one + opt_src->set(opt_target); + } + else { + ConfigOptionVectorBase* opt_vec_src = static_cast(opt_src); + const ConfigOptionVectorBase* opt_vec_dest = static_cast(opt_target); + int stride = 1; + if (key_set2.find(opt) != key_set2.end()) + stride = 2; + opt_vec_src->set_only_diff(opt_vec_dest, variant_index, stride); + } + } + } + return; +} + bool DynamicPrintConfig::is_custom_defined() { auto* is_custom_defined = dynamic_cast(this->option("is_custom_defined")); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index cd3d445bb..34c8dabd4 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -502,6 +502,7 @@ public: void update_non_diff_values_to_base_config(DynamicPrintConfig& new_config, const t_config_option_keys& keys, const std::set& different_keys, std::string extruder_id_name, std::string extruder_variant_name, std::set& key_set1, std::set& key_set2 = std::set()); + void update_diff_values_to_child_config(DynamicPrintConfig& new_config, std::string extruder_id_name, std::string extruder_variant_name, std::set& key_set1, std::set& key_set2); bool is_custom_defined(); }; @@ -510,6 +511,7 @@ extern std::set print_options_with_variant; extern std::set filament_options_with_variant; extern std::set printer_options_with_variant_1; extern std::set printer_options_with_variant_2; +extern std::set empty_options; void handle_legacy_sla(DynamicPrintConfig &config);