diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 192ccda99..5acda3a98 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -469,7 +469,7 @@ bool GCode::do_export(FILE *file, Print &print) m_cooling_buffer->set_current_extruder(initial_extruder_id); // Disable fan. - if (print.config.cooling.get_at(initial_extruder_id) && print.config.disable_fan_first_layers.get_at(initial_extruder_id)) + if (! print.config.cooling.get_at(initial_extruder_id) || print.config.disable_fan_first_layers.get_at(initial_extruder_id)) write(file, m_writer.set_fan(0, true)); // Set bed temperature if the start G-code does not contain any bed temp control G-codes. @@ -487,10 +487,12 @@ bool GCode::do_export(FILE *file, Print &print) this->_print_first_layer_extruder_temperatures(file, print, initial_extruder_id, false); // Let the start-up script prime the 1st printing tool. m_placeholder_parser.set("initial_tool", initial_extruder_id); - writeln(file, m_placeholder_parser.process(print.config.start_gcode.value)); + m_placeholder_parser.set("initial_extruder", initial_extruder_id); + m_placeholder_parser.set("current_extruder", initial_extruder_id); + writeln(file, m_placeholder_parser.process(print.config.start_gcode.value, initial_extruder_id)); // Process filament-specific gcode in extruder order. for (const std::string &start_gcode : print.config.start_filament_gcode.values) - writeln(file, m_placeholder_parser.process(start_gcode)); + writeln(file, m_placeholder_parser.process(start_gcode, &start_gcode - &print.config.start_filament_gcode.values.front())); this->_print_first_layer_extruder_temperatures(file, print, initial_extruder_id, true); // Set other general things. @@ -636,8 +638,8 @@ bool GCode::do_export(FILE *file, Print &print) write(file, m_writer.set_fan(false)); // Process filament-specific gcode in extruder order. for (const std::string &end_gcode : print.config.end_filament_gcode.values) - writeln(file, m_placeholder_parser.process(end_gcode)); - writeln(file, m_placeholder_parser.process(print.config.end_gcode)); + writeln(file, m_placeholder_parser.process(end_gcode, &end_gcode - &print.config.end_filament_gcode.values.front())); + writeln(file, m_placeholder_parser.process(print.config.end_gcode, m_writer.extruder()->id())); write(file, m_writer.update_progress(m_layer_count, m_layer_count, true)); // 100% write(file, m_writer.postamble()); @@ -800,7 +802,7 @@ void GCode::process_layer( PlaceholderParser pp(m_placeholder_parser); pp.set("layer_num", m_layer_index + 1); pp.set("layer_z", print_z); - gcode += pp.process(print.config.before_layer_gcode.value) + "\n"; + gcode += pp.process(print.config.before_layer_gcode.value, m_writer.extruder()->id()) + "\n"; } gcode += this->change_layer(print_z); // this will increase m_layer_index m_layer = &layer; @@ -808,7 +810,7 @@ void GCode::process_layer( PlaceholderParser pp(m_placeholder_parser); pp.set("layer_num", m_layer_index); pp.set("layer_z", print_z); - gcode += pp.process(print.config.layer_gcode.value) + "\n"; + gcode += pp.process(print.config.layer_gcode.value, m_writer.extruder()->id()) + "\n"; } if (! first_layer && ! m_second_layer_things_done) { @@ -2004,7 +2006,7 @@ std::string GCode::set_extruder(unsigned int extruder_id) PlaceholderParser pp = m_placeholder_parser; pp.set("previous_extruder", m_writer.extruder()->id()); pp.set("next_extruder", extruder_id); - gcode += pp.process(m_config.toolchange_gcode.value) + '\n'; + gcode += pp.process(m_config.toolchange_gcode.value, extruder_id) + '\n'; } // if ooze prevention is enabled, park current extruder in the nearest diff --git a/xs/src/libslic3r/PlaceholderParser.cpp b/xs/src/libslic3r/PlaceholderParser.cpp index db444c8f9..554c119fa 100644 --- a/xs/src/libslic3r/PlaceholderParser.cpp +++ b/xs/src/libslic3r/PlaceholderParser.cpp @@ -30,8 +30,7 @@ PlaceholderParser::PlaceholderParser() this->update_timestamp(); } -void -PlaceholderParser::update_timestamp() +void PlaceholderParser::update_timestamp() { time_t rawtime; time(&rawtime); @@ -56,22 +55,26 @@ PlaceholderParser::update_timestamp() this->set("second", timeinfo->tm_sec); } +// Scalar configuration values are stored into m_single, +// vector configuration values are stored into m_multiple. +// All vector configuration values stored into the PlaceholderParser +// are expected to be addressed by the extruder ID, therefore +// if a vector configuration value is addressed without an index, +// a current extruder ID is used. void PlaceholderParser::apply_config(const DynamicPrintConfig &config) { - t_config_option_keys opt_keys = config.keys(); - for (t_config_option_keys::const_iterator i = opt_keys.begin(); i != opt_keys.end(); ++i) { - const t_config_option_key &opt_key = *i; + for (const t_config_option_key &opt_key : config.keys()) { const ConfigOptionDef* def = config.def->get(opt_key); - if (def->multiline) continue; - + if (def->multiline || opt_key == "post_process") + continue; + const ConfigOption* opt = config.option(opt_key); - if (const ConfigOptionVectorBase* optv = dynamic_cast(opt)) { + const ConfigOptionVectorBase* optv = dynamic_cast(opt); + if (optv != nullptr && opt_key != "bed_shape") { // set placeholders for options with multiple values - // TODO: treat [bed_shape] as single, not multiple this->set(opt_key, optv->vserialize()); } else if (const ConfigOptionPoint* optp = dynamic_cast(opt)) { this->set(opt_key, optp->serialize()); - Pointf val = *optp; this->set(opt_key + "_X", val.x); this->set(opt_key + "_Y", val.y); @@ -82,8 +85,7 @@ void PlaceholderParser::apply_config(const DynamicPrintConfig &config) } } -void -PlaceholderParser::apply_env_variables() +void PlaceholderParser::apply_env_variables() { for (char** env = environ; *env; env++) { if (strncmp(*env, "SLIC3R_", 7) == 0) { @@ -99,8 +101,8 @@ PlaceholderParser::apply_env_variables() void PlaceholderParser::set(const std::string &key, const std::string &value) { - this->_single[key] = value; - this->_multiple.erase(key); + m_single[key] = value; + m_multiple.erase(key); } void PlaceholderParser::set(const std::string &key, int value) @@ -126,53 +128,63 @@ void PlaceholderParser::set(const std::string &key, double value) void PlaceholderParser::set(const std::string &key, std::vector values) { - if (values.empty()) { - this->_multiple.erase(key); - this->_single.erase(key); - } else { - this->_multiple[key] = values; - this->_single[key] = values.front(); - } + m_single.erase(key); + if (values.empty()) + m_multiple.erase(key); + else + m_multiple[key] = values; } -std::string PlaceholderParser::process(std::string str) const +std::string PlaceholderParser::process(std::string str, unsigned int current_extruder_id) const { - // replace single options, like [foo] - for (t_strstr_map::const_iterator it = this->_single.begin(); it != this->_single.end(); ++it) { - std::stringstream ss; - ss << '[' << it->first << ']'; - this->find_and_replace(str, ss.str(), it->second); + char key[2048]; + + // Replace extruder independent single options, like [foo]. + for (const auto &key_value : m_single) { + sprintf(key, "[%s]", key_value.first.c_str()); + const std::string &replace = key_value.second; + for (size_t i = 0; (i = str.find(key, i)) != std::string::npos;) { + str.replace(i, key_value.first.size() + 2, replace); + i += replace.size(); + } } - - // replace multiple options like [foo_0] by looping until we have enough values - // or until a previous match was found (this handles non-existing indices reasonably - // without a regex) - for (t_strstrs_map::const_iterator it = this->_multiple.begin(); it != this->_multiple.end(); ++it) { - const std::vector &values = it->second; - bool found = false; - for (size_t i = 0; (i < values.size()) || found; ++i) { - std::stringstream ss; - ss << '[' << it->first << '_' << i << ']'; - if (i < values.size()) { - found = this->find_and_replace(str, ss.str(), values[i]); - } else { - found = this->find_and_replace(str, ss.str(), values.front()); + + // Replace extruder dependent single options with the value for the active extruder. + // For example, [temperature] will be replaced with the current extruder temperature. + for (const auto &key_value : m_multiple) { + sprintf(key, "[%s]", key_value.first.c_str()); + const std::string &replace = key_value.second[(current_extruder_id < key_value.second.size()) ? current_extruder_id : 0]; + for (size_t i = 0; (i = str.find(key, i)) != std::string::npos;) { + str.replace(i, key_value.first.size() + 2, replace); + i += replace.size(); + } + } + + // Replace multiple options like [foo_0]. + for (const auto &key_value : m_multiple) { + sprintf(key, "[%s_", key_value.first.c_str()); + const std::vector &values = key_value.second; + for (size_t i = 0; (i = str.find(key, i)) != std::string::npos;) { + size_t k = str.find(']', i + key_value.first.size() + 2); + if (k != std::string::npos) { + // Parse the key index and the closing bracket. + ++ k; + int idx = 0; + if (sscanf(str.c_str() + i + key_value.first.size() + 2, "%d]", &idx) == 1 && idx >= 0) { + if (idx >= int(values.size())) + idx = 0; + str.replace(i, k - i, values[idx]); + i += values[idx].size(); + continue; + } } + // The key does not match the pattern [foo_%d]. Skip just [foo_.] with the hope that there was a missing ']', + // so an opening '[' may be found somewhere before the position k. + i += key_value.first.size() + 3; } } return str; } -bool PlaceholderParser::find_and_replace(std::string &source, std::string const &find, std::string const &replace) const -{ - bool found = false; - for (std::string::size_type i = 0; (i = source.find(find, i)) != std::string::npos; ) { - source.replace(i, find.length(), replace); - i += replace.length(); - found = true; - } - return found; -} - } diff --git a/xs/src/libslic3r/PlaceholderParser.hpp b/xs/src/libslic3r/PlaceholderParser.hpp index f736c14b0..a8abf8871 100644 --- a/xs/src/libslic3r/PlaceholderParser.hpp +++ b/xs/src/libslic3r/PlaceholderParser.hpp @@ -7,17 +7,13 @@ #include #include "PrintConfig.hpp" - namespace Slic3r { -typedef std::map t_strstr_map; -typedef std::map > t_strstrs_map; - class PlaceholderParser { public: - t_strstr_map _single; - t_strstrs_map _multiple; + std::map m_single; + std::map> m_multiple; PlaceholderParser(); void update_timestamp(); @@ -28,7 +24,7 @@ public: void set(const std::string &key, unsigned int value); void set(const std::string &key, double value); void set(const std::string &key, std::vector values); - std::string process(std::string str) const; + std::string process(std::string str, unsigned int current_extruder_id) const; private: bool find_and_replace(std::string &source, std::string const &find, std::string const &replace) const; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index df825b05c..5190372f3 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -1052,7 +1052,7 @@ void Print::_make_wipe_tower() std::string Print::output_filename() { this->placeholder_parser.update_timestamp(); - return this->placeholder_parser.process(this->config.output_filename_format.value); + return this->placeholder_parser.process(this->config.output_filename_format.value, 0); } std::string Print::output_filepath(const std::string &path) diff --git a/xs/xsp/PlaceholderParser.xsp b/xs/xsp/PlaceholderParser.xsp index 7daa638b6..3f1588ace 100644 --- a/xs/xsp/PlaceholderParser.xsp +++ b/xs/xsp/PlaceholderParser.xsp @@ -18,5 +18,6 @@ %code%{ THIS->apply_config(*config); %}; void set(std::string key, std::string value); %name{set_multiple} void set(std::string key, std::vector values); - std::string process(std::string str) const; + std::string process(std::string str) const + %code%{ RETVAL = THIS->process(str, 0); %}; };