diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libslic3r/GCode.cpp | 2 | ||||
-rw-r--r-- | src/libslic3r/GCode.hpp | 2 | ||||
-rw-r--r-- | src/libslic3r/PlaceholderParser.cpp | 43 | ||||
-rw-r--r-- | src/libslic3r/PlaceholderParser.hpp | 14 |
4 files changed, 53 insertions, 8 deletions
diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 60ef1ed5f..7deb38349 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -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) { 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) { // Collect the names of failed template substitutions for error reporting. auto it = m_placeholder_parser_failed_templates.find(name); diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 5efff5386..458eae80a 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -300,6 +300,8 @@ private: FullPrintConfig m_config; GCodeWriter m_writer; PlaceholderParser m_placeholder_parser; + // For random number generator etc. + PlaceholderParser::ContextData m_placeholder_parser_context; // Collection of templates, on which the placeholder substitution failed. std::map<std::string, std::string> m_placeholder_parser_failed_templates; OozePrevention m_ooze_prevention; diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index 8d4a88b14..6f2b7f3ea 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -6,7 +6,6 @@ #include <iomanip> #include <sstream> #include <map> -#include <boost/nowide/convert.hpp> #ifdef _MSC_VER #include <stdlib.h> // provides **_environ #else @@ -26,6 +25,7 @@ #endif #include <boost/algorithm/string.hpp> +#include <boost/nowide/convert.hpp> // Spirit v2.5 allows you to suppress automatic generation // 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 geq (expr &lhs, expr &rhs) { compare_op(lhs, rhs, '<', true ); } + static void throw_if_not_numeric(const expr ¶m) + { + const char *err_msg = "Not a numeric type."; + param.throw_if_not_numeric(err_msg); + } + enum Function2ParamsType { FUNCTION_MIN, FUNCTION_MAX, @@ -503,9 +509,8 @@ namespace client // Store the result into param1. static void function_2params(expr ¶m1, expr ¶m2, Function2ParamsType fun) { - const char *err_msg = "Not a numeric type."; - param1.throw_if_not_numeric(err_msg); - param2.throw_if_not_numeric(err_msg); + throw_if_not_numeric(param1); + throw_if_not_numeric(param2); if (param1.type == TYPE_DOUBLE || param2.type == TYPE_DOUBLE) { double d = 0.; switch (fun) { @@ -530,6 +535,20 @@ namespace client static void min(expr ¶m1, expr ¶m2) { function_2params(param1, param2, FUNCTION_MIN); } static void max(expr ¶m1, expr ¶m2) { function_2params(param1, param2, FUNCTION_MAX); } + // Store the result into param1. + static void random(expr ¶m1, expr ¶m2, 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) { const std::string *subject = nullptr; @@ -624,6 +643,7 @@ namespace client const DynamicConfig *config = nullptr; const DynamicConfig *config_override = nullptr; size_t current_extruder_id = 0; + PlaceholderParser::ContextData *context_data = nullptr; // 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. bool just_boolean_expression = false; @@ -825,6 +845,15 @@ namespace client } template <typename Iterator> + static void random(const MyContext *ctx, expr<Iterator> ¶m1, expr<Iterator> ¶m2) + { + 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> static void throw_exception(const std::string &msg, const boost::iterator_range<Iterator> &it_range) { // An asterix is added to the start of the string to differentiate the boost::spirit::info::tag content @@ -1176,6 +1205,8 @@ namespace client [ px::bind(&expr<Iterator>::min, _val, _2) ] | (kw["max"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')') [ 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) ] | (strict_double > iter_pos) [ px::bind(&FactorActions::double_, _1, _2, _val) ] | (int_ > iter_pos) [ px::bind(&FactorActions::int_, _1, _2, _val) ] @@ -1212,6 +1243,7 @@ namespace client ("false") ("min") ("max") + ("random") ("not") ("or") ("true"); @@ -1312,13 +1344,14 @@ static std::string process_macro(const std::string &templ, client::MyContext &co 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; context.external_config = this->external_config(); context.config = &this->config(); context.config_override = config_override; context.current_extruder_id = current_extruder_id; + context.context_data = context_data; return process_macro(templ, context); } diff --git a/src/libslic3r/PlaceholderParser.hpp b/src/libslic3r/PlaceholderParser.hpp index 40a7d5b53..d19e35d41 100644 --- a/src/libslic3r/PlaceholderParser.hpp +++ b/src/libslic3r/PlaceholderParser.hpp @@ -3,6 +3,7 @@ #include "libslic3r.h" #include <map> +#include <random> #include <string> #include <vector> #include "PrintConfig.hpp" @@ -11,7 +12,16 @@ namespace Slic3r { 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); // 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. // 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. // Throws Slic3r::PlaceholderParserError on syntax or runtime error. |