From ca60d37101593bb0a6afd02da50e71c759769e63 Mon Sep 17 00:00:00 2001 From: supermerill Date: Tue, 25 Feb 2025 23:34:11 +0100 Subject: [PATCH 1/7] fix ramping travel while lifted. --- src/libslic3r/GCode.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 18663e5a739..7fdbe91c2ec 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -7086,6 +7086,7 @@ void GCodeGenerator::_add_object_change_labels(std::string& gcode) { // if m_new_z_target, then the ramping lift will be written. if not, then there isn't anything to ensure a good z if(!m_new_z_target && BOOL_EXTRUDER_CONFIG(travel_ramping_lift) && m_spiral_vase_layer <= 0) { gcode += m_writer.get_travel_to_z_gcode(m_writer.get_position().z(), "ensure z is right"); + m_writer.set_lift(0); } } } @@ -7352,13 +7353,12 @@ void GCodeGenerator::write_travel_to(std::string &gcode, Polyline& travel, std:: double layer_change_diff = m_layer->print_z - m_writer.get_unlifted_position().z(); // move layer_change_diff into lift & z_diff_layer_and_lift z_diff_layer_and_lift += layer_change_diff; - } else { - // do a strait z-move (as we can't see the preious point. - gcode += m_writer.get_travel_to_z_gcode(m_layer->print_z, "strait z-move, as the travel is undefined."); - no_ramping = true; } - } else { - assert(!m_new_z_target); + } + if (travel.size() <= 1) { + // do a strait z-move (as we can't see the previous point. + gcode += m_writer.travel_to_z(m_layer->print_z, "strait z-move, as the travel is undefined."); + no_ramping = true; } // register get_extra_lift for our ramping lift (ramping lift + lift_min) if (m_writer.get_extra_lift() != 0) { From e6ba6d11c3326f301694121268517c34f56a592e Mon Sep 17 00:00:00 2001 From: supermerill Date: Tue, 25 Feb 2025 23:34:57 +0100 Subject: [PATCH 2/7] fix missing vendor config with wizard --- src/libslic3r/Semver.cpp | 2 +- src/slic3r/GUI/ConfigWizard.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Semver.cpp b/src/libslic3r/Semver.cpp index 1519af04063..5465e489443 100644 --- a/src/libslic3r/Semver.cpp +++ b/src/libslic3r/Semver.cpp @@ -6,6 +6,6 @@ namespace Slic3r { -Semver SEMVER { SLIC3R_VERSION }; +Semver SEMVER { SLIC3R_VERSION_FULL }; } diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index d950f24fe4d..7633a0308d3 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -173,7 +173,7 @@ BundleMap BundleMap::load() // Fresh index should be in archive_dir, otherwise look for it in cache // Then if not in archive or cache - it could be 3rd party profile that user just copied to vendor folder (both ini and cache) - fs::path idx_path (archive_dir / (id + ".idx")); + fs::path idx_path (cache_dir / (id + ".idx")); if (!boost::filesystem::exists(idx_path)) { BOOST_LOG_TRIVIAL(error) << format("Missing index %1% when loading bundle %2%. Going to search for it in cache folder.", idx_path.string(), id); idx_path = fs::path(cache_dir / (id + ".idx")); From 79e2285530e238ab082bd7753caa05f1f00e7b11 Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 26 Feb 2025 16:50:06 +0100 Subject: [PATCH 3/7] Fix void instead of sparse infill on top if solid deactivated. --- src/libslic3r/LayerRegion.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index 38c873cd0c5..ee2e1a1a3a1 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -1191,11 +1191,11 @@ void LayerRegion::prepare_fill_surfaces() this->region().config().fill_density.value == 0))) { for (Surface &surface : m_fill_surfaces) if (surface.has_pos_top()) - surface.surface_type = ( - //this->layer()->object()->config().infill_only_where_needed && + surface.surface_type = + /*( this->layer()->object()->config().infill_only_where_needed && !this->region().config().infill_dense.value && this->region().config().fill_pattern != ipLightning) ? - stPosInternal | stDensVoid : stPosInternal | stDensSparse; + stPosInternal | stDensVoid :*/ stPosInternal | stDensSparse; } if (this->region().config().bottom_solid_layers == 0) { for (Surface &surface : m_fill_surfaces) From c8b8d07dbebe019b183c0845bccc3bd2c965fe5b Mon Sep 17 00:00:00 2001 From: supermerill Date: Sat, 14 Sep 2024 19:40:41 +0200 Subject: [PATCH 4/7] new util to convert/test configs --- src/libslic3r/PrintConfig.cpp | 130 +++- src/libslic3r/Semver.hpp | 24 +- src/test-utils/CMakeLists.txt | 15 + src/test-utils/convert_config.cpp | 982 ++++++++++++++++++++++++++++++ 4 files changed, 1110 insertions(+), 41 deletions(-) create mode 100644 src/test-utils/convert_config.cpp diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 6b65a6b9b74..27a73356f8e 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -5088,7 +5088,7 @@ void PrintConfigDef::init_fff_params() def->is_vector_extruder = true; def->set_default_value(new ConfigOptionBools{ false }); - // why not reuse rretract_lift ? because it's a max? My current impl enforced the lift, so it's okay for me to remove it. + // why not reuse retract_lift ? because it's a max? My current impl enforced the lift, so it's okay for me to remove it. // def = this->add("travel_max_lift", coFloats); // def->label = L("Maximum ramping lift"); // def->tooltip = L("Maximum lift height of the ramping lift. It may not be reached if the next position " @@ -8697,7 +8697,9 @@ void _handle_legacy(std::unordered_map("external_perimeter_fan_speed"); @@ -9107,11 +9122,39 @@ void PrintConfigDef::handle_legacy_composite(DynamicPrintConfig &config, std::ma ConfigOptionGraphs opt; opt.set_can_be_disabled(); std::vector graph_data; + //ensure same size + assert(enable_dynamic_fan_speeds.size() >= values[0].size()); + assert(values[0].size() >= values[1].size()); + assert(values[1].size() >= values[2].size()); + assert(values[2].size() >= values[3].size()); + const size_t overhang_fan_speed_size = enable_dynamic_fan_speeds.size(); + for (size_t extruder_id = 0; extruder_id < overhang_fan_speed_size; extruder_id++) { + double default_value = 0; + if (values[0].size() <= extruder_id) { + assert(!enable_dynamic_fan_speeds.get_at(extruder_id)); + assert(values[0].size() == extruder_id); + values[0].set_at(default_value, extruder_id); + } else { + default_value = values[0].get_at(extruder_id); + } + if (values[1].size() <= extruder_id) { + assert(values[1].size() == extruder_id); + values[1].set_at(default_value, extruder_id); + } else { + default_value = values[1].get_at(extruder_id); + } + if (values[2].size() <= extruder_id) { + assert(values[2].size() == extruder_id); + values[2].set_at(default_value, extruder_id); + } else { + default_value = values[2].get_at(extruder_id); + } + if (values[3].size() <= extruder_id) { + assert(values[3].size() == extruder_id); + values[3].set_at(default_value, extruder_id); + } + } // while there is a value - assert(enable_dynamic_fan_speeds.size() == values[0].size()); - assert(values[0].size() == values[1].size()); - assert(values[0].size() == values[2].size()); - assert(values[0].size() == values[3].size()); for(int idx = 0 ;idx < enable_dynamic_fan_speeds.size(); ++idx) { // extract values Pointfs graph_curve; @@ -9226,13 +9269,33 @@ std::map PrintConfigDef::from_prusa(t_config_option_key output["brim_ears"] = "1"; } } - if ("support_material_contact_distance" == 0) { - output["support_material_contact_distance_type"] = "none"; + if ("thick_bridges" == opt_key) { + opt_key = "bridge_type"; + if (value == "1") { + value = "nozzle"; + output["bridge_overlap_min"] = "80%"; + output["bridge_overlap"] = "95%"; + } else { + value = "flow"; + output["bridge_overlap_min"] = "60%"; + output["bridge_overlap"] = "75%"; + } + } + if ("support_material_contact_distance" == opt_key) { + if ("0" == value) { + output["support_material_contact_distance_type"] = "none"; + } else { + output["support_material_contact_distance_type"] = "plane"; + } } if (opt_key == "seam_position") { if ("cost" == value ) { // eqauls to "near" == value || "nearest" == value output["seam_angle_cost"] = "50%"; output["seam_travel_cost"] = "50%"; + } else if ("nearest" == value) { + value = "cost"; + output["seam_angle_cost"] = "50%"; + output["seam_travel_cost"] = "50%"; } } if ("bridge_type" == opt_key) { // seems like thick_bridge to 0 @@ -9244,7 +9307,7 @@ std::map PrintConfigDef::from_prusa(t_config_option_key if ("first_layer_height" == opt_key) { if (!value.empty() && value.back() == '%') { // A first_layer_height isn't a % of layer_height but from nozzle_diameter now! - // can't really convert right now, so put it at a safe value liek 50%. + // can't really convert right now, so put it at a safe value like 50%. value = "50%"; } } @@ -9269,9 +9332,15 @@ std::map PrintConfigDef::from_prusa(t_config_option_key value = "rectilinear"; } if ("fan_always_on" == opt_key) { + opt_key = ""; //min_fan_speed is already converted to default_fan_speed, just has to deactivate it if not always_on - if (value != "1") - output["default_fan_speed"] = "0"; + if (value != "1") { + if (all_conf.option("default_fan_speed")) { + output["default_fan_speed"] = std::string("!") + all_conf.option("default_fan_speed")->serialize(); + } else { + output["default_fan_speed"] = "!0"; + } + } } if ("bridge_angle" == opt_key && "0" == value) { value = "!0"; @@ -9335,7 +9404,9 @@ std::map PrintConfigDef::from_prusa(t_config_option_key {"{temperature[initial_extruder]}", "{temperature[initial_extruder]+extruder_temperature_offset[initial_extruder]}"}, {"[first_layer_temperature]", "{first_layer_temperature+extruder_temperature_offset}"}, {"{first_layer_temperature}", "{first_layer_temperature+extruder_temperature_offset}"}, - {"{first_layer_temperature[initial_extruder]}", "{first_layer_temperature[initial_extruder]+extruder_temperature_offset[initial_extruder]}"}}; + {"{first_layer_temperature[initial_extruder]}", "{first_layer_temperature[initial_extruder]+extruder_temperature_offset[initial_extruder]}"}, + {"!is_nil(", "is_enabled("}, + {"is_nil(", "!is_enabled("}}; static const std::set custom_gcode_keys = {"template_custom_gcode", "toolchange_gcode", "before_layer_gcode", @@ -9445,7 +9516,7 @@ void _deserialize_maybe_from_prusa(const std::mapsecond != opt_value) { const ConfigOptionDef *optdef = def->get(opt_key); if (optdef != nullptr) { ConfigSubstitution substitution(optdef, settings.at(key), ConfigOptionUniquePtr(config.option(opt_key)->clone())); @@ -10069,16 +10140,13 @@ std::map PrintConfigDef::to_prusa(t_config_option_key& } if ("default_fan_speed" == opt_key) { if (!value.empty() && value.front() == '!') { - value = "1"; - } - if (value == "0") { - opt_key = "min_fan_speed"; - value = std::to_string(all_conf.option("fan_printer_min_speed")->get_float()); new_entries["fan_always_on"] = "0"; } else { - opt_key = "min_fan_speed"; new_entries["fan_always_on"] = "1"; } + opt_key = "min_fan_speed"; + value = std::to_string(std::max(all_conf.option("fan_printer_min_speed")->get_float(), + all_conf.option("default_fan_speed")->get_float())); } if ("bridge_fan_speed" == opt_key) { if (!value.empty() && value.front() == '!') { diff --git a/src/libslic3r/Semver.hpp b/src/libslic3r/Semver.hpp index 09a165d4cb0..ab2cdba1ca1 100644 --- a/src/libslic3r/Semver.hpp +++ b/src/libslic3r/Semver.hpp @@ -115,18 +115,22 @@ class Semver ~Semver() { ::semver_free(&ver); } - // const accessors - int maj() const { return ver.counter_size > 0 ? ver.counters[0] : 0; } - int min() const { return ver.counter_size > 1 ? ver.counters[1] : 0; } - //int counter() const { return ver.counter_size > 2 ? ver.counters[2] : 0; } - //int patch() const { return ver.counter_size > 3 ? ver.counters[3] : 0; } - const char* prerelease() const { return ver.prerelease; } - const char* metadata() const { return ver.metadata; } + // const accessors + int maj() const { return ver.counter_size > 0 ? ver.counters[0] : 0; } + int min() const { return ver.counter_size > 1 ? ver.counters[1] : 0; } + int counter() const { return ver.counter_size > 2 ? ver.counters[2] : 0; } + int patch() const { return ver.counter_size > 3 ? ver.counters[3] : 0; } + bool has_maj() const { return ver.counter_size > 0; } + bool has_min() const { return ver.counter_size > 1; } + bool has_counter() const { return ver.counter_size > 2; } + bool has_patch() const { return ver.counter_size > 3; } + const char *prerelease() const { return ver.prerelease; } + const char *metadata() const { return ver.metadata; } // Setters - //void set_maj(int maj) { if(ver.counter_size > 0) ver.counters[0] = maj; } - //void set_min(int min) { if (ver.counter_size > 1) ver.counters[1] = min; } - //void set_counter(int count) { if (ver.counter_size > 2) ver.counters[2] = count; } + void set_maj(int maj) { if(ver.counter_size > 0) ver.counters[0] = maj; } + void set_min(int min) { if (ver.counter_size > 1) ver.counters[1] = min; } + void set_counter(int count) { if (ver.counter_size > 2) ver.counters[2] = count; } void set_patch(int patch) { if (ver.counter_size > 3) ver.counters[3] = patch; } void set_metadata(std::optional meta) { diff --git a/src/test-utils/CMakeLists.txt b/src/test-utils/CMakeLists.txt index 2933f13d429..c147e23b4e6 100644 --- a/src/test-utils/CMakeLists.txt +++ b/src/test-utils/CMakeLists.txt @@ -12,3 +12,18 @@ endif () if (WIN32) prusaslicer_copy_dlls(stl_to_cpp) endif() + + + +# test your vendor config, helping to convert from prusaslicer. +add_executable(convert_config convert_config.cpp) + +if (CMAKE_SYSTEM_NAME STREQUAL "Linux") + target_link_libraries(convert_config libslic3r xcb) +else () + target_link_libraries(convert_config libslic3r) +endif () + +if (WIN32) + prusaslicer_copy_dlls(convert_config) +endif() diff --git a/src/test-utils/convert_config.cpp b/src/test-utils/convert_config.cpp new file mode 100644 index 00000000000..f040c02becd --- /dev/null +++ b/src/test-utils/convert_config.cpp @@ -0,0 +1,982 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ClipboardXX/include/clipboardxx.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace Slic3r; +using namespace std; + + +// 1) For the group given by group_name, initialize the presets. +struct Prst { + Prst(const std::string §ion_name, const std::string &name, boost::property_tree::ptree *node) : section_name(section_name), name(name), node(node) {} + // Name of this preset. If the name starts with '*', it is an intermediate preset, + // this section name: [section_name: name]\nnode + const std::string section_name; + // which will not make it into the result. + const std::string name; + std::string name_with_template; + // Link to the source boost property tree node, owned by tree. + boost::property_tree::ptree *node; + DynamicPrintConfig config; + DynamicPrintConfig config_before_prusa; + DynamicPrintConfig config_before_legacy_composite; + //DynamicPrintConfig config_no_prusa_convert; + DynamicPrintConfig config_diff; + // Link to the presets, from which this preset inherits. + std::vector> inherits; + // Link to the presets, for which this preset is a direct parent. + std::vector> parent_of; + // When running the Kahn's Topological sorting algorithm, this counter is decreased from inherits.size() to zero. + // A cycle is indicated, if the number does not drop to zero after the Kahn's algorithm finishes. + size_t num_incoming_edges_left = 0; + // Sorting by the name, to be used when inserted into std::set. + bool operator==(const Prst &rhs) const { return this->name == rhs.name; } + bool operator< (const Prst &rhs) const { return this->name < rhs.name; } +}; +typedef std::shared_ptr PrstPtr; + +std::string get_tech_str(PrinterTechnology tech) { + return ((tech == PrinterTechnology::ptFFF) ? "FFF" : + (tech == PrinterTechnology::ptSLA) ? "DLP(/fake SLA)" : + (tech == PrinterTechnology::ptSLS) ? "SLS" : + (tech == PrinterTechnology::ptMill) ? "CNC" : + (tech == PrinterTechnology::ptLaser) ? "SLA(laser-based)" : + "unknown"); +} + + +t_config_option_keys config_diffs( + const DynamicPrintConfig ¤t_config, + const DynamicPrintConfig &new_full_config) +{ + const std::vector &extruder_retract_keys = print_config_def.extruder_retract_keys(); + const std::string filament_prefix = "filament_"; + t_config_option_keys print_diff; + for (const t_config_option_key &opt_key : current_config.keys()) { + const ConfigOption *opt_old = current_config.option(opt_key); + assert(opt_old != nullptr); + const ConfigOption *opt_new = new_full_config.option(opt_key); + // assert(opt_new != nullptr); + if (opt_new == nullptr) + //FIXME This may happen when executing some test cases. + continue; + if (*opt_new != *opt_old) + print_diff.emplace_back(opt_key); + } + + return print_diff; +} + +void load_preset(const VendorProfile &vendor_profile, PrstPtr preset_to_load) +{ + + std::cout << " --------- now loading preset ["<section_name<<":"<name<<"] --------- \n"; + + + ConfigSubstitutionContext substitution_context { ForwardCompatibilitySubstitutionRule::Enable }; + PresetsConfigSubstitutions substitutions; + //std::string section_name, boost::property_tree::ptree section_data + + std::string path = "[file]"; + PresetBundle::LoadConfigBundleAttributes flags = PresetBundle::LoadConfigBundleAttribute::LoadSystem | PresetBundle::LoadConfigBundleAttribute::ConvertFromPrusa; + PresetCollection *presets = nullptr; + PresetBundle default_bundle; //bundle with only default presets + PhysicalPrinterCollection *ph_printers = nullptr; + std::string ph_printer_name; + + std::vector loaded_fff_prints; + std::vector loaded_filaments; + std::vector loaded_sla_prints; + std::vector loaded_sla_materials; + std::vector loaded_printers; + std::vector loaded_physical_printers; + std::string active_print; + std::vector active_filaments; + std::string active_sla_print; + std::string active_sla_material; + std::string active_printer; + std::string active_physical_printer; + size_t presets_loaded = 0; + size_t ph_printers_loaded = 0; + bool is_print = false; + bool is_printer = false; + + if (preset_to_load->section_name == "print") { + presets = &default_bundle.fff_prints; + is_print = true; + } else if (preset_to_load->section_name == "filament") { + presets = &default_bundle.filaments; + if (vendor_profile.templates_profile) { + preset_to_load->name_with_template += " @Template"; + } + } else if (preset_to_load->section_name == "sla_print") { + presets = &default_bundle.sla_prints; + is_print = true; + } else if (preset_to_load->section_name == "sla_material") { + presets = &default_bundle.sla_materials; + } else if (preset_to_load->section_name == "printer") { + is_printer = true; + presets = &default_bundle.printers; + } else if (preset_to_load->section_name == "physical_printer") { + assert(false); + ph_printers = &default_bundle.physical_printers; + } + //else if (preset_to_load->section_name == "presets") { + // // Load the names of the active presets. + // for (auto &kvp : *preset_to_load->node) { + // if (kvp.first == "print") { + // active_print = kvp.second.data(); + // } else if (boost::starts_with(kvp.first, "filament")) { + // int idx = 0; + // if (kvp.first == "filament" || sscanf(kvp.first.c_str(), "filament_%d", &idx) == 1) { + // if (int(active_filaments.size()) <= idx) + // active_filaments.resize(idx + 1, std::string()); + // active_filaments[idx] = kvp.second.data(); + // } + // } else if (kvp.first == "sla_print") { + // active_sla_print = kvp.second.data(); + // } else if (kvp.first == "sla_material") { + // active_sla_material = kvp.second.data(); + // } else if (kvp.first == "printer") { + // active_printer = kvp.second.data(); + // } else if (kvp.first == "physical_printer") { + // active_physical_printer = kvp.second.data(); + // } + // } + //} + //else if (preset_to_load->section_name == "obsolete_presets") { + // // Parse the names of obsolete presets. These presets will be deleted from user's + // // profile directory on installation of this vendor preset. + // for (auto &kvp : *preset_to_load->node) { + // std::vector *dst = nullptr; + // if (kvp.first == "print") + // dst = &default_bundle.obsolete_presets.fff_prints; + // else if (kvp.first == "filament") + // dst = &default_bundle.obsolete_presets.filaments; + // else if (kvp.first == "sla_print") + // dst = &default_bundle.obsolete_presets.sla_prints; + // else if (kvp.first == "sla_material") + // dst = &default_bundle.obsolete_presets.sla_materials; + // else if (kvp.first == "printer") + // dst = &default_bundle.obsolete_presets.printers; + // if (dst) + // unescape_strings_cstyle(kvp.second.data(), *dst); + // } + //} + //else if (section_name == "settings") { + // // Load the settings. + // for (auto &kvp : *preset_to_load->node) { + // if (kvp.first == "autocenter") { + // } + // } + //} + else { + // Ignore an unknown section. + BOOST_LOG_TRIVIAL(error) << "Error, unknown section: " <section_name; + return; + } + + // Load the print, filament or printer preset. + DynamicPrintConfig default_config; + //DynamicPrintConfig& config = preset_to_load->con; + //DynamicPrintConfig config_no_prusa_convert; + //DynamicPrintConfig config_no_legacy_composite; + std::string alias_name; + std::vector renamed_from; + std::map, std::vector>> opts_prusa_transformed; + std::map opts_deleted; + std::map written_ini; + std::vector ini_ordered_keys; + try { + //auto parse_config_section = [ &preset_to_load, &written_ini, &ini_ordered_keys, &alias_name, &renamed_from, &substitution_context, &path, &flags, + //&merged_config] + //(DynamicPrintConfig &config) { + //set base as the default + if (is_printer) { + default_config = DynamicPrintConfig(); + //find printer_technology field + for (auto &kvp : *preset_to_load->node) { + if (kvp.first == "printer_technology") { + default_config.set_deserialize(kvp.first, kvp.second.data(), substitution_context); + } + } + if (!default_config.has("printer_technology")) { + //from inheritance? + for (auto &preset_parent_ptr : preset_to_load->inherits) { + if (preset_parent_ptr->config.has("printer_technology")) { + default_config.set_key_value("printer_technology", preset_parent_ptr->config.option("printer_technology")->clone()); + } + } + } + if (!default_config.has("printer_technology")) { + BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The preset \"" + << preset_to_load->section_name << ":" << preset_to_load->name + << "\" does not contains a printer_technology field, and this is mandatory " + "for a printer section."; + return; + } + default_config = presets->default_preset_for(default_config).config; + } else { + default_config = presets->default_preset().config; + } + preset_to_load->config = default_config; + //apply parents + // Iterate in a reverse order, so the last change will be placed first in merged. + for (auto it_inherits = preset_to_load->inherits.rbegin(); it_inherits != preset_to_load->inherits.rend(); ++it_inherits) { + preset_to_load->config.apply((*it_inherits)->config_diff); + } + substitution_context.clear(); + std::unordered_map> dict_opt; + for (auto &kvp : *preset_to_load->node) { + if (kvp.first == "alias") { + alias_name = kvp.second.data(); + BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The preset \"" + << preset_to_load->section_name << ":" << preset_to_load->name + << "\" contains invalid \"alias\" key, which is being ignored."; + } else if (kvp.first == "renamed_from") { + if (!unescape_strings_cstyle(kvp.second.data(), renamed_from)) { + BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The preset \"" + << preset_to_load->section_name << ":" << preset_to_load->name + << "\" contains invalid \"renamed_from\" key, which is being ignored."; + } + } + // Throws on parsing error. For system presets, no substituion is being done, but an exception is thrown. + t_config_option_key opt_key = kvp.first; + std::string value = kvp.second.data(); + if (written_ini.find(opt_key) != written_ini.end()) { + BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The preset \"" + << preset_to_load->section_name << ":" << preset_to_load->name + << "\" contains duplicate " << opt_key << " field."; + } else { + written_ini[opt_key] = value; + ini_ordered_keys.push_back(opt_key); + } + if ("gcode_label_objects" == opt_key) { + std::string opt_key2 = kvp.first; + std::string value2 = kvp.second.data(); + } + dict_opt[opt_key] = {opt_key, value}; + } + PrintConfigDef::handle_legacy_map(dict_opt, true); + for (auto &[saved_key, key_val] : dict_opt) { + auto &[opt_key, value] = key_val; + // don't throw for an unknown key, just ignore it + if (!opt_key.empty()) { + preset_to_load->config.set_deserialize(opt_key, value, substitution_context); + } else { + opts_deleted[saved_key] = value; + } + } + preset_to_load->config_before_prusa = preset_to_load->config; + + //prusa: first try the unkown keys + { + std::unordered_map> dict_opt_from_prusa; + std::set not_deleted_anymore; + for (auto &[key, value] : opts_deleted) { + t_config_option_key opt_key = key; + std::string opt_value = value; + std::map result = PrintConfigDef::from_prusa(opt_key, opt_value, + preset_to_load->config); + std::pair old_pair = {key, value}; + if (!opt_key.empty() && (opt_key != key || opt_value != value)) { + dict_opt_from_prusa[opt_key] = {opt_key, opt_value}; + not_deleted_anymore.insert(key); + opts_prusa_transformed[old_pair].push_back({opt_key, opt_value}); + } + for (auto &[k, v] : result) { + assert(!k.empty()); + dict_opt_from_prusa[k] = {k, v}; + not_deleted_anymore.insert(key); + opts_prusa_transformed[old_pair].push_back({k, v}); + } + } + for (auto &key : not_deleted_anymore) { + opts_deleted.erase(key); + } + PrintConfigDef::handle_legacy_map(dict_opt_from_prusa, true); + for (auto &[saved_key, key_val] : dict_opt_from_prusa) { + auto &[opt_key, value] = key_val; + // don't throw for an unknown key, just ignore it + if (!opt_key.empty()) { + preset_to_load->config.set_deserialize(opt_key, value, substitution_context); + } else { + opts_deleted[saved_key] = value; + } + } + if (flags.has(PresetBundle::LoadConfigBundleAttribute::ConvertFromPrusa)) + preset_to_load->config.convert_from_prusa(true); + } + preset_to_load->config_before_legacy_composite = preset_to_load->config; + preset_to_load->config.handle_legacy_composite(opts_deleted); + //apply preset_to_load-> to no-prusa config + //preset_to_load->config_no_prusa_convert = preset_to_load->config_before_prusa; + //std::vector> opts_deleted_donot_care; + //preset_to_load->config_no_prusa_convert.handle_legacy_composite(opts_deleted_donot_care); + //}; + //if (presets == &default_bundle.printers) { + // // Select the default config based on the printer_technology field extracted from kvp. + // DynamicPrintConfig config_src; + // parse_config_section(config_src); + // default_config = &presets->default_preset_for(config_src).config; + // config = *default_config; + // config.apply(config_src); + //} else { + // default_config = &presets->default_preset().config; + // config = *default_config; + // parse_config_section(config); + //} + } catch (const ConfigurationError &e) { + throw ConfigurationError(format("Invalid configuration bundle \"%1%\", section [%2%]: ", path, preset_to_load->section_name + ":"s + preset_to_load->name) + e.what()); + } + + Preset::normalize(preset_to_load->config); + //Preset::normalize(preset_to_load->config_no_prusa_convert); + // Report configuration fields, which are misplaced into a wrong group. + std::string incorrect_keys = Preset::remove_invalid_keys(preset_to_load->config, default_config); + if (! incorrect_keys.empty()) + BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" << + preset_to_load->section_name << ":" << preset_to_load->name << "\" contains the following incorrect keys: " << incorrect_keys << ", which were removed"; + if (flags.has(PresetBundle::LoadConfigBundleAttribute::LoadSystem) && presets == &default_bundle.printers) { + // Filter out printer presets, which are not mentioned in the vendor profile. + // These presets are considered not installed. + auto printer_model = preset_to_load->config.opt_string("printer_model"); + if (printer_model.empty()) { + BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" << + preset_to_load->section_name << ":" << preset_to_load->name << "\" defines no printer model, it will be ignored."; + return; + } + auto printer_variant = preset_to_load->config.opt_string("printer_variant"); + if (printer_variant.empty()) { + BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" << + preset_to_load->section_name << ":" << preset_to_load->name << "\" defines no printer variant, it will be ignored."; + return; + } + auto it_model = std::find_if(vendor_profile.models.cbegin(), vendor_profile.models.cend(), + [&](const VendorProfile::PrinterModel &m) { return m.id == printer_model; } + ); + if (it_model == vendor_profile.models.end()) { + BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" << + preset_to_load->section_name << ":" << preset_to_load->name << "\" defines invalid printer model \"" << printer_model << "\", it will be ignored."; + return; + } + auto it_variant = it_model->variant(printer_variant); + if (it_variant == nullptr) { + BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" << + preset_to_load->section_name << ":" << preset_to_load->name << "\" defines invalid printer variant \"" << printer_variant << "\", it will be ignored."; + return; + } + const Preset *preset_existing = presets->find_preset(preset_to_load->section_name + ":"s + preset_to_load->name, false); + if (preset_existing != nullptr) { + BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" << + preset_to_load->section_name << ":" << preset_to_load->name << "\" has already been loaded from another Confing Bundle."; + return; + } + } else if (! flags.has(PresetBundle::LoadConfigBundleAttribute::LoadSystem)) { + // This is a user config bundle. + const Preset *existing = presets->find_preset(preset_to_load->name_with_template, false); + if (existing != nullptr) { + if (existing->is_system) { + assert(existing->vendor != nullptr); + BOOST_LOG_TRIVIAL(error) << "Error in a user provided Config Bundle \"" << path << "\": The " << presets->name() << " preset \"" << + existing->name << "\" is a system preset of vendor " << existing->vendor->name << " and it will be ignored."; + return; + } else { + assert(existing->vendor == nullptr); + BOOST_LOG_TRIVIAL(trace) << "A " << presets->name() << " preset \"" << existing->name << "\" was overwritten with a preset from user Config Bundle \"" << path << "\""; + } + } else { + BOOST_LOG_TRIVIAL(trace) << "A new " << presets->name() << " preset \"" << preset_to_load->name_with_template << "\" was imported from user Config Bundle \"" << path << "\""; + } + } +// // Decide a full path to this .ini file +// auto file_name = boost::algorithm::iends_with(preset_to_load->name_with_template, ".ini") ? preset_to_load->name_with_template : preset_to_load->name_with_template + ".ini"; +// auto file_path = (boost::filesystem::path(data_dir()) +//#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR +// // Store the print/filament/printer presets into a "presets" directory. +// / "presets" +//#else +// // Store the print/filament/printer presets at the same location as the upstream Slic3r. +//#endif +// / presets->section_name() / file_name).make_preferred(); +// // Load the preset into the list of presets, save it to disk. +// Preset &loaded = presets->load_preset(file_path.string(), preset_to_load->name_with_template, std::move(config), false); +// if (flags.has(PresetBundle::LoadConfigBundleAttribute::SaveImported)) +// loaded.save(); +// if (flags.has(PresetBundle::LoadConfigBundleAttribute::LoadSystem)) { +// loaded.is_system = true; +// loaded.vendor = &vendor_profile; +// } +// +// // Derive the profile logical name aka alias from the preset name if the alias was not stated explicitely. +// if (alias_name.empty()) { +// size_t end_pos = preset_to_load->name_with_template.find_first_of("@"); +// if (end_pos != std::string::npos) { +// alias_name = preset_to_load->name_with_template.substr(0, end_pos); +// if (renamed_from.empty()) +// // Add the preset name with the '@' character removed into the "renamed_from" list. +// renamed_from.emplace_back(alias_name + preset_to_load->name_with_template.substr(end_pos + 1)); +// boost::trim_right(alias_name); +// } +// } +// if (alias_name.empty()) +// loaded.alias = preset_to_load->name_with_template; +// else +// loaded.alias = std::move(alias_name); +// loaded.renamed_from = std::move(renamed_from); + if (! substitution_context.empty()) + substitutions.push_back({preset_to_load->name_with_template, presets->type(), PresetConfigSubstitutions::Source::ConfigBundle, + std::string(), std::move(substitution_context).data()}); + + std::vector diff_keys; + + //populate config diff + diff_keys = config_diffs(preset_to_load->config, default_config); + for (const std::string &key : diff_keys) { + if (preset_to_load->config.has(key)) { + preset_to_load->config_diff.set_deserialize(key, preset_to_load->config.option(key)->serialize()); + } + } + + //compare the ini settigns to the fixed profile + std::cout << " ===== list of legacy vconverted settings: ===== \n"; + for (const std::string &key : ini_ordered_keys) { + if (!preset_to_load->config.option(key)) { + std::string opt_key = key; + std::string value = written_ini[key]; + std::cout << "'" << opt_key << " = " << value << "'"; + PrintConfigDef::handle_legacy_pair(opt_key, value, true); + if (opt_key.empty()) { + if (opts_deleted.find(key) != opts_deleted.end()) { + std::cout << " => legacy delete. please remove this deprecated setting."; + } else { + std::cout << " => transformed into something (see below), please delete this legacy value when you've written the new one."; + } + } else if (opt_key != key || value != written_ini[key]) { + std::cout << " => legacy convert:'" << opt_key << " = " << value << "'"; + } + std::cout << "\n"; + } + } + diff_keys = config_diffs(preset_to_load->config_before_legacy_composite, preset_to_load->config_before_prusa); + std::cout << " ===== list of settings converted from prusa: " << diff_keys.size() << " ===== \n"; + for (const std::string &key : diff_keys) { + std::cout << "'" << key << " = " << (preset_to_load->config_before_prusa.option(key) ? preset_to_load->config_before_prusa.option(key)->serialize() : "") << "'"; + std::cout << "=> '" << key << " = " << (preset_to_load->config_before_legacy_composite.option(key) ? preset_to_load->config_before_legacy_composite.option(key)->serialize() : "") << "'"; + std::cout << "\n"; + } + for (auto &entry : opts_prusa_transformed) { + auto &old_pair = entry.first; + auto &vector = entry.second; + std::cout << "'" << old_pair.first << " = " << old_pair.second << "'"; + if (vector.size() == 1) { + std::cout << "=> '" << vector.front().first << " = " << vector.front().second << "'"; + std::cout << "\n"; + } else { + std::cout << "=> [\n"; + for (auto &new_pair : vector) { + std::cout << " '" << new_pair.first << " = " << new_pair.second << "'\n"; + } + std::cout<<" ]\n"; + } + + } + diff_keys = config_diffs(preset_to_load->config, preset_to_load->config_before_legacy_composite); + std::cout << " ===== list of finals changes need to move from an old setting: " << diff_keys.size() << " ===== \n"; + for (const std::string &key : diff_keys) { + std::cout << "'" << key << " = " << (preset_to_load->config_before_legacy_composite.option(key) ? preset_to_load->config_before_legacy_composite.option(key)->serialize() : "") << "'"; + std::cout << "=> '" << key << " = " << (preset_to_load->config.option(key) ? preset_to_load->config.option(key)->serialize() : "") << "'"; + std::cout << "\n"; + } + if (!preset_to_load->config_before_legacy_composite.option("print_version")) { + std::cout << "'print_version = '"; + std::cout << "=> 'print_version = " << ConfigOptionStringVersion().serialize() << "'"; + std::cout << "\n"; + } + +} + +std::vector get_configbundle_hierarchy(boost::property_tree::ptree &tree, const std::string &group_name) +{ + namespace pt = boost::property_tree; + + struct ComparePrstPtr + { + bool operator()(const PrstPtr &a, const PrstPtr &b) const { return *a < *b; } + }; + // Find the presets, store them into a std::map, addressed by their names. + std::set presets; + std::string group_name_preset = group_name + ":"; + for (auto §ion : tree) + if (boost::starts_with(section.first, group_name_preset) && section.first.size() > group_name_preset.size()) + presets.emplace(std::make_shared(group_name, section.first.substr(group_name_preset.size()), §ion.second)); + // Fill in the "inherits" and "parent_of" members, report invalid inheritance fields. + for (const PrstPtr &prst : presets) { + // Parse the list of comma separated values, possibly enclosed in quotes. + std::vector inherits_names; + std::vector inherits_system; + if (Slic3r::unescape_strings_cstyle(prst->node->get("inherits", ""), inherits_names)) { + // Resolve the inheritance by name. + std::vector &inherits_nodes = prst->inherits; + for (const std::string &node_name : inherits_names) { + auto temp = std::make_shared(group_name, node_name, nullptr); + auto it = presets.find(temp); + if (it == presets.end()) + BOOST_LOG_TRIVIAL(error) << "flatten_configbundle_hierarchy: The preset " << prst->name << " inherits an unknown preset \"" << node_name << "\""; + else { + inherits_nodes.push_back(*it); + inherits_nodes.back()->parent_of.push_back(prst); + } + } + } else { + BOOST_LOG_TRIVIAL(error) << "flatten_configbundle_hierarchy: The preset " << prst->name << " has an invalid \"inherits\" field"; + } + // Remove the "inherits" key, it has no meaning outside of the config bundle. + prst->node->erase("inherits"); + if (! inherits_system.empty()) { + // Loaded a user config bundle, where a profile inherits a system profile. + // User profile should be derived from a single system profile only. + assert(inherits_system.size() == 1); + if (inherits_system.size() > 1) + BOOST_LOG_TRIVIAL(error) << "flatten_configbundle_hierarchy: The preset " << prst->name << " inherits from more than single system preset"; + prst->node->put("inherits", Slic3r::escape_string_cstyle(inherits_system.front())); + } + } + + // 2) Create a linear ordering for the directed acyclic graph of preset inheritance. + // https://en.wikipedia.org/wiki/Topological_sorting + // Kahn's algorithm. + std::vector sorted; + { + // Initialize S with the set of all nodes with no incoming edge. + std::deque S; + for (const PrstPtr &prst : presets) + if (prst->inherits.empty()) + S.push_back(prst); + else + prst->num_incoming_edges_left = prst->inherits.size(); + while (! S.empty()) { + PrstPtr n = S.front(); + S.pop_front(); + sorted.push_back(n); + for (PrstPtr m : n->parent_of) { + assert(m->num_incoming_edges_left > 0); + if (-- m->num_incoming_edges_left == 0) { + // We have visited all parents of m. + S.push_back(m); + } + } + } + if (sorted.size() < presets.size()) { + for (const PrstPtr &prst : presets) + if (prst->num_incoming_edges_left) + BOOST_LOG_TRIVIAL(error) << "flatten_configbundle_hierarchy: The preset " << prst->name << " has cyclic dependencies"; + } + } + + return sorted; + + //// Apply the dependencies in their topological ordering. + //for (PrstPtr prst : sorted) { + // // Merge the preset nodes in their order of application. + // // Iterate in a reverse order, so the last change will be placed first in merged. + // for (auto it_inherits = prst->inherits.rbegin(); it_inherits != prst->inherits.rend(); ++ it_inherits) + // for (auto it = (*it_inherits)->node->begin(); it != (*it_inherits)->node->end(); ++ it) + //if (it->first == "renamed_from") { + // // Don't inherit "renamed_from" flag, it does not make sense. The "renamed_from" flag only makes sense for a concrete preset. + // if (boost::starts_with((*it_inherits)->name, "*")) + // BOOST_LOG_TRIVIAL(error) << boost::format("Nonpublic intermediate preset %1% contains a \"renamed_from\" field, which is ignored") % (*it_inherits)->name; + //} else if (prst->node->find(it->first) == prst->node->not_found()) + // prst->node->add_child(it->first, it->second); + //} + + //// Remove the "internal" presets from the ptree. These presets are marked with '*'. + //group_name_preset += '*'; + //for (auto it_section = tree.begin(); it_section != tree.end(); ) { + // if (boost::starts_with(it_section->first, group_name_preset) && it_section->first.size() > group_name_preset.size()) + // // Remove the "internal" preset from the ptree. + // it_section = tree.erase(it_section); + // else + // // Keep the preset. + // ++ it_section; + //} +} + +void update_preset(const VendorProfile &vendor_profile, PrstPtr preset_to_update) { + if (!preset_to_update->config.empty()) { + //alread updated + return; + } + DynamicPrintConfig merged_config; + // Merge the preset nodes in their order of application. + // Iterate in a reverse order, so the last change will be placed first in merged. + for (auto it_inherits = preset_to_update->inherits.rbegin(); it_inherits != preset_to_update->inherits.rend(); ++it_inherits) { + //first ensure parents are updated + update_preset(vendor_profile, (*it_inherits)); + for (auto it = (*it_inherits)->node->begin(); it != (*it_inherits)->node->end(); ++it) { + if ((it)->first == "renamed_from") { + // Don't inherit "renamed_from" flag, it does not make sense. The "renamed_from" flag only makes sense + // for a concrete preset. + if (boost::starts_with((*it_inherits)->name, "*")) + BOOST_LOG_TRIVIAL(error) << boost::format("Nonpublic intermediate preset %1% contains a " + "\"renamed_from\" field, which is ignored") % + (*it_inherits)->name; + } + // else if (preset_to_update->node->find((*it)->first) == preset_to_update->node->not_found()) { + // preset_to_update->node->add_child((*it)->first, (*it)->second); + //} + } + merged_config.apply((*it_inherits)->config); + } + // now we have the parent config + // use it to parse our config + load_preset(vendor_profile, preset_to_update); + +} + +std::pair> load_sections(const std::string &path) { + + // 1) Read the complete config file into a boost::property_tree. + namespace pt = boost::property_tree; + pt::ptree tree; + { + boost::nowide::ifstream ifs(path); + try { + pt::read_ini(ifs, tree); + } catch (const boost::property_tree::ini_parser::ini_parser_error &err) { + BOOST_LOG_TRIVIAL(error) << "Failed loading config bundle \"" + < ordered_presets_print = get_configbundle_hierarchy(tree, "print"); + // Apply the dependencies in their topological ordering. + for (PrstPtr &prst : ordered_presets_print) { + update_preset(vp, prst); + } + std::vector ordered_presets_sla_print = get_configbundle_hierarchy(tree, "sla_print"); + // Apply the dependencies in their topological ordering. + for (PrstPtr &prst : ordered_presets_sla_print) { + update_preset(vp, prst); + } + std::vector ordered_presets_printer = get_configbundle_hierarchy(tree, "printer"); + // Apply the dependencies in their topological ordering. + for (PrstPtr &prst : ordered_presets_printer) { + update_preset(vp, prst); + } + std::vector ordered_presets_filament = get_configbundle_hierarchy(tree, "filament"); + // Apply the dependencies in their topological ordering. + for (PrstPtr &prst : ordered_presets_filament) { + update_preset(vp, prst); + } + std::vector ordered_presets_material = get_configbundle_hierarchy(tree, "material"); + // Apply the dependencies in their topological ordering. + for (PrstPtr &prst : ordered_presets_material) { + update_preset(vp, prst); + } + //load_preset(vp, std::string section_name, boost::property_tree::ptree section_data) + + std::vector all; + append(all, ordered_presets_print); + append(all, ordered_presets_sla_print); + append(all, ordered_presets_printer); + append(all, ordered_presets_filament); + append(all, ordered_presets_material); + + return {vp, all}; +} + + +void save(const std::string &file, VendorProfile &vp, std::vector &presets, const Semver &ver_susi) +{ + boost::nowide::ofstream c; + c.open(file, std::ios::out | std::ios::trunc); + c << "# " << Slic3r::header_slic3r_generated() << std::endl; + c << "# Generated to " SLIC3R_APP_NAME; + + c << "\n"; + c << "[vendor]\n"; + c << "id = " << vp.id << "\n"; + c << "name = " << vp.name << "\n"; + c << "full_name = " << vp.full_name << "\n"; + c << "config_version = " << ver_susi << "\n"; + c << "config_update_url = \n# " << vp.config_update_url << "\n"; + c << "changelog_url = " << vp.changelog_url << "\n"; + c << "technologies = "; + for (PrinterTechnology &tech : vp.technologies) { + if (tech != vp.technologies.front()) + c <<"; "; + c << to_string(tech); + } + c << "\n"; + + // note: default_filaments & default_sla_materials are not used! + + //printer_model sections + for (VendorProfile::PrinterModel &pmodel : vp.models) { + c << "\n[printer_model:"<name_with_template.empty()) { + c << "#name_with_template = " << preset->name_with_template << "\n"; + } + c << "[" << preset->section_name << ":" << preset->name << "]\n"; + // inherits + if (!preset->inherits.empty()) { + c << "inherits = "; + DynamicPrintConfig config_inherit; + for (std::shared_ptr &inherit_preset : preset->inherits) { + assert(inherit_preset); + if (inherit_preset != preset->inherits.front()) + c <<"; "; + c << inherit_preset->name; + for (std::string &key : inherit_preset->config.keys()) { + config_inherit.set_key_value(key, inherit_preset->config.option(key)->clone()); + } + } + c << "\n"; + //on ne met que le diff + t_config_option_keys diff = preset->config.diff(config_inherit); + for (const std::string &opt_key : diff) + c << opt_key << " = " << preset->config.opt_serialize(opt_key) << "\n"; + } else { + for (const std::string &opt_key : preset->config.keys()) + c << opt_key << " = " << preset->config.opt_serialize(opt_key) << "\n"; + } + } + c.close(); +} + +int main(int argc, char const *argv[]) +{ + Semver slic3r_2_7_61("2.7.61-alpha+UNKNOWN"); + Semver slic3r_2_7_alpha("2.7-alpha+UNKNOWN"); + Semver slic3r_2_6_1_rc2("2.6.1-rc2"); + Semver slic3r_2_6_2_alpha0("2.6.2-alpha0"); + Semver slic3r_2_7_0_alpha2("2.7.0-alpha2"); + Semver slic3r_2_7_0_beta1("2.7.0-beta1"); + + auto test = [](Semver& s1, Semver& s2){ + std::cout << ((s1 == s2) ? "equal" : ((s1 < s2) ? "lower" : "higher")) << "\n"; }; + + test(slic3r_2_6_1_rc2,slic3r_2_6_2_alpha0); + test(slic3r_2_6_2_alpha0,slic3r_2_7_0_alpha2); + test(slic3r_2_7_0_alpha2,slic3r_2_7_0_beta1); + std::cout<<"test 2.7-alpha+UNKNOWN\n"; + test(slic3r_2_7_alpha,slic3r_2_6_1_rc2); + test(slic3r_2_7_alpha,slic3r_2_6_2_alpha0); + test(slic3r_2_7_alpha,slic3r_2_7_0_alpha2); + test(slic3r_2_7_alpha,slic3r_2_7_0_beta1); + test(slic3r_2_7_alpha,slic3r_2_7_61); + std::cout<<"2.7.61-alpha+UNKNOWN\n"; + test(slic3r_2_7_61,slic3r_2_6_1_rc2); + test(slic3r_2_7_61,slic3r_2_6_2_alpha0); + test(slic3r_2_7_61,slic3r_2_7_0_alpha2); + test(slic3r_2_7_61,slic3r_2_7_0_beta1); + + + clipboardxx::clipboard clipboard; + if (argc != 2) { + std::cout<<"usage: test_config \"path/to/vendor/config.ini\"\n"; + return 0; + } + std::string path_str = argv[1]; + if(path_str.front() == '\"' && path_str.back() == '\"') + path_str = path_str.substr(1,path_str.size()-2); + boost::filesystem::path path_in(path_str); + + //PresetsConfigSubstitutions substitutions; + //std::pair res = + // this->load_configbundle(path_str, PresetBundle::LoadSystem, ForwardCompatibilitySubstitutionRule::); + auto [vp, presets] = load_sections(path_str); + + // get path & name + boost::filesystem::path path_out = path_in.parent_path(); + path_out /= "converted"; + boost::filesystem::create_directory(path_out); + path_out /= path_in.filename(); + std::cout<{{-5, -5, -0.1}},std::vector{{1,4,3}}); + //std::stringstream out_cpp; + //int idx_obj = 0; + //for (Slic3r::ModelObject* obj : model.objects) { + // int idx_vol = 0; + // for(Slic3r::ModelVolume *vol : obj->volumes) { + // Slic3r::TriangleMesh mesh = vol->mesh(); + // Slic3r::AABBMesh indexed_mesh(mesh); // more user-friendly + // out_cpp << "AABBMesh vol_"<< idx_obj << "_" << idx_vol <<" = AABBMesh(std::vector{"; + // int ptidx= 0; + // for(const Slic3r::Vec3f &pt : indexed_mesh.vertices()) + // out_cpp << (0==ptidx++?"{":",{") << Slic3r::to_string_nozero(pt.x(), 7) + // << ',' << Slic3r::to_string_nozero(pt.y(), 7) + // << ',' << Slic3r::to_string_nozero(pt.z(), 7) << '}'; + // out_cpp << "},std::vector{"; + // ptidx= 0; + // for(const Slic3r::Vec3i32 &tri : indexed_mesh.indices()) + // out_cpp << (0==ptidx++?"{":",{") << tri(0) << ',' << tri(1) << ',' << tri(2) << '}'; + // out_cpp << "});\n"; + + // idx_vol++; + // } + // out_cpp << "\n"; + // idx_obj++; + //} + + //clipboard << out_cpp.str(); + //std::cout << out_cpp.str(); + + return 0; +} From 76d6ba2054d8c3f49c480f1676e1e909780d0c81 Mon Sep 17 00:00:00 2001 From: supermerill Date: Mon, 3 Mar 2025 12:54:36 +0100 Subject: [PATCH 5/7] ignore bad directories --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 4ec1e24dc0c..f233b5626dd 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ deps/build-linux/* **/.idea/ .pkg_cache CMakeUserPresets.json +**/bad_* + From fa1b8c1478277de32806cf636bd67f54b7f1c67e Mon Sep 17 00:00:00 2001 From: supermerill Date: Tue, 4 Mar 2025 19:25:52 +0100 Subject: [PATCH 6/7] fix config convert, default value for vector use option's default is the system default is empty (before it was using the system's default-option's default) --- src/libslic3r/Config.hpp | 2 +- src/libslic3r/Preset.cpp | 10 +- src/libslic3r/PrintConfig.cpp | 116 ++++-- src/test-utils/convert_config.cpp | 668 +++++++++++++++++++++++------- 4 files changed, 610 insertions(+), 186 deletions(-) diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 21c85b4e5d7..e38a0731846 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -952,7 +952,7 @@ class ConfigOptionVector : public ConfigOptionVectorBase this->m_enabled.erase(this->m_enabled.begin() + n, this->m_enabled.end()); } else if (n > this->m_values.size()) { if (this->m_values.empty()) { - if (opt_default == nullptr) + if (opt_default == nullptr || opt_default->size() == 0) this->m_values.resize(n, this->default_value); else if (opt_default->type() != this->type()) throw ConfigurationError("ConfigOptionVector::resize(): Extending with an incompatible type."); diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index c4494f54623..49a9dd18391 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1,10 +1,6 @@ -///|/ Copyright (c) Prusa Research 2017 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš MatÄ›na @lukasmatena, Tomáš Mészáros @tamasmeszaros, Lukáš Hejl @hejllukas, VojtÄ›ch Bubník @bubnikv, Pavel MikuÅ¡ @Godrak, David Kocík @kocikdav, Enrico Turri @enricoturri1966, VojtÄ›ch Král @vojtechkral -///|/ Copyright (c) 2021 Martin Budden -///|/ Copyright (c) 2021 Ilya @xorza -///|/ Copyright (c) 2019 John Drake @foxox -///|/ Copyright (c) 2018 Martin Loidl @LoidlM +///|/ Copyright (c) SuperSlicer 2025 Durand rémi @supermerill ///|/ -///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ SuperSlicer is released under the terms of the AGPLv3 or higher ///|/ #include @@ -50,6 +46,8 @@ using boost::property_tree::ptree; +// todo: arc_fitting and mlin_gcode_resolution switch from print to printer + namespace Slic3r { ConfigFileType guess_config_file_type(const ptree &tree) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 27a73356f8e..f76b217e181 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1795,9 +1795,9 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("This string is edited by a Dialog and contains extusion multiplier for different speeds."); def->mode = comExpert | comSuSi; def->is_vector_extruder = true; - def->set_default_value(new ConfigOptionGraphs( GraphData(0,10, GraphData::GraphType::LINEAR, + def->set_default_value(new ConfigOptionGraphs({ GraphData(0,10, GraphData::GraphType::LINEAR, {{10,1.},{20,1.},{30,1.},{40,1.},{60,1.},{80,1.},{120,1.},{160,1.},{240,1.},{320,1.},{480,1.},{640,1.},{960,1.},{1280,1.}} - ))); + )})); def->graph_settings = std::make_shared(); def->graph_settings->title = L("Extrusion multiplier per extrusion speed"); def->graph_settings->description = L("Choose the extrusion multipler value for multiple speeds.\nYou can add/remove points with a right clic."); @@ -4285,7 +4285,7 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Overhang size is expressed as a percentage of overlap of the extrusion with the previous layer:" " 100% would be full overlap (no overhang), while 0% represents full overhang (floating extrusion, bridge)." " Speeds for overhang sizes in between are calculated via linear interpolation," - " as a percentage between the (external) perimeter speed and the overhang speed." + " as a percentage between the the overhang speed and the (external) perimeter speed." "\nNote that the speeds generated to gcode will never exceed the max volumetric speed value."); def->sidetext = L("mm/s"); def->can_be_disabled = true; @@ -6565,7 +6565,7 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Only used for Klipper, where you can name the extruder. If not set, will be 'extruderX' with 'X' replaced by the extruder number."); def->mode = comExpert | comSuSi; def->is_vector_extruder = true; - def->set_default_value(new ConfigOptionStrings("")); + def->set_default_value(new ConfigOptionStrings({""})); def = this->add("top_fan_speed", coInts); def->label = L("Top Solid fan speed"); @@ -8469,7 +8469,7 @@ inline void for_ech_entry(std::unordered_map> &dict, - const t_config_option_key &&opt_key) { + const t_config_option_key &opt_key) { last_search_result = dict.find(opt_key); // exists and not already deleted/changed return last_search_result != dict.end() && last_search_result->second.first == opt_key; @@ -8545,6 +8545,15 @@ inline t_config_option_key &opt_key() { // it->second.second = ""; //} +const std::vector> widths_2_spacings_for_phony_fix = + {{"extrusion_width", "extrusion_spacing"}, + {"perimeter_extrusion_width", "perimeter_extrusion_spacing"}, + {"external_perimeter_extrusion_width", "external_perimeter_extrusion_spacing"}, + {"first_layer_extrusion_width", "first_layer_extrusion_spacing"}, + {"infill_extrusion_width", "infill_extrusion_spacing"}, + {"solid_infill_extrusion_width", "solid_infill_extrusion_spacing"}, + {"top_infill_extrusion_width", "top_infill_extrusion_spacing"}}; + inline void erase() { last_search_result->second.first = ""; } @@ -8975,6 +8984,40 @@ void _handle_legacy(std::unordered_map phony spacing + dict[width_2_spacing.second] = {width_2_spacing.second, ""}; + } else { + // can't compute it... put 0 + dict[width_2_spacing.second] = {width_2_spacing.second, "0"}; + } + } else { + const std::string &spacing_value = value(); + if (width_value.empty() && spacing_value.empty()) { + // all phony => set width to 0 + dict[width_2_spacing.first] = {width_2_spacing.first, "0"}; + } else if (!width_value.empty() && !spacing_value.empty()) { + // no phony => set width to phony + dict[width_2_spacing.first] = {width_2_spacing.first, ""}; + } + } + } else if (has(dict, width_2_spacing.second)) { + const std::string &spacing_value = value(); + if (!spacing_value.empty()) { + // we have a spacing => phony width + dict[width_2_spacing.first] = {width_2_spacing.first, ""}; + } else { + // can't compute it... put 0 + dict[width_2_spacing.first] = {width_2_spacing.first, "0"}; + } + } + } + } } // namespace Handle_gacy_tools @@ -9050,9 +9093,11 @@ void PrintConfigDef::handle_legacy_composite(DynamicPrintConfig &config, std::ma for (const t_config_option_key &opt_key : to_erase) { opt_deleted.erase(opt_key); } - if (useful_items.find("enable_dynamic_overhang_speeds") != useful_items.end()) { + if (useful_items.find("enable_dynamic_overhang_speeds") != useful_items.end() || + useful_items.find("overhang_speed_0") != useful_items.end()) { ConfigOptionBool enable_dynamic_overhang_speeds; - enable_dynamic_overhang_speeds.deserialize(useful_items["enable_dynamic_overhang_speeds"]); + if (useful_items.find("enable_dynamic_overhang_speeds") != useful_items.end()) + enable_dynamic_overhang_speeds.deserialize(useful_items["enable_dynamic_overhang_speeds"]); std::vector values; values.resize(4); values[0].deserialize(useful_items["overhang_speed_0"]); @@ -9086,10 +9131,8 @@ void PrintConfigDef::handle_legacy_composite(DynamicPrintConfig &config, std::ma // extract values Pointfs graph_curve; for (int x = 0; x < values.size(); ++x) { - double speed = std::clamp(values[x].value, min, max); - if (values[x].percent) { - speed = values[x].get_abs_value(external_perimeter_speed); - } + double speed = values[x].get_abs_value(external_perimeter_speed); + speed = std::clamp(speed, min, max); double percent = (speed - min) / (max - min); if (min == external_perimeter_speed) { percent = 1 - percent; @@ -9102,27 +9145,39 @@ void PrintConfigDef::handle_legacy_composite(DynamicPrintConfig &config, std::ma graph_curve.push_back(Vec2d(100, 100)); } opt.value = GraphData(graph_curve); - opt.set_enabled(enable_dynamic_overhang_speeds.value); + if (useful_items.find("enable_dynamic_overhang_speeds") != useful_items.end()) + opt.set_enabled(enable_dynamic_overhang_speeds.value); config.set_key_value("overhangs_dynamic_speed", opt.clone()); } - if (useful_items.find("enable_dynamic_fan_speeds") != useful_items.end()) { + if (useful_items.find("enable_dynamic_fan_speeds") != useful_items.end() || + useful_items.find("overhang_fan_speed_0") != useful_items.end()) { // note: there can be a enable_dynamic_fan_speeds and no overhang_fan_speed_X (if it's disabled) // note: there can be a overhang_fan_speed_0 but no overhang_fan_speed_1/2/3 ConfigOptionBools enable_dynamic_fan_speeds; - enable_dynamic_fan_speeds.deserialize(useful_items["enable_dynamic_fan_speeds"]); + if(useful_items.find("enable_dynamic_fan_speeds") != useful_items.end()) + enable_dynamic_fan_speeds.deserialize(useful_items["enable_dynamic_fan_speeds"]); auto *external_perimeter_fan_speed = config.option("external_perimeter_fan_speed"); auto *perimeter_fan_speed = config.option("perimeter_fan_speed"); auto *default_fan_speed = config.option("default_fan_speed"); std::vector values; values.resize(4); - values[0].deserialize(useful_items["overhang_fan_speed_0"]); - values[1].deserialize(useful_items["overhang_fan_speed_1"]); - values[2].deserialize(useful_items["overhang_fan_speed_2"]); - values[3].deserialize(useful_items["overhang_fan_speed_3"]); + if(useful_items.find("overhang_fan_speed_0") != useful_items.end()) + values[0].deserialize(useful_items["overhang_fan_speed_0"]); + if(useful_items.find("overhang_fan_speed_1") != useful_items.end()) + values[1].deserialize(useful_items["overhang_fan_speed_1"]); + if(useful_items.find("overhang_fan_speed_2") != useful_items.end()) + values[2].deserialize(useful_items["overhang_fan_speed_2"]); + if(useful_items.find("overhang_fan_speed_3") != useful_items.end()) + values[3].deserialize(useful_items["overhang_fan_speed_3"]); ConfigOptionGraphs opt; opt.set_can_be_disabled(); std::vector graph_data; //ensure same size + if (enable_dynamic_fan_speeds.size() < values[0].size()) { + for (size_t extruder_id = 0; extruder_id < values[0].size(); extruder_id++) { + enable_dynamic_fan_speeds.set_at(true, extruder_id); + } + } assert(enable_dynamic_fan_speeds.size() >= values[0].size()); assert(values[0].size() >= values[1].size()); assert(values[1].size() >= values[2].size()); @@ -9314,7 +9369,8 @@ std::map PrintConfigDef::from_prusa(t_config_option_key if ("resolution" == opt_key && value == "0") { value = "0.0125"; } - if ("gcode_resolution" == opt_key) { + // can't transfert from print config to printer config (unless there is both) + if ("gcode_resolution" == opt_key && all_conf.has("nozzle_diameter")) { output["gcode_min_resolution"] = value; } if (("brim_width" == opt_key || "brim_width_interior" == opt_key) && all_conf.option("brim_separation") ) { @@ -9401,10 +9457,16 @@ std::map PrintConfigDef::from_prusa(t_config_option_key static const std::vector> custom_gcode_replace = {{"[temperature]", "{temperature+extruder_temperature_offset}"}, {"{temperature}", "{temperature+extruder_temperature_offset}"}, - {"{temperature[initial_extruder]}", "{temperature[initial_extruder]+extruder_temperature_offset[initial_extruder]}"}, + {"[temperature[initial_tool]]", "{temperature[initial_tool]+extruder_temperature_offset[initial_tool]}"}, + {"{temperature[initial_tool]}", "{temperature[initial_tool]+extruder_temperature_offset[initial_tool]}"}, + {"[temperature[initial_extruder]]", "{temperature[initial_tool]+extruder_temperature_offset[initial_tool]}"}, + {"{temperature[initial_extruder]}", "{temperature[initial_tool]+extruder_temperature_offset[initial_tool]}"}, {"[first_layer_temperature]", "{first_layer_temperature+extruder_temperature_offset}"}, {"{first_layer_temperature}", "{first_layer_temperature+extruder_temperature_offset}"}, - {"{first_layer_temperature[initial_extruder]}", "{first_layer_temperature[initial_extruder]+extruder_temperature_offset[initial_extruder]}"}, + {"[first_layer_temperature[initial_tool]]", "{first_layer_temperature[initial_tool]+extruder_temperature_offset[initial_tool]}"}, + {"[first_layer_temperature[initial_extruder]]", "{first_layer_temperature[initial_tool]+extruder_temperature_offset[initial_tool]}"}, + {"{first_layer_temperature[initial_tool]}", "{first_layer_temperature[initial_tool]+extruder_temperature_offset[initial_tool]}"}, + {"{first_layer_temperature[initial_extruder]}", "{first_layer_temperature[initial_tool]+extruder_temperature_offset[initial_tool]}"}, {"!is_nil(", "is_enabled("}, {"is_nil(", "!is_enabled("}}; @@ -9430,14 +9492,6 @@ const std::unordered_set prusa_import_to_review_keys = "thumbnails" }; -const std::vector> prusa_import_widths_2_spacings_for_phony_fix = - {{"extrusion_width", "extrusion_spacing"}, - {"perimeter_extrusion_width", "perimeter_extrusion_spacing"}, - {"external_perimeter_extrusion_width", "external_perimeter_extrusion_spacing"}, - {"first_layer_extrusion_width", "first_layer_extrusion_spacing"}, - {"infill_extrusion_width", "infill_extrusion_spacing"}, - {"solid_infill_extrusion_width", "solid_infill_extrusion_spacing"}, - {"top_infill_extrusion_width", "top_infill_extrusion_spacing"}}; template void _convert_from_prusa(CONFIG_CLASS& conf, const DynamicPrintConfig& global_config, bool with_phony) { @@ -9470,7 +9524,7 @@ void _convert_from_prusa(CONFIG_CLASS& conf, const DynamicPrintConfig& global_co // set phony entries if (with_phony) { - for (auto & [opt_key_width, opt_key_spacing] : prusa_import_widths_2_spacings_for_phony_fix) { + for (auto & [opt_key_width, opt_key_spacing] : Handle_legacy_tools::widths_2_spacings_for_phony_fix) { // if prusa has defined a width, or if the conf has a default spacing that need to be overwritten if (conf.option(opt_key_width) != nullptr || conf.option(opt_key_spacing) != nullptr) { ConfigOption *opt_new = print_config_def.get(opt_key_spacing)->default_value.get()->clone(); @@ -9611,7 +9665,7 @@ void _deserialize_maybe_from_prusa(const std::map> inherits; + // if true, it means that it has all values defined from itself and its parents. + bool has_all_values; + // you need to write all values, even the ones that are the same as the current default + bool write_defaults; + // set it to true if it's useless or wrong. + bool deleted = false; // Link to the presets, for which this preset is a direct parent. std::vector> parent_of; // When running the Kahn's Topological sorting algorithm, this counter is decreased from inherits.size() to zero. @@ -64,6 +71,14 @@ struct Prst { // Sorting by the name, to be used when inserted into std::set. bool operator==(const Prst &rhs) const { return this->name == rhs.name; } bool operator< (const Prst &rhs) const { return this->name < rhs.name; } + + // also get the diffs from parent. + void apply_current_diff(DynamicPrintConfig &to_be_applied) const { + for (std::shared_ptr parent : inherits) { + parent->apply_current_diff(to_be_applied); + } + to_be_applied.apply(config_diff); + } }; typedef std::shared_ptr PrstPtr; @@ -92,6 +107,8 @@ t_config_option_keys config_diffs( if (opt_new == nullptr) //FIXME This may happen when executing some test cases. continue; + if (opt_new->is_phony() && opt_old->is_phony()) + continue; if (*opt_new != *opt_old) print_diff.emplace_back(opt_key); } @@ -101,7 +118,10 @@ t_config_option_keys config_diffs( void load_preset(const VendorProfile &vendor_profile, PrstPtr preset_to_load) { - + bool check_preset_debug = false; + if (preset_to_load->name.find("*0.25nozzle*") != std::string::npos) { + check_preset_debug = true; + } std::cout << " --------- now loading preset ["<section_name<<":"<name<<"] --------- \n"; @@ -109,7 +129,7 @@ void load_preset(const VendorProfile &vendor_profile, PrstPtr preset_to_load) PresetsConfigSubstitutions substitutions; //std::string section_name, boost::property_tree::ptree section_data - std::string path = "[file]"; + std::string path = vendor_profile.name; PresetBundle::LoadConfigBundleAttributes flags = PresetBundle::LoadConfigBundleAttribute::LoadSystem | PresetBundle::LoadConfigBundleAttribute::ConvertFromPrusa; PresetCollection *presets = nullptr; PresetBundle default_bundle; //bundle with only default presets @@ -205,6 +225,7 @@ void load_preset(const VendorProfile &vendor_profile, PrstPtr preset_to_load) else { // Ignore an unknown section. BOOST_LOG_TRIVIAL(error) << "Error, unknown section: " <section_name; + preset_to_load->deleted = true; return; } @@ -218,9 +239,9 @@ void load_preset(const VendorProfile &vendor_profile, PrstPtr preset_to_load) std::map, std::vector>> opts_prusa_transformed; std::map opts_deleted; std::map written_ini; - std::vector ini_ordered_keys; + std::vector ini_keys; try { - //auto parse_config_section = [ &preset_to_load, &written_ini, &ini_ordered_keys, &alias_name, &renamed_from, &substitution_context, &path, &flags, + //auto parse_config_section = [ &preset_to_load, &written_ini, &ini_keys, &alias_name, &renamed_from, &substitution_context, &path, &flags, //&merged_config] //(DynamicPrintConfig &config) { //set base as the default @@ -240,23 +261,32 @@ void load_preset(const VendorProfile &vendor_profile, PrstPtr preset_to_load) } } } - if (!default_config.has("printer_technology")) { - BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The preset \"" - << preset_to_load->section_name << ":" << preset_to_load->name - << "\" does not contains a printer_technology field, and this is mandatory " - "for a printer section."; - return; + if (!default_config.has("printer_technology") && preset_to_load->has_all_values) { + if (!preset_to_load->parent_of.empty() && preset_to_load->inherits.empty()) { + BOOST_LOG_TRIVIAL(warning) + << "Warning in a Vendor Config Bundle \"" << path << "\": The preset \"" + << preset_to_load->section_name << ":" << preset_to_load->name + << "\" does not contains a printer_technology field, and this should be set " + " in the common root."; + } else { + BOOST_LOG_TRIVIAL(error) + << "Error in a Vendor Config Bundle \"" << path << "\": The preset \"" + << preset_to_load->section_name << ":" << preset_to_load->name + << "\" does not contains a printer_technology field, and this is mandatory " + "for at least one printer section in the inheritance tree."; + preset_to_load->deleted = true; + return; + } } default_config = presets->default_preset_for(default_config).config; } else { default_config = presets->default_preset().config; } - preset_to_load->config = default_config; //apply parents - // Iterate in a reverse order, so the last change will be placed first in merged. - for (auto it_inherits = preset_to_load->inherits.rbegin(); it_inherits != preset_to_load->inherits.rend(); ++it_inherits) { - preset_to_load->config.apply((*it_inherits)->config_diff); + for (auto it_inherits = preset_to_load->inherits.begin(); it_inherits != preset_to_load->inherits.end(); ++it_inherits) { + (*it_inherits)->apply_current_diff(default_config); } + preset_to_load->config = default_config; substitution_context.clear(); std::unordered_map> dict_opt; for (auto &kvp : *preset_to_load->node) { @@ -281,7 +311,6 @@ void load_preset(const VendorProfile &vendor_profile, PrstPtr preset_to_load) << "\" contains duplicate " << opt_key << " field."; } else { written_ini[opt_key] = value; - ini_ordered_keys.push_back(opt_key); } if ("gcode_label_objects" == opt_key) { std::string opt_key2 = kvp.first; @@ -290,11 +319,13 @@ void load_preset(const VendorProfile &vendor_profile, PrstPtr preset_to_load) dict_opt[opt_key] = {opt_key, value}; } PrintConfigDef::handle_legacy_map(dict_opt, true); + ini_keys.clear(); for (auto &[saved_key, key_val] : dict_opt) { auto &[opt_key, value] = key_val; // don't throw for an unknown key, just ignore it if (!opt_key.empty()) { preset_to_load->config.set_deserialize(opt_key, value, substitution_context); + ini_keys.push_back(opt_key); } else { opts_deleted[saved_key] = value; } @@ -361,47 +392,54 @@ void load_preset(const VendorProfile &vendor_profile, PrstPtr preset_to_load) } catch (const ConfigurationError &e) { throw ConfigurationError(format("Invalid configuration bundle \"%1%\", section [%2%]: ", path, preset_to_load->section_name + ":"s + preset_to_load->name) + e.what()); } - Preset::normalize(preset_to_load->config); //Preset::normalize(preset_to_load->config_no_prusa_convert); // Report configuration fields, which are misplaced into a wrong group. std::string incorrect_keys = Preset::remove_invalid_keys(preset_to_load->config, default_config); if (! incorrect_keys.empty()) - BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" << + BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The preset \"" << preset_to_load->section_name << ":" << preset_to_load->name << "\" contains the following incorrect keys: " << incorrect_keys << ", which were removed"; - if (flags.has(PresetBundle::LoadConfigBundleAttribute::LoadSystem) && presets == &default_bundle.printers) { + //if (flags.has(PresetBundle::LoadConfigBundleAttribute::LoadSystem) && presets == &default_bundle.printers) { + // if printer leaf, it needs to be linked to a printer_model + if (presets == &default_bundle.printers && preset_to_load->parent_of.empty()) { // Filter out printer presets, which are not mentioned in the vendor profile. // These presets are considered not installed. - auto printer_model = preset_to_load->config.opt_string("printer_model"); - if (printer_model.empty()) { + // note: *common* doesn't have any printer_model + auto printer_model = preset_to_load->config.option("printer_model"); + if (!printer_model || printer_model->serialize().empty()) { BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" << preset_to_load->section_name << ":" << preset_to_load->name << "\" defines no printer model, it will be ignored."; + preset_to_load->deleted = true; return; } auto printer_variant = preset_to_load->config.opt_string("printer_variant"); if (printer_variant.empty()) { BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" << preset_to_load->section_name << ":" << preset_to_load->name << "\" defines no printer variant, it will be ignored."; + preset_to_load->deleted = true; return; } auto it_model = std::find_if(vendor_profile.models.cbegin(), vendor_profile.models.cend(), - [&](const VendorProfile::PrinterModel &m) { return m.id == printer_model; } + [&](const VendorProfile::PrinterModel &m) { return m.id == printer_model->serialize(); } ); if (it_model == vendor_profile.models.end()) { BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" << - preset_to_load->section_name << ":" << preset_to_load->name << "\" defines invalid printer model \"" << printer_model << "\", it will be ignored."; + preset_to_load->section_name << ":" << preset_to_load->name << "\" defines invalid printer model \"" << printer_model->serialize() << "\", it will be ignored."; + preset_to_load->deleted = true; return; } auto it_variant = it_model->variant(printer_variant); if (it_variant == nullptr) { BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" << preset_to_load->section_name << ":" << preset_to_load->name << "\" defines invalid printer variant \"" << printer_variant << "\", it will be ignored."; + preset_to_load->deleted = true; return; } const Preset *preset_existing = presets->find_preset(preset_to_load->section_name + ":"s + preset_to_load->name, false); if (preset_existing != nullptr) { BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" << preset_to_load->section_name << ":" << preset_to_load->name << "\" has already been loaded from another Confing Bundle."; + preset_to_load->deleted = true; return; } } else if (! flags.has(PresetBundle::LoadConfigBundleAttribute::LoadSystem)) { @@ -409,18 +447,25 @@ void load_preset(const VendorProfile &vendor_profile, PrstPtr preset_to_load) const Preset *existing = presets->find_preset(preset_to_load->name_with_template, false); if (existing != nullptr) { if (existing->is_system) { - assert(existing->vendor != nullptr); - BOOST_LOG_TRIVIAL(error) << "Error in a user provided Config Bundle \"" << path << "\": The " << presets->name() << " preset \"" << - existing->name << "\" is a system preset of vendor " << existing->vendor->name << " and it will be ignored."; + assert(existing->vendor != nullptr); + BOOST_LOG_TRIVIAL(error) + << "Error in a user provided Config Bundle \"" << path << "\": The " << presets->name() + << " preset \"" << existing->name << "\" is a system preset of vendor " << existing->vendor->name + << " and it will be ignored."; + preset_to_load->deleted = true; return; } else { assert(existing->vendor == nullptr); BOOST_LOG_TRIVIAL(trace) << "A " << presets->name() << " preset \"" << existing->name << "\" was overwritten with a preset from user Config Bundle \"" << path << "\""; } } else { - BOOST_LOG_TRIVIAL(trace) << "A new " << presets->name() << " preset \"" << preset_to_load->name_with_template << "\" was imported from user Config Bundle \"" << path << "\""; + BOOST_LOG_TRIVIAL(trace) << "A new " << presets->name() << " preset \"" + << preset_to_load->name_with_template + << "\" was imported from user Config Bundle \"" << path << "\""; } } + + // // Decide a full path to this .ini file // auto file_name = boost::algorithm::iends_with(preset_to_load->name_with_template, ".ini") ? preset_to_load->name_with_template : preset_to_load->name_with_template + ".ini"; // auto file_path = (boost::filesystem::path(data_dir()) @@ -460,68 +505,106 @@ void load_preset(const VendorProfile &vendor_profile, PrstPtr preset_to_load) substitutions.push_back({preset_to_load->name_with_template, presets->type(), PresetConfigSubstitutions::Source::ConfigBundle, std::string(), std::move(substitution_context).data()}); - std::vector diff_keys; + { + std::set diff_keys(ini_keys.begin(), ini_keys.end()); - //populate config diff - diff_keys = config_diffs(preset_to_load->config, default_config); - for (const std::string &key : diff_keys) { - if (preset_to_load->config.has(key)) { - preset_to_load->config_diff.set_deserialize(key, preset_to_load->config.option(key)->serialize()); + // populate config diff + // because convertion can add new keys + auto vec = config_diffs(preset_to_load->config, default_config); + for (std::string &key : vec) { + if (default_config.option(key)->size() == 0 && preset_to_load->config.option(key)->size() > 0) { + assert((preset_to_load->config.option(key)->type() & coVectorType) == coVectorType); + const ConfigOptionVectorBase* opt = static_cast(preset_to_load->config.option(key)); + ConfigOptionVectorBase* opt_copy = static_cast(preset_to_load->config.option(key)->clone()); + opt_copy->resize(0); + opt_copy->resize(opt->size()); + bool is_default_ptr = (opt_copy) == (opt); + bool is_default = (*opt_copy) == (*opt); + delete opt_copy; + if (is_default && !preset_to_load->write_defaults) { + continue; + } + } + diff_keys.insert(key); + } + for (const std::string &key : diff_keys) { + //assert(preset_to_load->config.has(key)); // ini_keys keys may have been deleted by convert + if (preset_to_load->config.has(key)) { + preset_to_load->config_diff.set_deserialize(key, preset_to_load->config.opt_serialize(key)); + } } } //compare the ini settigns to the fixed profile - std::cout << " ===== list of legacy vconverted settings: ===== \n"; - for (const std::string &key : ini_ordered_keys) { - if (!preset_to_load->config.option(key)) { - std::string opt_key = key; - std::string value = written_ini[key]; - std::cout << "'" << opt_key << " = " << value << "'"; - PrintConfigDef::handle_legacy_pair(opt_key, value, true); - if (opt_key.empty()) { - if (opts_deleted.find(key) != opts_deleted.end()) { - std::cout << " => legacy delete. please remove this deprecated setting."; - } else { - std::cout << " => transformed into something (see below), please delete this legacy value when you've written the new one."; + size_t count = 0; + for (const std::string &key : ini_keys) + if (!preset_to_load->config.option(key)) + count++; + if (count > 0) { + std::cout << " ===== list of legacy vconverted settings: ===== \n"; + for (const std::string &key : ini_keys) { + if (!preset_to_load->config.option(key)) { + std::string opt_key = key; + std::string value = written_ini[key]; + std::cout << "'" << opt_key << " = " << value << "'"; + PrintConfigDef::handle_legacy_pair(opt_key, value, true); + if (opt_key.empty()) { + if (opts_deleted.find(key) != opts_deleted.end()) { + std::cout << " => legacy delete. please remove this deprecated setting."; + } else { + std::cout << " => transformed into something (see below), please delete this legacy value " + "when you've written the new one."; + } + } else if (opt_key != key || value != written_ini[key]) { + std::cout << " => legacy convert:'" << opt_key << " = " << value << "'"; } - } else if (opt_key != key || value != written_ini[key]) { - std::cout << " => legacy convert:'" << opt_key << " = " << value << "'"; + std::cout << "\n"; } - std::cout << "\n"; } } - diff_keys = config_diffs(preset_to_load->config_before_legacy_composite, preset_to_load->config_before_prusa); - std::cout << " ===== list of settings converted from prusa: " << diff_keys.size() << " ===== \n"; - for (const std::string &key : diff_keys) { - std::cout << "'" << key << " = " << (preset_to_load->config_before_prusa.option(key) ? preset_to_load->config_before_prusa.option(key)->serialize() : "") << "'"; - std::cout << "=> '" << key << " = " << (preset_to_load->config_before_legacy_composite.option(key) ? preset_to_load->config_before_legacy_composite.option(key)->serialize() : "") << "'"; - std::cout << "\n"; - } - for (auto &entry : opts_prusa_transformed) { - auto &old_pair = entry.first; - auto &vector = entry.second; - std::cout << "'" << old_pair.first << " = " << old_pair.second << "'"; - if (vector.size() == 1) { - std::cout << "=> '" << vector.front().first << " = " << vector.front().second << "'"; - std::cout << "\n"; - } else { - std::cout << "=> [\n"; - for (auto &new_pair : vector) { - std::cout << " '" << new_pair.first << " = " << new_pair.second << "'\n"; + { + std::vector diff_keys = config_diffs(preset_to_load->config_before_legacy_composite, preset_to_load->config_before_prusa); + count = diff_keys.size() + opts_prusa_transformed.size(); + if (count > 0){ + std::cout << " ===== list of settings converted from prusa: " << diff_keys.size() << " ===== \n"; + for (const std::string &key : diff_keys) { + std::cout << "'" << key << " = " << (preset_to_load->config_before_prusa.option(key) ? preset_to_load->config_before_prusa.opt_serialize(key) : "") << "'"; + std::cout << "=> '" << key << " = " << (preset_to_load->config_before_legacy_composite.option(key) ? preset_to_load->config_before_legacy_composite.opt_serialize(key) : "") << "'"; + std::cout << "\n"; + } + for (auto &entry : opts_prusa_transformed) { + auto &old_pair = entry.first; + auto &vector = entry.second; + std::cout << "'" << old_pair.first << " = " << old_pair.second << "'"; + if (vector.size() == 1) { + std::cout << "=> '" << vector.front().first << " = " << vector.front().second << "'"; + std::cout << "\n"; + } else { + std::cout << "=> [\n"; + for (auto &new_pair : vector) { + std::cout << " '" << new_pair.first << " = " << new_pair.second << "'\n"; + } + std::cout<<" ]\n"; + } } - std::cout<<" ]\n"; } - } - diff_keys = config_diffs(preset_to_load->config, preset_to_load->config_before_legacy_composite); - std::cout << " ===== list of finals changes need to move from an old setting: " << diff_keys.size() << " ===== \n"; - for (const std::string &key : diff_keys) { - std::cout << "'" << key << " = " << (preset_to_load->config_before_legacy_composite.option(key) ? preset_to_load->config_before_legacy_composite.option(key)->serialize() : "") << "'"; - std::cout << "=> '" << key << " = " << (preset_to_load->config.option(key) ? preset_to_load->config.option(key)->serialize() : "") << "'"; - std::cout << "\n"; + { + std::vector diff_keys = config_diffs(preset_to_load->config, preset_to_load->config_before_legacy_composite); + if (diff_keys.size() > 0) { + std::cout << " ===== list of finals changes need to move from an old setting: " << diff_keys.size() << " ===== \n"; + for (const std::string &key : diff_keys) { + std::cout << "'" << key << " = " << (preset_to_load->config_before_legacy_composite.option(key) ? preset_to_load->config_before_legacy_composite.opt_serialize(key) : "") << "'"; + std::cout << "=> '" << key << " = " << (preset_to_load->config.option(key) ? preset_to_load->config.opt_serialize(key) : "") << "'"; + std::cout << "\n"; + } + } } - if (!preset_to_load->config_before_legacy_composite.option("print_version")) { - std::cout << "'print_version = '"; + if (preset_to_load->config_before_legacy_composite.option("print_version") && + (preset_to_load->config_before_legacy_composite.option("print_version")->serialize() != + ConfigOptionStringVersion().serialize())) { + std::cout << "'print_version = " + << preset_to_load->config_before_legacy_composite.option("print_version")->serialize() << "'"; std::cout << "=> 'print_version = " << ConfigOptionStringVersion().serialize() << "'"; std::cout << "\n"; } @@ -539,9 +622,16 @@ std::vector get_configbundle_hierarchy(boost::property_tree::ptree &tre // Find the presets, store them into a std::map, addressed by their names. std::set presets; std::string group_name_preset = group_name + ":"; - for (auto §ion : tree) - if (boost::starts_with(section.first, group_name_preset) && section.first.size() > group_name_preset.size()) - presets.emplace(std::make_shared(group_name, section.first.substr(group_name_preset.size()), §ion.second)); + size_t section_idx = 0; + for (auto §ion : tree) { + section_idx++; + if (boost::starts_with(section.first, group_name_preset) && section.first.size() > group_name_preset.size()) { + PrstPtr preset = std::make_shared(group_name, section.first.substr(group_name_preset.size()), §ion.second); + preset->section_idx = section_idx; + presets.emplace(preset); + } + + } // Fill in the "inherits" and "parent_of" members, report invalid inheritance fields. for (const PrstPtr &prst : presets) { // Parse the list of comma separated values, possibly enclosed in quotes. @@ -553,9 +643,10 @@ std::vector get_configbundle_hierarchy(boost::property_tree::ptree &tre for (const std::string &node_name : inherits_names) { auto temp = std::make_shared(group_name, node_name, nullptr); auto it = presets.find(temp); - if (it == presets.end()) - BOOST_LOG_TRIVIAL(error) << "flatten_configbundle_hierarchy: The preset " << prst->name << " inherits an unknown preset \"" << node_name << "\""; - else { + if (it == presets.end()) { + BOOST_LOG_TRIVIAL(error) << "flatten_configbundle_hierarchy: The preset " << prst->name + << " inherits an unknown preset \"" << node_name << "\""; + } else { inherits_nodes.push_back(*it); inherits_nodes.back()->parent_of.push_back(prst); } @@ -666,6 +757,138 @@ void update_preset(const VendorProfile &vendor_profile, PrstPtr preset_to_update } +void add_common_deps(std::vector &ordered_presets) { + std::vector commons; + std::vector combined; + // update roots + // get roots with "common" name + // get other "combined" roots + for (PrstPtr &prstptr : ordered_presets) { + if (prstptr->inherits.empty()) { + if (prstptr->parent_of.empty() && !(prstptr->name.front() == '*' && prstptr->name.back() == '*')) { + commons.push_back(prstptr); + prstptr->write_defaults = true; + prstptr->has_all_values = true; + } else { + combined.push_back(prstptr); + prstptr->write_defaults = false; + prstptr->has_all_values = false; + } + } else { + // unless inherit , really set in next loop + prstptr->write_defaults = false; + prstptr->has_all_values = false; + } + } +update_write_defaults:; + // update every intermediate node from it parents. + bool has_change = true; + while (has_change) { + has_change = false; + for (PrstPtr &prstptr : ordered_presets) { + if (!prstptr->inherits.empty() && !prstptr->has_all_values) { + for (PrstPtr &parent : prstptr->inherits) { + if (parent->has_all_values) { + prstptr->has_all_values = true; + has_change = true; + break; + } + } + } + } + } + // update leafs + // put any "combined" root as "common" if they have at least one occurence when they don't combine with a "common" one + std::map> associated_with; + for (PrstPtr &prstptr : ordered_presets) { + if (prstptr->parent_of.empty() && !prstptr->inherits.empty() && !prstptr->has_all_values) { + if (prstptr->name.front() == '*' && prstptr->name.back() == '*') { + // ignore, it will emit a warning in the loop after. not here because we can iterate this loop multiple times. + continue; + } + // get the root of first parent, and set the outmost parent to "write_defaults" + PrstPtr root = prstptr->inherits.front(); + while (!root->inherits.empty()) { + root = root->inherits.front(); + } + { + std::cout << "Preset " << root->section_name << ": '" << root->name + << "' needs all default options because of the chain '"; + PrstPtr root_chain = prstptr; + std::cout << prstptr->name; + while (!root_chain->inherits.empty()) { + root_chain = root_chain->inherits.front(); + std::cout << "' -> '" << root_chain->name; + } + std::cout << "'\n"; + } + root->write_defaults = true; + root->has_all_values = true; + // redo update + goto update_write_defaults; + } + } + + + for (PrstPtr &prstptr : ordered_presets) { + if (prstptr->parent_of.empty() && !prstptr->inherits.empty() && !prstptr->has_all_values) { + if (prstptr->name.front() == '*' && prstptr->name.back() == '*') { + BOOST_LOG_TRIVIAL(warning) << "The preset " << prstptr->section_name << ":" << prstptr->name + << " isn't inherited by anything, hence is useless."; + } + } + } + //ensure an inherit doesn't erase evrything + for (PrstPtr &prstptr : ordered_presets) { + if (!prstptr->inherits.empty()) { + if ((prstptr->has_all_values || prstptr->parent_of.empty()) && + !prstptr->inherits.front()->has_all_values) { + BOOST_LOG_TRIVIAL(warning) << "The preset " << prstptr->section_name << ":" << prstptr->name + << " inherits (first) a preset \"" << prstptr->inherits.front()->name + << " that doesn't define every setting, it's not recommended.\""; + //assert(false); + } + for (size_t parent_idx = 1; parent_idx < prstptr->inherits.size(); ++parent_idx) { + PrstPtr &parent = prstptr->inherits[parent_idx]; + if (parent->has_all_values) { + std::cout << "Looking at " << prstptr->section_name << ": " << prstptr->name << "\n"; + if (prstptr->inherits.front()->has_all_values) { + std::cout << "first inherited preset " << prstptr->inherits.front()->name + << " need all default options because of the chain "; + PrstPtr root_chain = prstptr->inherits.front(); + std::cout << prstptr->name; + while (!root_chain->inherits.empty()) { + root_chain = root_chain->inherits.front(); + std::cout << "->" << root_chain->name; + } + std::cout << "\n"; + } else { + std::cout << "first inherited preset " << prstptr->inherits.front()->name + << " don't need all default options because of the chain.\n"; + } + { + std::cout << (parent_idx+1) << "-th inherited preset " << prstptr->inherits[parent_idx]->name + << " need all default options because of the chain "; + PrstPtr root_chain = prstptr->inherits[parent_idx]; + std::cout << prstptr->inherits[parent_idx]->name; + while (!root_chain->inherits.empty()) { + root_chain = root_chain->inherits.front(); + std::cout << "->" << root_chain->name; + } + std::cout << "\n"; + } + BOOST_LOG_TRIVIAL(error) + << "The preset " << prstptr->section_name << ":" << prstptr->name << " inherits a preset \"" + << prstptr->inherits.front()->name + << " that define every settings, erasing the previous inheritance(s)!\""; + //assert(false); + } + } + } + } + +} + std::pair> load_sections(const std::string &path) { // 1) Read the complete config file into a boost::property_tree. @@ -695,6 +918,16 @@ std::pair> load_sections(const std::string & return {}; } + // if there's no technologies field, check if it's not sla + auto vendor_section_it = tree.find("vendor"); + const std::string technologies_field = vendor_section_it->second.get("technologies", ""); + if (technologies_field.empty()) { + assert(vp.technologies.size() == 1 && vp.technologies.front() == PrinterTechnology::ptFFF); + if (vp.name.find("SLA") != std::string::npos) { + vp.technologies.front() = PrinterTechnology::ptSLA; + } + } + cout<<"Vendor profile '"<> load_sections(const std::string & for(auto var : model.variants) cout<<" '"< ordered_presets_print = get_configbundle_hierarchy(tree, "print"); + // also try to use a common config as common even if it's not said. (like when we combine 0.2 nozzle always with common) + add_common_deps(ordered_presets_print); // Apply the dependencies in their topological ordering. for (PrstPtr &prst : ordered_presets_print) { update_preset(vp, prst); } std::vector ordered_presets_sla_print = get_configbundle_hierarchy(tree, "sla_print"); + add_common_deps(ordered_presets_sla_print); // Apply the dependencies in their topological ordering. for (PrstPtr &prst : ordered_presets_sla_print) { update_preset(vp, prst); } std::vector ordered_presets_printer = get_configbundle_hierarchy(tree, "printer"); + add_common_deps(ordered_presets_printer); // Apply the dependencies in their topological ordering. for (PrstPtr &prst : ordered_presets_printer) { update_preset(vp, prst); } std::vector ordered_presets_filament = get_configbundle_hierarchy(tree, "filament"); + add_common_deps(ordered_presets_filament); // Apply the dependencies in their topological ordering. for (PrstPtr &prst : ordered_presets_filament) { update_preset(vp, prst); } std::vector ordered_presets_material = get_configbundle_hierarchy(tree, "material"); + add_common_deps(ordered_presets_material); // Apply the dependencies in their topological ordering. for (PrstPtr &prst : ordered_presets_material) { update_preset(vp, prst); } //load_preset(vp, std::string section_name, boost::property_tree::ptree section_data) + std::vector all; append(all, ordered_presets_print); append(all, ordered_presets_sla_print); append(all, ordered_presets_printer); append(all, ordered_presets_filament); append(all, ordered_presets_material); + std::sort(all.begin(), all.end(), [](const PrstPtr &p1, const PrstPtr &p2) { + return p1->section_idx < p2->section_idx; + }); return {vp, all}; } -void save(const std::string &file, VendorProfile &vp, std::vector &presets, const Semver &ver_susi) +void save(boost::nowide::ofstream &c, VendorProfile &vp, std::vector &presets, const Semver &ver_susi) { - boost::nowide::ofstream c; - c.open(file, std::ios::out | std::ios::trunc); - c << "# " << Slic3r::header_slic3r_generated() << std::endl; - c << "# Generated to " SLIC3R_APP_NAME; c << "\n"; c << "[vendor]\n"; @@ -812,15 +1053,54 @@ void save(const std::string &file, VendorProfile &vp, std::vector &pres c << "\n"; } + //don't print special fields if empty + auto is_printable = [](const DynamicPrintConfig &config, const std::string &key) { + if(!config.has(key)) return false; + if(key == "printer_model") return false; + // also erase things that can't have any default value + if (std::set{"tool_name", "print_settings_modified", "filament_settings_modified", + "sla_print_settings_modified", "sla_material_settings_modified", + "printer_settings_modified", "printer_vendor", "printer_notes", "printer_model", + "printer_variant", "default_print_profile", "default_filament_profile", + "default_sla_print_profile", "default_sla_material_profile", "host_type", + "print_host", "printhost_apikey", "printhost_cafile", "printhost_client_cert", + "printhost_client_cert_password", "printhost_port", "printhost_authorization_type", + // HTTP digest authentization (RFC 2617) + "printhost_user", "printhost_password", "printhost_ssl_ignore_revoke"} + .count(key) > 0) { + if (config.opt_serialize(key).empty()) { + return false; + } + } + return true; + }; + // config presets sections for (PrstPtr preset : presets) { + bool check_preset_debug = false; + if (preset->name.find("0.05mm 0.25nozzle V2") != std::string::npos) { + check_preset_debug = true; + } + if (preset->deleted) { + continue; + } c << "\n"; if (!preset->name_with_template.empty()) { c << "#name_with_template = " << preset->name_with_template << "\n"; } + assert(preset->has_all_values || !preset->parent_of.empty() || + (preset->name.front() == '*' && preset->name.back() == '*')); + if((preset->name.front() == '*' && preset->name.back() == '*') && preset->parent_of.empty()){ + if (preset->has_all_values) { + c << "# unused (common) preset\n"; + } else { + c << "# unused (flavor) preset\n"; + } + } c << "[" << preset->section_name << ":" << preset->name << "]\n"; - // inherits + // inherits? if (!preset->inherits.empty()) { + assert(!preset->write_defaults); c << "inherits = "; DynamicPrintConfig config_inherit; for (std::shared_ptr &inherit_preset : preset->inherits) { @@ -828,73 +1108,88 @@ void save(const std::string &file, VendorProfile &vp, std::vector &pres if (inherit_preset != preset->inherits.front()) c <<"; "; c << inherit_preset->name; - for (std::string &key : inherit_preset->config.keys()) { - config_inherit.set_key_value(key, inherit_preset->config.option(key)->clone()); + // has_all_values -> inherit a config with all settings, we can erase evrything + // !has_all_values -> only erase the diff + if (inherit_preset->has_all_values) { + for (std::string &key : inherit_preset->config.keys()) { + config_inherit.set_key_value(key, inherit_preset->config.option(key)->clone()); + } + } else { + inherit_preset->apply_current_diff(config_inherit); } } c << "\n"; - //on ne met que le diff - t_config_option_keys diff = preset->config.diff(config_inherit); - for (const std::string &opt_key : diff) - c << opt_key << " = " << preset->config.opt_serialize(opt_key) << "\n"; + // print onlydiff + t_config_option_keys diff = preset->config.diff(config_inherit, false); + //print printer_model first + if (std::find(diff.begin(), diff.end(), "printer_model") != diff.end() && + !preset->config.opt_serialize("printer_model").empty()) { + c << "printer_model" << " = " << preset->config.opt_serialize("printer_model") << "\n"; + } + //then the others + for (const std::string &opt_key : diff) { + if (is_printable( preset->config, opt_key)) { + c << opt_key << " = " << preset->config.opt_serialize(opt_key) << "\n"; + } + } } else { - for (const std::string &opt_key : preset->config.keys()) - c << opt_key << " = " << preset->config.opt_serialize(opt_key) << "\n"; + //print printer_model first + if (preset->config.has("printer_model") && !preset->config.opt_serialize("printer_model").empty()) { + c << "printer_model" << " = " << preset->config.opt_serialize("printer_model") << "\n"; + } + //then the others + if (preset->write_defaults) { + for (const std::string &opt_key : preset->config.keys()) { + if (is_printable( preset->config, opt_key)) { + c << opt_key << " = " << preset->config.opt_serialize(opt_key) << "\n"; + } + } + } else { + for (const std::string &opt_key : preset->config_diff.keys()) { + if (is_printable( preset->config_diff, opt_key)) { + c << opt_key << " = " << preset->config.opt_serialize(opt_key) << "\n"; + } + } + } } } - c.close(); } -int main(int argc, char const *argv[]) -{ - Semver slic3r_2_7_61("2.7.61-alpha+UNKNOWN"); - Semver slic3r_2_7_alpha("2.7-alpha+UNKNOWN"); - Semver slic3r_2_6_1_rc2("2.6.1-rc2"); - Semver slic3r_2_6_2_alpha0("2.6.2-alpha0"); - Semver slic3r_2_7_0_alpha2("2.7.0-alpha2"); - Semver slic3r_2_7_0_beta1("2.7.0-beta1"); - - auto test = [](Semver& s1, Semver& s2){ - std::cout << ((s1 == s2) ? "equal" : ((s1 < s2) ? "lower" : "higher")) << "\n"; }; - - test(slic3r_2_6_1_rc2,slic3r_2_6_2_alpha0); - test(slic3r_2_6_2_alpha0,slic3r_2_7_0_alpha2); - test(slic3r_2_7_0_alpha2,slic3r_2_7_0_beta1); - std::cout<<"test 2.7-alpha+UNKNOWN\n"; - test(slic3r_2_7_alpha,slic3r_2_6_1_rc2); - test(slic3r_2_7_alpha,slic3r_2_6_2_alpha0); - test(slic3r_2_7_alpha,slic3r_2_7_0_alpha2); - test(slic3r_2_7_alpha,slic3r_2_7_0_beta1); - test(slic3r_2_7_alpha,slic3r_2_7_61); - std::cout<<"2.7.61-alpha+UNKNOWN\n"; - test(slic3r_2_7_61,slic3r_2_6_1_rc2); - test(slic3r_2_7_61,slic3r_2_6_2_alpha0); - test(slic3r_2_7_61,slic3r_2_7_0_alpha2); - test(slic3r_2_7_61,slic3r_2_7_0_beta1); - - - clipboardxx::clipboard clipboard; - if (argc != 2) { - std::cout<<"usage: test_config \"path/to/vendor/config.ini\"\n"; - return 0; - } - std::string path_str = argv[1]; - if(path_str.front() == '\"' && path_str.back() == '\"') - path_str = path_str.substr(1,path_str.size()-2); - boost::filesystem::path path_in(path_str); +void convert_config(boost::filesystem::path &path_in, boost::filesystem::path &path_out){ + //if(path_in.string().find("Tri") == std::string::npos) return; + //Semver slic3r_2_7_61("2.7.61-alpha+UNKNOWN"); + //Semver slic3r_2_7_alpha("2.7-alpha+UNKNOWN"); + //Semver slic3r_2_6_1_rc2("2.6.1-rc2"); + //Semver slic3r_2_6_2_alpha0("2.6.2-alpha0"); + //Semver slic3r_2_7_0_alpha2("2.7.0-alpha2"); + //Semver slic3r_2_7_0_beta1("2.7.0-beta1"); + + //auto test = [](Semver& s1, Semver& s2){ + // std::cout << ((s1 == s2) ? "equal" : ((s1 < s2) ? "lower" : "higher")) << "\n"; }; + // + //test(slic3r_2_6_1_rc2,slic3r_2_6_2_alpha0); + //test(slic3r_2_6_2_alpha0,slic3r_2_7_0_alpha2); + //test(slic3r_2_7_0_alpha2,slic3r_2_7_0_beta1); + //std::cout<<"test 2.7-alpha+UNKNOWN\n"; + //test(slic3r_2_7_alpha,slic3r_2_6_1_rc2); + //test(slic3r_2_7_alpha,slic3r_2_6_2_alpha0); + //test(slic3r_2_7_alpha,slic3r_2_7_0_alpha2); + //test(slic3r_2_7_alpha,slic3r_2_7_0_beta1); + //test(slic3r_2_7_alpha,slic3r_2_7_61); + //std::cout<<"2.7.61-alpha+UNKNOWN\n"; + //test(slic3r_2_7_61,slic3r_2_6_1_rc2); + //test(slic3r_2_7_61,slic3r_2_6_2_alpha0); + //test(slic3r_2_7_61,slic3r_2_7_0_alpha2); + //test(slic3r_2_7_61,slic3r_2_7_0_beta1); + + //PresetsConfigSubstitutions substitutions; //std::pair res = // this->load_configbundle(path_str, PresetBundle::LoadSystem, ForwardCompatibilitySubstitutionRule::); - auto [vp, presets] = load_sections(path_str); + auto [vp, presets] = load_sections(path_in.string()); // get path & name - boost::filesystem::path path_out = path_in.parent_path(); - path_out /= "converted"; - boost::filesystem::create_directory(path_out); - path_out /= path_in.filename(); - std::cout< Date: Wed, 5 Mar 2025 18:27:31 +0100 Subject: [PATCH 7/7] new configs --- resources/profiles | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/profiles b/resources/profiles index ca25c7ec55d..26b8957b31f 160000 --- a/resources/profiles +++ b/resources/profiles @@ -1 +1 @@ -Subproject commit ca25c7ec55dcc6073da61e39692c321cdb6497dc +Subproject commit 26b8957b31ff40ceb43f0b09b16135ab1b8142fe