diff --git a/resources/profiles/Original Prusa i3 MK2, MK2S, MK2MM and MK3.ini b/resources/profiles/Original Prusa i3 MK2, MK2S, MK2MM and MK3.ini index 17c8bfcce..caaada2ea 100644 --- a/resources/profiles/Original Prusa i3 MK2, MK2S, MK2MM and MK3.ini +++ b/resources/profiles/Original Prusa i3 MK2, MK2S, MK2MM and MK3.ini @@ -32,6 +32,7 @@ gap_fill_speed = 40 gcode_comments = 0 infill_every_layers = 1 infill_extruder = 1 +infill_extrusion_width = 0.45 infill_first = 0 infill_only_where_needed = 0 infill_overlap = 25% @@ -81,6 +82,7 @@ support_material_with_sheath = 0 support_material_xy_spacing = 60% thin_walls = 0 top_infill_extrusion_width = 0.45 +top_solid_infill_speed = 40 travel_speed = 180 wipe_tower = 0 wipe_tower_per_color_wipe = 15 @@ -132,6 +134,7 @@ inherits = *0.05mm* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.25 and num_extruders==1 external_perimeter_extrusion_width = 0 extrusion_width = 0.28 +fill_density = 20% first_layer_extrusion_width = 0.3 infill_extrusion_width = 0 infill_speed = 20 @@ -171,10 +174,10 @@ infill_speed = 60 perimeter_speed = 50 perimeters = 3 solid_infill_speed = 50 -top_solid_infill_speed = 40 [print:0.10mm DETAIL MK3] inherits = *0.10mm* +bridge_flow_ratio = 0.8 bridge_speed = 30 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ external_perimeter_speed = 35 @@ -190,35 +193,30 @@ top_solid_infill_speed = 50 [print:0.10mm DETAIL 0.25 nozzle] inherits = *0.10mm* -bottom_solid_layers = 10 -bridge_acceleration = 300 -compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.25 and num_extruders==1 -default_acceleration = 500 -external_perimeter_extrusion_width = 0 +bridge_acceleration = 600 +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.25 external_perimeter_speed = 20 -extrusion_width = 0.28 -first_layer_acceleration = 500 -first_layer_extrusion_width = 0.3 -gap_fill_speed = 20 -infill_acceleration = 800 -infill_extrusion_width = 0 -infill_speed = 20 -perimeter_acceleration = 300 -perimeter_extrusion_width = 0 -perimeter_speed = 20 +external_perimeter_extrusion_width = 0.25 +extrusion_width = 0.25 +fill_density = 15% +first_layer_extrusion_width = 0.25 +infill_acceleration = 1600 +infill_extrusion_width = 0.25 +infill_speed = 40 +perimeter_acceleration = 600 +perimeter_extrusion_width = 0.25 +perimeter_speed = 25 perimeters = 4 small_perimeter_speed = 10 -solid_infill_extrusion_width = 0 -solid_infill_speed = 20 +solid_infill_extrusion_width = 0.25 +solid_infill_speed = 40 support_material_extrusion_width = 0.18 support_material_interface_layers = 0 support_material_interface_spacing = 0.15 support_material_spacing = 1 -support_material_speed = 20 support_material_xy_spacing = 150% -top_infill_extrusion_width = 0 -top_solid_infill_speed = 20 -top_solid_layers = 15 +top_infill_extrusion_width = 0.25 +top_solid_infill_speed = 30 [print:*0.15mm*] inherits = *common* @@ -235,7 +233,6 @@ support_material_contact_distance = 0.15 support_material_interface_spacing = 0.2 support_material_spacing = 2 top_infill_extrusion_width = 0.4 -top_solid_infill_speed = 40 top_solid_layers = 7 [print:0.15mm 100mms Linear Advance] @@ -257,6 +254,7 @@ top_solid_layers = 5 [print:0.15mm OPTIMAL] inherits = *0.15mm* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 +top_infill_extrusion_width = 0.45 [print:0.15mm OPTIMAL 0.25 nozzle] inherits = *0.15mm* @@ -315,14 +313,12 @@ wipe_tower = 1 [print:0.15mm OPTIMAL SOLUBLE FULL] inherits = *0.15mm* -bottom_solid_layers = 4 -bridge_flow_ratio = 0.95 +bottom_solid_layers = 5 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 -external_perimeter_speed = 30 +external_perimeter_speed = 25 notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder overhangs = 1 perimeter_speed = 40 -perimeters = 2 skirts = 0 solid_infill_speed = 40 support_material = 1 @@ -334,10 +330,11 @@ support_material_interface_spacing = 0.1 support_material_synchronize_layers = 1 support_material_threshold = 80 support_material_with_sheath = 1 -support_material_xy_spacing = 120% +support_material_xy_spacing = 60% +top_infill_extrusion_width = 0.45 top_solid_infill_speed = 30 -top_solid_layers = 5 wipe_tower = 1 +wipe_tower_per_color_wipe = 20 [print:0.15mm OPTIMAL SOLUBLE INTERFACE] inherits = 0.15mm OPTIMAL SOLUBLE FULL @@ -345,7 +342,7 @@ notes = Set your solluble extruder in Multiple Extruders > Support material/raf support_material_extruder = 0 support_material_interface_layers = 3 support_material_with_sheath = 0 -wipe_tower_per_color_wipe = 20 +support_material_xy_spacing = 120% [print:*0.20mm*] inherits = *common* @@ -436,6 +433,7 @@ inherits = 0.20mm NORMAL SOLUBLE FULL notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder support_material_extruder = 0 support_material_interface_layers = 3 +support_material_with_sheath = 0 [print:*0.35mm*] inherits = *common* @@ -448,10 +446,10 @@ infill_extrusion_width = 0.75 infill_speed = 60 layer_height = 0.35 perimeter_acceleration = 800 -perimeter_extrusion_width = 0.43 +perimeter_extrusion_width = 0.65 perimeter_speed = 50 perimeters = 2 -solid_infill_extrusion_width = 0.7 +solid_infill_extrusion_width = 0.65 solid_infill_speed = 60 support_material_contact_distance = 0.15 support_material_interface_spacing = 0.2 @@ -461,27 +459,28 @@ top_solid_layers = 4 wipe_tower = 1 [print:0.35mm FAST] -inherits = *common* +inherits = *0.35mm* bridge_flow_ratio = 0.95 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 +first_layer_extrusion_width = 0.42 infill_extrusion_width = 0.7 -perimeter_extrusion_width = 0.65 +perimeter_extrusion_width = 0.43 solid_infill_extrusion_width = 0.7 top_infill_extrusion_width = 0.43 [print:0.35mm FAST 0.6 nozzle] -inherits = *common* +inherits = *0.35mm* bottom_solid_layers = 7 -compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.61 +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 +external_perimeter_extrusion_width = 0.61 extrusion_width = 0.67 first_layer_extrusion_width = 0.65 perimeters = 3 -solid_infill_extrusion_width = 0.65 top_infill_extrusion_width = 0.6 top_solid_layers = 9 [print:0.35mm FAST sol full 0.6 nozzle] -inherits = *common* +inherits = *0.35mm* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 and num_extruders>1 external_perimeter_speed = 30 extrusion_width = 0.67 @@ -500,11 +499,12 @@ support_material_synchronize_layers = 1 support_material_threshold = 80 support_material_xy_spacing = 120% top_infill_extrusion_width = 0.57 +wipe_tower_per_color_wipe = 20 [print:0.35mm FAST sol int 0.6 nozzle] inherits = 0.35mm FAST sol full 0.6 nozzle support_material_extruder = 0 -support_material_interface_layers = 0 +support_material_interface_layers = 2 support_material_xy_spacing = 150% [filament:*common*] diff --git a/xs/src/slic3r/GUI/PresetBundle.cpp b/xs/src/slic3r/GUI/PresetBundle.cpp index 3b4bf097f..bf79c6562 100644 --- a/xs/src/slic3r/GUI/PresetBundle.cpp +++ b/xs/src/slic3r/GUI/PresetBundle.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -474,6 +475,125 @@ void PresetBundle::load_config_file_config_bundle(const std::string &path, const this->update_compatible_with_printer(false); } +// Process the Config Bundle loaded as a Boost property tree. +// For each print, filament and printer preset (group defined by group_name), apply the inherited presets. +// The presets starting with '*' are considered non-terminal and they are +// removed through the flattening process by this function. +// This function will never fail, but it will produce error messages through boost::log. +static void flatten_configbundle_hierarchy(boost::property_tree::ptree &tree, const std::string &group_name) +{ + namespace pt = boost::property_tree; + + typedef std::pair ptree_child_type; + + // 1) For the group given by group_name, initialize the presets. + struct Prst { + Prst(const std::string &name, pt::ptree *node) : name(name), node(node) {} + // Name of this preset. If the name starts with '*', it is an intermediate preset, + // which will not make it into the result. + const std::string name; + // Link to the source boost property tree node, owned by tree. + pt::ptree *node; + // 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; } + }; + // 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(section.first.substr(group_name_preset.size()), §ion.second); + // Fill in the "inherits" and "parent_of" members, report invalid inheritance fields. + for (const Prst &prst : presets) { + // Parse the list of comma separated values, possibly enclosed in quotes. + std::vector inherits_names; + if (Slic3r::unescape_strings_cstyle(prst.node->get("inherits", ""), inherits_names)) { + // Resolve the inheritance by name. + std::vector &inherits_nodes = const_cast(prst).inherits; + for (const std::string &node_name : inherits_names) { + auto it = presets.find(Prst(node_name, nullptr)); + if (it == presets.end()) + BOOST_LOG_TRIVIAL(error) << "flatten_configbundle_hierarchy: The preset " << prst.name << " inherits an unknown preset \"" << node_name << "\""; + else { + inherits_nodes.emplace_back(const_cast(&(*it))); + inherits_nodes.back()->parent_of.emplace_back(const_cast(&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 the config bundle. + const_cast(prst.node)->erase("inherits"); + } + + // 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 Prst &prst : presets) + if (prst.inherits.empty()) + S.emplace_back(const_cast(&prst)); + else + const_cast(&prst)->num_incoming_edges_left = prst.inherits.size(); + while (! S.empty()) { + Prst *n = S.front(); + S.pop_front(); + sorted.emplace_back(n); + for (Prst *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.emplace_back(m); + } + } + } + if (sorted.size() < presets.size()) { + for (const Prst &prst : presets) + if (prst.num_incoming_edges_left) + BOOST_LOG_TRIVIAL(error) << "flatten_configbundle_hierarchy: The preset " << prst.name << " has cyclic dependencies"; + } + } + + // Apply the dependencies in their topological ordering. + for (Prst *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 (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; + } +} + +static void flatten_configbundle_hierarchy(boost::property_tree::ptree &tree) +{ + flatten_configbundle_hierarchy(tree, "print"); + flatten_configbundle_hierarchy(tree, "filament"); + flatten_configbundle_hierarchy(tree, "printer"); +} + // Load a config bundle file, into presets and store the loaded presets into separate files // of the local configuration directory. size_t PresetBundle::load_configbundle(const std::string &path, unsigned int flags) @@ -486,6 +606,8 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla pt::ptree tree; boost::nowide::ifstream ifs(path); pt::read_ini(ifs, tree); + // Flatten the config bundle by applying the inheritance rules. Internal profiles (with names starting with '*') are removed. + flatten_configbundle_hierarchy(tree); // 2) Parse the property_tree, extract the active preset names and the profiles, save them into local config files. std::vector loaded_prints;