This commit is contained in:
enricoturri1966 2020-12-09 10:23:13 +01:00
commit 070ee5308c
4 changed files with 53 additions and 8 deletions

View File

@ -1340,7 +1340,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
std::string GCode::placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override) std::string GCode::placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override)
{ {
try { try {
return m_placeholder_parser.process(templ, current_extruder_id, config_override); return m_placeholder_parser.process(templ, current_extruder_id, config_override, &m_placeholder_parser_context);
} catch (std::runtime_error &err) { } catch (std::runtime_error &err) {
// Collect the names of failed template substitutions for error reporting. // Collect the names of failed template substitutions for error reporting.
auto it = m_placeholder_parser_failed_templates.find(name); auto it = m_placeholder_parser_failed_templates.find(name);

View File

@ -300,6 +300,8 @@ private:
FullPrintConfig m_config; FullPrintConfig m_config;
GCodeWriter m_writer; GCodeWriter m_writer;
PlaceholderParser m_placeholder_parser; PlaceholderParser m_placeholder_parser;
// For random number generator etc.
PlaceholderParser::ContextData m_placeholder_parser_context;
// Collection of templates, on which the placeholder substitution failed. // Collection of templates, on which the placeholder substitution failed.
std::map<std::string, std::string> m_placeholder_parser_failed_templates; std::map<std::string, std::string> m_placeholder_parser_failed_templates;
OozePrevention m_ooze_prevention; OozePrevention m_ooze_prevention;

View File

@ -6,7 +6,6 @@
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
#include <map> #include <map>
#include <boost/nowide/convert.hpp>
#ifdef _MSC_VER #ifdef _MSC_VER
#include <stdlib.h> // provides **_environ #include <stdlib.h> // provides **_environ
#else #else
@ -26,6 +25,7 @@
#endif #endif
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/nowide/convert.hpp>
// Spirit v2.5 allows you to suppress automatic generation // Spirit v2.5 allows you to suppress automatic generation
// of predefined terminals to speed up complation. With // of predefined terminals to speed up complation. With
@ -496,6 +496,12 @@ namespace client
static void leq (expr &lhs, expr &rhs) { compare_op(lhs, rhs, '>', true ); } static void leq (expr &lhs, expr &rhs) { compare_op(lhs, rhs, '>', true ); }
static void geq (expr &lhs, expr &rhs) { compare_op(lhs, rhs, '<', true ); } static void geq (expr &lhs, expr &rhs) { compare_op(lhs, rhs, '<', true ); }
static void throw_if_not_numeric(const expr &param)
{
const char *err_msg = "Not a numeric type.";
param.throw_if_not_numeric(err_msg);
}
enum Function2ParamsType { enum Function2ParamsType {
FUNCTION_MIN, FUNCTION_MIN,
FUNCTION_MAX, FUNCTION_MAX,
@ -503,9 +509,8 @@ namespace client
// Store the result into param1. // Store the result into param1.
static void function_2params(expr &param1, expr &param2, Function2ParamsType fun) static void function_2params(expr &param1, expr &param2, Function2ParamsType fun)
{ {
const char *err_msg = "Not a numeric type."; throw_if_not_numeric(param1);
param1.throw_if_not_numeric(err_msg); throw_if_not_numeric(param2);
param2.throw_if_not_numeric(err_msg);
if (param1.type == TYPE_DOUBLE || param2.type == TYPE_DOUBLE) { if (param1.type == TYPE_DOUBLE || param2.type == TYPE_DOUBLE) {
double d = 0.; double d = 0.;
switch (fun) { switch (fun) {
@ -530,6 +535,20 @@ namespace client
static void min(expr &param1, expr &param2) { function_2params(param1, param2, FUNCTION_MIN); } static void min(expr &param1, expr &param2) { function_2params(param1, param2, FUNCTION_MIN); }
static void max(expr &param1, expr &param2) { function_2params(param1, param2, FUNCTION_MAX); } static void max(expr &param1, expr &param2) { function_2params(param1, param2, FUNCTION_MAX); }
// Store the result into param1.
static void random(expr &param1, expr &param2, std::mt19937 &rng)
{
throw_if_not_numeric(param1);
throw_if_not_numeric(param2);
if (param1.type == TYPE_DOUBLE || param2.type == TYPE_DOUBLE) {
param1.data.d = std::uniform_real_distribution<>(param1.as_d(), param2.as_d())(rng);
param1.type = TYPE_DOUBLE;
} else {
param1.data.i = std::uniform_int_distribution<>(param1.as_i(), param2.as_i())(rng);
param1.type = TYPE_INT;
}
}
static void regex_op(expr &lhs, boost::iterator_range<Iterator> &rhs, char op) static void regex_op(expr &lhs, boost::iterator_range<Iterator> &rhs, char op)
{ {
const std::string *subject = nullptr; const std::string *subject = nullptr;
@ -624,6 +643,7 @@ namespace client
const DynamicConfig *config = nullptr; const DynamicConfig *config = nullptr;
const DynamicConfig *config_override = nullptr; const DynamicConfig *config_override = nullptr;
size_t current_extruder_id = 0; size_t current_extruder_id = 0;
PlaceholderParser::ContextData *context_data = nullptr;
// If false, the macro_processor will evaluate a full macro. // If false, the macro_processor will evaluate a full macro.
// If true, the macro processor will evaluate just a boolean condition using the full expressive power of the macro processor. // If true, the macro processor will evaluate just a boolean condition using the full expressive power of the macro processor.
bool just_boolean_expression = false; bool just_boolean_expression = false;
@ -824,6 +844,15 @@ namespace client
output = expr_index.i(); output = expr_index.i();
} }
template <typename Iterator>
static void random(const MyContext *ctx, expr<Iterator> &param1, expr<Iterator> &param2)
{
if (ctx->context_data == nullptr)
ctx->throw_exception("Random number generator not available in this context.",
boost::iterator_range<Iterator>(param1.it_range.begin(), param2.it_range.end()));
expr<Iterator>::random(param1, param2, ctx->context_data->rng);
}
template <typename Iterator> template <typename Iterator>
static void throw_exception(const std::string &msg, const boost::iterator_range<Iterator> &it_range) static void throw_exception(const std::string &msg, const boost::iterator_range<Iterator> &it_range)
{ {
@ -1176,6 +1205,8 @@ namespace client
[ px::bind(&expr<Iterator>::min, _val, _2) ] [ px::bind(&expr<Iterator>::min, _val, _2) ]
| (kw["max"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')') | (kw["max"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')')
[ px::bind(&expr<Iterator>::max, _val, _2) ] [ px::bind(&expr<Iterator>::max, _val, _2) ]
| (kw["random"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')')
[ px::bind(&MyContext::random<Iterator>, _r1, _val, _2) ]
| (kw["int"] > '(' > unary_expression(_r1) > ')') [ px::bind(&FactorActions::to_int, _1, _val) ] | (kw["int"] > '(' > unary_expression(_r1) > ')') [ px::bind(&FactorActions::to_int, _1, _val) ]
| (strict_double > iter_pos) [ px::bind(&FactorActions::double_, _1, _2, _val) ] | (strict_double > iter_pos) [ px::bind(&FactorActions::double_, _1, _2, _val) ]
| (int_ > iter_pos) [ px::bind(&FactorActions::int_, _1, _2, _val) ] | (int_ > iter_pos) [ px::bind(&FactorActions::int_, _1, _2, _val) ]
@ -1212,6 +1243,7 @@ namespace client
("false") ("false")
("min") ("min")
("max") ("max")
("random")
("not") ("not")
("or") ("or")
("true"); ("true");
@ -1312,13 +1344,14 @@ static std::string process_macro(const std::string &templ, client::MyContext &co
return output; return output;
} }
std::string PlaceholderParser::process(const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override) const std::string PlaceholderParser::process(const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override, ContextData *context_data) const
{ {
client::MyContext context; client::MyContext context;
context.external_config = this->external_config(); context.external_config = this->external_config();
context.config = &this->config(); context.config = &this->config();
context.config_override = config_override; context.config_override = config_override;
context.current_extruder_id = current_extruder_id; context.current_extruder_id = current_extruder_id;
context.context_data = context_data;
return process_macro(templ, context); return process_macro(templ, context);
} }

View File

@ -3,6 +3,7 @@
#include "libslic3r.h" #include "libslic3r.h"
#include <map> #include <map>
#include <random>
#include <string> #include <string>
#include <vector> #include <vector>
#include "PrintConfig.hpp" #include "PrintConfig.hpp"
@ -11,7 +12,16 @@ namespace Slic3r {
class PlaceholderParser class PlaceholderParser
{ {
public: public:
// Context to be shared during multiple executions of the PlaceholderParser.
// The context is kept external to the PlaceholderParser, so that the same PlaceholderParser
// may be called safely from multiple threads.
// In the future, the context may hold variables created and modified by the PlaceholderParser
// and shared between the PlaceholderParser::process() invocations.
struct ContextData {
std::mt19937 rng;
};
PlaceholderParser(const DynamicConfig *external_config = nullptr); PlaceholderParser(const DynamicConfig *external_config = nullptr);
// Return a list of keys, which should be changed in m_config from rhs. // Return a list of keys, which should be changed in m_config from rhs.
@ -41,7 +51,7 @@ public:
// Fill in the template using a macro processing language. // Fill in the template using a macro processing language.
// Throws Slic3r::PlaceholderParserError on syntax or runtime error. // Throws Slic3r::PlaceholderParserError on syntax or runtime error.
std::string process(const std::string &templ, unsigned int current_extruder_id = 0, const DynamicConfig *config_override = nullptr) const; std::string process(const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override, ContextData *context = nullptr) const;
// Evaluate a boolean expression using the full expressive power of the PlaceholderParser boolean expression syntax. // Evaluate a boolean expression using the full expressive power of the PlaceholderParser boolean expression syntax.
// Throws Slic3r::PlaceholderParserError on syntax or runtime error. // Throws Slic3r::PlaceholderParserError on syntax or runtime error.