Implemented inheritance of profiles inside a config bundle.

Updated the Prusa's presets to match the initial flat config bundle.
This commit is contained in:
bubnikv 2018-03-07 16:48:28 +01:00
parent 77e142553a
commit f0fde26295
2 changed files with 161 additions and 39 deletions

View File

@ -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*]

View File

@ -14,6 +14,7 @@
#include <boost/property_tree/ini_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/locale.hpp>
#include <boost/log/trivial.hpp>
#include <wx/dcmemory.h>
#include <wx/image.h>
@ -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<pt::ptree::key_type, pt::ptree> 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<Prst*> inherits;
// Link to the presets, for which this preset is a direct parent.
std::vector<Prst*> 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<Prst> presets;
std::string group_name_preset = group_name + ":";
for (auto &section : 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()), &section.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<std::string> inherits_names;
if (Slic3r::unescape_strings_cstyle(prst.node->get<std::string>("inherits", ""), inherits_names)) {
// Resolve the inheritance by name.
std::vector<Prst*> &inherits_nodes = const_cast<Prst&>(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<Prst*>(&(*it)));
inherits_nodes.back()->parent_of.emplace_back(const_cast<Prst*>(&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<pt::ptree*>(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<Prst*> sorted;
{
// Initialize S with the set of all nodes with no incoming edge.
std::deque<Prst*> S;
for (const Prst &prst : presets)
if (prst.inherits.empty())
S.emplace_back(const_cast<Prst*>(&prst));
else
const_cast<Prst*>(&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<std::string> loaded_prints;