PrusaSlicer-NonPlainar/xs/src/libslic3r/PlaceholderParser.cpp
bubnikv 75c72bc59b Fix of "MM incorrect extruder temperature"
https://github.com/prusa3d/Slic3r/issues/443

Change of the PlaceholderParser:
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.

Also a small fix of fan handling: The fan speed is set to zero
at the start of the G-code if the cooling for the initial extruder
is disabled.
2017-07-31 15:42:55 +02:00

191 lines
6.1 KiB
C++

#include "PlaceholderParser.hpp"
#include <cstring>
#include <ctime>
#include <iomanip>
#include <sstream>
#ifdef _MSC_VER
#include <stdlib.h> // provides **_environ
#else
#include <unistd.h> // provides **environ
#endif
#ifdef __APPLE__
#include <crt_externs.h>
#undef environ
#define environ (*_NSGetEnviron())
#else
#ifdef _MSC_VER
#define environ _environ
#else
extern char **environ;
#endif
#endif
namespace Slic3r {
PlaceholderParser::PlaceholderParser()
{
this->set("version", SLIC3R_VERSION);
this->apply_env_variables();
this->update_timestamp();
}
void PlaceholderParser::update_timestamp()
{
time_t rawtime;
time(&rawtime);
struct tm* timeinfo = localtime(&rawtime);
{
std::ostringstream ss;
ss << (1900 + timeinfo->tm_year);
ss << std::setw(2) << std::setfill('0') << (1 + timeinfo->tm_mon);
ss << std::setw(2) << std::setfill('0') << timeinfo->tm_mday;
ss << "-";
ss << std::setw(2) << std::setfill('0') << timeinfo->tm_hour;
ss << std::setw(2) << std::setfill('0') << timeinfo->tm_min;
ss << std::setw(2) << std::setfill('0') << timeinfo->tm_sec;
this->set("timestamp", ss.str());
}
this->set("year", 1900 + timeinfo->tm_year);
this->set("month", 1 + timeinfo->tm_mon);
this->set("day", timeinfo->tm_mday);
this->set("hour", timeinfo->tm_hour);
this->set("minute", timeinfo->tm_min);
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)
{
for (const t_config_option_key &opt_key : config.keys()) {
const ConfigOptionDef* def = config.def->get(opt_key);
if (def->multiline || opt_key == "post_process")
continue;
const ConfigOption* opt = config.option(opt_key);
const ConfigOptionVectorBase* optv = dynamic_cast<const ConfigOptionVectorBase*>(opt);
if (optv != nullptr && opt_key != "bed_shape") {
// set placeholders for options with multiple values
this->set(opt_key, optv->vserialize());
} else if (const ConfigOptionPoint* optp = dynamic_cast<const ConfigOptionPoint*>(opt)) {
this->set(opt_key, optp->serialize());
Pointf val = *optp;
this->set(opt_key + "_X", val.x);
this->set(opt_key + "_Y", val.y);
} else {
// set single-value placeholders
this->set(opt_key, opt->serialize());
}
}
}
void PlaceholderParser::apply_env_variables()
{
for (char** env = environ; *env; env++) {
if (strncmp(*env, "SLIC3R_", 7) == 0) {
std::stringstream ss(*env);
std::string key, value;
std::getline(ss, key, '=');
ss >> value;
this->set(key, value);
}
}
}
void PlaceholderParser::set(const std::string &key, const std::string &value)
{
m_single[key] = value;
m_multiple.erase(key);
}
void PlaceholderParser::set(const std::string &key, int value)
{
std::ostringstream ss;
ss << value;
this->set(key, ss.str());
}
void PlaceholderParser::set(const std::string &key, unsigned int value)
{
std::ostringstream ss;
ss << value;
this->set(key, ss.str());
}
void PlaceholderParser::set(const std::string &key, double value)
{
std::ostringstream ss;
ss << value;
this->set(key, ss.str());
}
void PlaceholderParser::set(const std::string &key, std::vector<std::string> values)
{
m_single.erase(key);
if (values.empty())
m_multiple.erase(key);
else
m_multiple[key] = values;
}
std::string PlaceholderParser::process(std::string str, unsigned int current_extruder_id) const
{
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 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<std::string> &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;
}
}