Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer
This commit is contained in:
commit
c2598cf8d6
@ -591,7 +591,7 @@ bool CLI::setup(int argc, char **argv)
|
||||
// Initialize with defaults.
|
||||
for (const t_optiondef_map *options : { &cli_actions_config_def.options, &cli_transform_config_def.options, &cli_misc_config_def.options })
|
||||
for (const std::pair<t_config_option_key, ConfigOptionDef> &optdef : *options)
|
||||
m_config.optptr(optdef.first, true);
|
||||
m_config.option(optdef.first, true);
|
||||
|
||||
set_data_dir(m_config.opt_string("datadir"));
|
||||
|
||||
|
@ -757,6 +757,12 @@ ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool cre
|
||||
return opt;
|
||||
}
|
||||
|
||||
const ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key) const
|
||||
{
|
||||
auto it = options.find(opt_key);
|
||||
return (it == options.end()) ? nullptr : it->second.get();
|
||||
}
|
||||
|
||||
void DynamicConfig::read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra, t_config_option_keys* keys)
|
||||
{
|
||||
std::vector<const char*> args;
|
||||
|
@ -1494,8 +1494,49 @@ protected:
|
||||
ConfigOptionDef* add_nullable(const t_config_option_key &opt_key, ConfigOptionType type);
|
||||
};
|
||||
|
||||
// A pure interface to resolving ConfigOptions.
|
||||
// This pure interface is useful as a base of ConfigBase, also it may be overriden to combine
|
||||
// various config sources.
|
||||
class ConfigOptionResolver
|
||||
{
|
||||
public:
|
||||
ConfigOptionResolver() {}
|
||||
virtual ~ConfigOptionResolver() {}
|
||||
|
||||
// Find a ConfigOption instance for a given name.
|
||||
virtual const ConfigOption* optptr(const t_config_option_key &opt_key) const = 0;
|
||||
|
||||
bool has(const t_config_option_key &opt_key) const { return this->optptr(opt_key) != nullptr; }
|
||||
|
||||
const ConfigOption* option(const t_config_option_key &opt_key) const { return this->optptr(opt_key); }
|
||||
|
||||
template<typename TYPE>
|
||||
const TYPE* option(const t_config_option_key& opt_key) const
|
||||
{
|
||||
const ConfigOption* opt = this->optptr(opt_key);
|
||||
return (opt == nullptr || opt->type() != TYPE::static_type()) ? nullptr : static_cast<const TYPE*>(opt);
|
||||
}
|
||||
|
||||
const ConfigOption* option_throw(const t_config_option_key& opt_key) const
|
||||
{
|
||||
const ConfigOption* opt = this->optptr(opt_key);
|
||||
if (opt == nullptr)
|
||||
throw UnknownOptionException(opt_key);
|
||||
return opt;
|
||||
}
|
||||
|
||||
template<typename TYPE>
|
||||
const TYPE* option_throw(const t_config_option_key& opt_key) const
|
||||
{
|
||||
const ConfigOption* opt = this->option_throw(opt_key);
|
||||
if (opt->type() != TYPE::static_type())
|
||||
throw BadOptionTypeException("Conversion to a wrong type");
|
||||
return static_cast<TYPE*>(opt);
|
||||
}
|
||||
};
|
||||
|
||||
// An abstract configuration store.
|
||||
class ConfigBase
|
||||
class ConfigBase : public ConfigOptionResolver
|
||||
{
|
||||
public:
|
||||
// Definition of configuration values for the purpose of GUI presentation, editing, value mapping and config file handling.
|
||||
@ -1503,7 +1544,7 @@ public:
|
||||
// but it carries the defaults of the configuration values.
|
||||
|
||||
ConfigBase() {}
|
||||
virtual ~ConfigBase() {}
|
||||
~ConfigBase() override {}
|
||||
|
||||
// Virtual overridables:
|
||||
public:
|
||||
@ -1513,6 +1554,7 @@ public:
|
||||
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) = 0;
|
||||
// Collect names of all configuration values maintained by this configuration store.
|
||||
virtual t_config_option_keys keys() const = 0;
|
||||
|
||||
protected:
|
||||
// Verify whether the opt_key has not been obsoleted or renamed.
|
||||
// Both opt_key and value may be modified by handle_legacy().
|
||||
@ -1521,12 +1563,10 @@ protected:
|
||||
virtual void handle_legacy(t_config_option_key &/*opt_key*/, std::string &/*value*/) const {}
|
||||
|
||||
public:
|
||||
using ConfigOptionResolver::option;
|
||||
using ConfigOptionResolver::option_throw;
|
||||
|
||||
// Non-virtual methods:
|
||||
bool has(const t_config_option_key &opt_key) const { return this->option(opt_key) != nullptr; }
|
||||
|
||||
const ConfigOption* option(const t_config_option_key &opt_key) const
|
||||
{ return const_cast<ConfigBase*>(this)->option(opt_key, false); }
|
||||
|
||||
ConfigOption* option(const t_config_option_key &opt_key, bool create = false)
|
||||
{ return this->optptr(opt_key, create); }
|
||||
|
||||
@ -1537,10 +1577,6 @@ public:
|
||||
return (opt == nullptr || opt->type() != TYPE::static_type()) ? nullptr : static_cast<TYPE*>(opt);
|
||||
}
|
||||
|
||||
template<typename TYPE>
|
||||
const TYPE* option(const t_config_option_key &opt_key) const
|
||||
{ return const_cast<ConfigBase*>(this)->option<TYPE>(opt_key, false); }
|
||||
|
||||
ConfigOption* option_throw(const t_config_option_key &opt_key, bool create = false)
|
||||
{
|
||||
ConfigOption *opt = this->optptr(opt_key, create);
|
||||
@ -1549,9 +1585,6 @@ public:
|
||||
return opt;
|
||||
}
|
||||
|
||||
const ConfigOption* option_throw(const t_config_option_key &opt_key) const
|
||||
{ return const_cast<ConfigBase*>(this)->option_throw(opt_key, false); }
|
||||
|
||||
template<typename TYPE>
|
||||
TYPE* option_throw(const t_config_option_key &opt_key, bool create = false)
|
||||
{
|
||||
@ -1561,10 +1594,6 @@ public:
|
||||
return static_cast<TYPE*>(opt);
|
||||
}
|
||||
|
||||
template<typename TYPE>
|
||||
const TYPE* option_throw(const t_config_option_key &opt_key) const
|
||||
{ return const_cast<ConfigBase*>(this)->option_throw<TYPE>(opt_key, false); }
|
||||
|
||||
// Apply all keys of other ConfigBase defined by this->def() to this ConfigBase.
|
||||
// An UnknownOptionException is thrown in case some option keys of other are not defined by this->def(),
|
||||
// or this ConfigBase is of a StaticConfig type and it does not support some of the keys, and ignore_nonexistent is not set.
|
||||
@ -1735,6 +1764,8 @@ public:
|
||||
{ return dynamic_cast<T*>(this->option(opt_key, create)); }
|
||||
template<class T> const T* opt(const t_config_option_key &opt_key) const
|
||||
{ return dynamic_cast<const T*>(this->option(opt_key)); }
|
||||
// Overrides ConfigResolver::optptr().
|
||||
const ConfigOption* optptr(const t_config_option_key &opt_key) const override;
|
||||
// Overrides ConfigBase::optptr(). Find ando/or create a ConfigOption instance for a given name.
|
||||
ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) override;
|
||||
// Overrides ConfigBase::keys(). Collect names of all configuration values maintained by this configuration store.
|
||||
|
@ -1,12 +1,17 @@
|
||||
#include "Flow.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "Print.hpp"
|
||||
#include <cmath>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
// Mark string for localization and translate.
|
||||
#define L(s) Slic3r::I18N::translate(s)
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// This static method returns a sane extrusion width default.
|
||||
static inline float auto_extrusion_width(FlowRole role, float nozzle_diameter, float height)
|
||||
float Flow::auto_extrusion_width(FlowRole role, float nozzle_diameter)
|
||||
{
|
||||
switch (role) {
|
||||
case frSupportMaterial:
|
||||
@ -22,6 +27,92 @@ static inline float auto_extrusion_width(FlowRole role, float nozzle_diameter, f
|
||||
}
|
||||
}
|
||||
|
||||
// Used by the Flow::extrusion_width() funtion to provide hints to the user on default extrusion width values,
|
||||
// and to provide reasonable values to the PlaceholderParser.
|
||||
static inline FlowRole opt_key_to_flow_role(const std::string &opt_key)
|
||||
{
|
||||
if (opt_key == "perimeter_extrusion_width" ||
|
||||
// or all the defaults:
|
||||
opt_key == "extrusion_width" || opt_key == "first_layer_extrusion_width")
|
||||
return frPerimeter;
|
||||
else if (opt_key == "external_perimeter_extrusion_width")
|
||||
return frExternalPerimeter;
|
||||
else if (opt_key == "infill_extrusion_width")
|
||||
return frInfill;
|
||||
else if (opt_key == "solid_infill_extrusion_width")
|
||||
return frSolidInfill;
|
||||
else if (opt_key == "top_infill_extrusion_width")
|
||||
return frTopSolidInfill;
|
||||
else if (opt_key == "support_material_extrusion_width")
|
||||
return frSupportMaterial;
|
||||
else
|
||||
throw std::runtime_error("opt_key_to_flow_role: invalid argument");
|
||||
};
|
||||
|
||||
static inline void throw_on_missing_variable(const std::string &opt_key, const char *dependent_opt_key)
|
||||
{
|
||||
throw std::runtime_error((boost::format(L("Cannot calculate extrusion width for %1%: Variable \"%2%\" not accessible.")) % opt_key % dependent_opt_key).str());
|
||||
}
|
||||
|
||||
// Used to provide hints to the user on default extrusion width values, and to provide reasonable values to the PlaceholderParser.
|
||||
double Flow::extrusion_width(const std::string& opt_key, const ConfigOptionFloatOrPercent* opt, const ConfigOptionResolver& config, const unsigned int first_printing_extruder)
|
||||
{
|
||||
assert(opt != nullptr);
|
||||
|
||||
bool first_layer = boost::starts_with(opt_key, "first_layer_");
|
||||
|
||||
#if 0
|
||||
// This is the logic used for skit / brim, but not for the rest of the 1st layer.
|
||||
if (opt->value == 0. && first_layer) {
|
||||
// The "first_layer_extrusion_width" was set to zero, try a substitute.
|
||||
opt = config.option<ConfigOptionFloatOrPercent>("perimeter_extrusion_width");
|
||||
if (opt == nullptr)
|
||||
throw_on_missing_variable(opt_key, "perimeter_extrusion_width");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (opt->value == 0.) {
|
||||
// The role specific extrusion width value was set to zero, try the role non-specific extrusion width.
|
||||
opt = config.option<ConfigOptionFloatOrPercent>("extrusion_width");
|
||||
if (opt == nullptr)
|
||||
throw_on_missing_variable(opt_key, "extrusion_width");
|
||||
// Use the "layer_height" instead of "first_layer_height".
|
||||
first_layer = false;
|
||||
}
|
||||
|
||||
if (opt->percent) {
|
||||
auto opt_key_layer_height = first_layer ? "first_layer_height" : "layer_height";
|
||||
auto opt_layer_height = config.option(opt_key_layer_height);
|
||||
if (opt_layer_height == nullptr)
|
||||
throw_on_missing_variable(opt_key, opt_key_layer_height);
|
||||
double layer_height = opt_layer_height->getFloat();
|
||||
if (first_layer && static_cast<const ConfigOptionFloatOrPercent*>(opt_layer_height)->percent) {
|
||||
// first_layer_height depends on layer_height.
|
||||
opt_layer_height = config.option("layer_height");
|
||||
if (opt_layer_height == nullptr)
|
||||
throw_on_missing_variable(opt_key, "layer_height");
|
||||
layer_height *= 0.01 * opt_layer_height->getFloat();
|
||||
}
|
||||
return opt->get_abs_value(layer_height);
|
||||
}
|
||||
|
||||
if (opt->value == 0.) {
|
||||
// If user left option to 0, calculate a sane default width.
|
||||
auto opt_nozzle_diameters = config.option<ConfigOptionFloats>("nozzle_diameter");
|
||||
if (opt_nozzle_diameters == nullptr)
|
||||
throw_on_missing_variable(opt_key, "nozzle_diameter");
|
||||
return auto_extrusion_width(opt_key_to_flow_role(opt_key), float(opt_nozzle_diameters->get_at(first_printing_extruder)));
|
||||
}
|
||||
|
||||
return opt->value;
|
||||
}
|
||||
|
||||
// Used to provide hints to the user on default extrusion width values, and to provide reasonable values to the PlaceholderParser.
|
||||
double Flow::extrusion_width(const std::string& opt_key, const ConfigOptionResolver &config, const unsigned int first_printing_extruder)
|
||||
{
|
||||
return extrusion_width(opt_key, config.option<ConfigOptionFloatOrPercent>(opt_key), config, first_printing_extruder);
|
||||
}
|
||||
|
||||
// This constructor builds a Flow object from an extrusion width config setting
|
||||
// and other context properties.
|
||||
Flow Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height, float bridge_flow_ratio)
|
||||
@ -39,7 +130,7 @@ Flow Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent
|
||||
sqrt(bridge_flow_ratio) * nozzle_diameter;
|
||||
} else if (! width.percent && width.value == 0.) {
|
||||
// If user left option to 0, calculate a sane default width.
|
||||
w = auto_extrusion_width(role, nozzle_diameter, height);
|
||||
w = auto_extrusion_width(role, nozzle_diameter);
|
||||
} else {
|
||||
// If user set a manual value, use it.
|
||||
w = float(width.get_abs_value(height));
|
||||
|
@ -64,6 +64,16 @@ public:
|
||||
// This method is used exclusively to calculate new flow of 100% infill, where the extrusion width was allowed to scale
|
||||
// to fit a region with integer number of lines.
|
||||
static Flow new_from_spacing(float spacing, float nozzle_diameter, float height, bool bridge);
|
||||
|
||||
// Sane extrusion width defautl based on nozzle diameter.
|
||||
// The defaults were derived from manual Prusa MK3 profiles.
|
||||
static float auto_extrusion_width(FlowRole role, float nozzle_diameter);
|
||||
|
||||
// Extrusion width from full config, taking into account the defaults (when set to zero) and ratios (percentages).
|
||||
// Precise value depends on layer index (1st layer vs. other layers vs. variable layer height),
|
||||
// on active extruder etc. Therefore the value calculated by this function shall be used as a hint only.
|
||||
static double extrusion_width(const std::string &opt_key, const ConfigOptionFloatOrPercent *opt, const ConfigOptionResolver &config, const unsigned int first_printing_extruder = 0);
|
||||
static double extrusion_width(const std::string &opt_key, const ConfigOptionResolver &config, const unsigned int first_printing_extruder = 0);
|
||||
};
|
||||
|
||||
extern Flow support_material_flow(const PrintObject *object, float layer_height = 0.f);
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "PlaceholderParser.hpp"
|
||||
#include "Flow.hpp"
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
@ -99,11 +100,7 @@ static inline bool opts_equal(const DynamicConfig &config_old, const DynamicConf
|
||||
const ConfigOption *opt_old = config_old.option(opt_key);
|
||||
const ConfigOption *opt_new = config_new.option(opt_key);
|
||||
assert(opt_new != nullptr);
|
||||
if (opt_old == nullptr)
|
||||
return false;
|
||||
return (opt_new->type() == coFloatOrPercent) ?
|
||||
dynamic_cast<const ConfigOptionFloat*>(opt_old)->value == config_new.get_abs_value(opt_key) :
|
||||
*opt_new == *opt_old;
|
||||
return opt_old != nullptr && *opt_new == *opt_old;
|
||||
}
|
||||
|
||||
std::vector<std::string> PlaceholderParser::config_diff(const DynamicPrintConfig &rhs)
|
||||
@ -126,14 +123,7 @@ bool PlaceholderParser::apply_config(const DynamicPrintConfig &rhs)
|
||||
bool modified = false;
|
||||
for (const t_config_option_key &opt_key : rhs.keys()) {
|
||||
if (! opts_equal(m_config, rhs, opt_key)) {
|
||||
// Store a copy of the config option.
|
||||
// Convert FloatOrPercent values to floats first.
|
||||
//FIXME there are some ratio_over chains, which end with empty ratio_with.
|
||||
// For example, XXX_extrusion_width parameters are not handled by get_abs_value correctly.
|
||||
const ConfigOption *opt_rhs = rhs.option(opt_key);
|
||||
this->set(opt_key, (opt_rhs->type() == coFloatOrPercent) ?
|
||||
new ConfigOptionFloat(rhs.get_abs_value(opt_key)) :
|
||||
opt_rhs->clone());
|
||||
this->set(opt_key, rhs.option(opt_key)->clone());
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
@ -142,16 +132,8 @@ bool PlaceholderParser::apply_config(const DynamicPrintConfig &rhs)
|
||||
|
||||
void PlaceholderParser::apply_only(const DynamicPrintConfig &rhs, const std::vector<std::string> &keys)
|
||||
{
|
||||
for (const t_config_option_key &opt_key : keys) {
|
||||
// Store a copy of the config option.
|
||||
// Convert FloatOrPercent values to floats first.
|
||||
//FIXME there are some ratio_over chains, which end with empty ratio_with.
|
||||
// For example, XXX_extrusion_width parameters are not handled by get_abs_value correctly.
|
||||
const ConfigOption *opt_rhs = rhs.option(opt_key);
|
||||
this->set(opt_key, (opt_rhs->type() == coFloatOrPercent) ?
|
||||
new ConfigOptionFloat(rhs.get_abs_value(opt_key)) :
|
||||
opt_rhs->clone());
|
||||
}
|
||||
for (const t_config_option_key &opt_key : keys)
|
||||
this->set(opt_key, rhs.option(opt_key)->clone());
|
||||
}
|
||||
|
||||
void PlaceholderParser::apply_config(DynamicPrintConfig &&rhs)
|
||||
@ -635,7 +617,7 @@ namespace client
|
||||
return os;
|
||||
}
|
||||
|
||||
struct MyContext {
|
||||
struct MyContext : public ConfigOptionResolver {
|
||||
const DynamicConfig *external_config = nullptr;
|
||||
const DynamicConfig *config = nullptr;
|
||||
const DynamicConfig *config_override = nullptr;
|
||||
@ -650,7 +632,7 @@ namespace client
|
||||
|
||||
static void evaluate_full_macro(const MyContext *ctx, bool &result) { result = ! ctx->just_boolean_expression; }
|
||||
|
||||
const ConfigOption* resolve_symbol(const std::string &opt_key) const
|
||||
const ConfigOption* optptr(const t_config_option_key &opt_key) const override
|
||||
{
|
||||
const ConfigOption *opt = nullptr;
|
||||
if (config_override != nullptr)
|
||||
@ -662,6 +644,8 @@ namespace client
|
||||
return opt;
|
||||
}
|
||||
|
||||
const ConfigOption* resolve_symbol(const std::string &opt_key) const { return this->optptr(opt_key); }
|
||||
|
||||
template <typename Iterator>
|
||||
static void legacy_variable_expansion(
|
||||
const MyContext *ctx,
|
||||
@ -758,7 +742,43 @@ namespace client
|
||||
case coPoint: output.set_s(opt.opt->serialize()); break;
|
||||
case coBool: output.set_b(opt.opt->getBool()); break;
|
||||
case coFloatOrPercent:
|
||||
ctx->throw_exception("FloatOrPercent variables are not supported", opt.it_range);
|
||||
{
|
||||
std::string opt_key(opt.it_range.begin(), opt.it_range.end());
|
||||
if (boost::ends_with(opt_key, "extrusion_width")) {
|
||||
// Extrusion width supports defaults and a complex graph of dependencies.
|
||||
output.set_d(Flow::extrusion_width(opt_key, *ctx, static_cast<unsigned int>(ctx->current_extruder_id)));
|
||||
} else if (! static_cast<const ConfigOptionFloatOrPercent*>(opt.opt)->percent) {
|
||||
// Not a percent, just return the value.
|
||||
output.set_d(opt.opt->getFloat());
|
||||
} else {
|
||||
// Resolve dependencies using the "ratio_over" link to a parent value.
|
||||
const ConfigOptionDef *opt_def = print_config_def.get(opt_key);
|
||||
assert(opt_def != nullptr);
|
||||
double v = opt.opt->getFloat() * 0.01; // percent to ratio
|
||||
for (;;) {
|
||||
const ConfigOption *opt_parent = opt_def->ratio_over.empty() ? nullptr : ctx->resolve_symbol(opt_def->ratio_over);
|
||||
if (opt_parent == nullptr)
|
||||
ctx->throw_exception("FloatOrPercent variable failed to resolve the \"ratio_over\" dependencies", opt.it_range);
|
||||
if (boost::ends_with(opt_def->ratio_over, "extrusion_width")) {
|
||||
// Extrusion width supports defaults and a complex graph of dependencies.
|
||||
assert(opt_parent->type() == coFloatOrPercent);
|
||||
v *= Flow::extrusion_width(opt_def->ratio_over, static_cast<const ConfigOptionFloatOrPercent*>(opt_parent), *ctx, static_cast<unsigned int>(ctx->current_extruder_id));
|
||||
break;
|
||||
}
|
||||
if (opt_parent->type() == coFloat || opt_parent->type() == coFloatOrPercent) {
|
||||
v *= opt_parent->getFloat();
|
||||
if (opt_parent->type() == coFloat || ! static_cast<const ConfigOptionFloatOrPercent*>(opt_parent)->percent)
|
||||
break;
|
||||
v *= 0.01; // percent to ratio
|
||||
}
|
||||
// Continue one level up in the "ratio_over" hierarchy.
|
||||
opt_def = print_config_def.get(opt_def->ratio_over);
|
||||
assert(opt_def != nullptr);
|
||||
}
|
||||
output.set_d(v);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ctx->throw_exception("Unknown scalar variable type", opt.it_range);
|
||||
}
|
||||
|
@ -24,8 +24,7 @@
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
//! macro used to mark string used at localization,
|
||||
//! return same string
|
||||
// Mark string for localization and translate.
|
||||
#define L(s) Slic3r::I18N::translate(s)
|
||||
|
||||
namespace Slic3r {
|
||||
@ -527,7 +526,6 @@ void Print::config_diffs(
|
||||
const DynamicPrintConfig &new_full_config,
|
||||
t_config_option_keys &print_diff, t_config_option_keys &object_diff, t_config_option_keys ®ion_diff,
|
||||
t_config_option_keys &full_config_diff,
|
||||
DynamicPrintConfig &placeholder_parser_overrides,
|
||||
DynamicPrintConfig &filament_overrides) const
|
||||
{
|
||||
// Collect changes to print config, account for overrides of extruder retract values by filament presets.
|
||||
@ -563,19 +561,11 @@ void Print::config_diffs(
|
||||
object_diff = m_default_object_config.diff(new_full_config);
|
||||
region_diff = m_default_region_config.diff(new_full_config);
|
||||
// Prepare for storing of the full print config into new_full_config to be exported into the G-code and to be used by the PlaceholderParser.
|
||||
// As the PlaceholderParser does not interpret the FloatOrPercent values itself, these values are stored into the PlaceholderParser converted to floats.
|
||||
for (const t_config_option_key &opt_key : new_full_config.keys()) {
|
||||
const ConfigOption *opt_old = m_full_print_config.option(opt_key);
|
||||
const ConfigOption *opt_new = new_full_config.option(opt_key);
|
||||
if (opt_old == nullptr || *opt_new != *opt_old)
|
||||
full_config_diff.emplace_back(opt_key);
|
||||
if (opt_new->type() == coFloatOrPercent) {
|
||||
// The m_placeholder_parser is never modified by the background processing, GCode.cpp/hpp makes a copy.
|
||||
const ConfigOption *opt_old_pp = this->placeholder_parser().config().option(opt_key);
|
||||
double new_value = new_full_config.get_abs_value(opt_key);
|
||||
if (opt_old_pp == nullptr || static_cast<const ConfigOptionFloat*>(opt_old_pp)->value != new_value)
|
||||
placeholder_parser_overrides.set_key_value(opt_key, new ConfigOptionFloat(new_value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -593,8 +583,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
|
||||
// Find modified keys of the various configs. Resolve overrides extruder retract values by filament profiles.
|
||||
t_config_option_keys print_diff, object_diff, region_diff, full_config_diff;
|
||||
DynamicPrintConfig placeholder_parser_overrides, filament_overrides;
|
||||
this->config_diffs(new_full_config, print_diff, object_diff, region_diff, full_config_diff, placeholder_parser_overrides, filament_overrides);
|
||||
DynamicPrintConfig filament_overrides;
|
||||
this->config_diffs(new_full_config, print_diff, object_diff, region_diff, full_config_diff, filament_overrides);
|
||||
|
||||
// Do not use the ApplyStatus as we will use the max function when updating apply_status.
|
||||
unsigned int apply_status = APPLY_STATUS_UNCHANGED;
|
||||
@ -614,9 +604,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
// which should be stopped if print_diff is not empty.
|
||||
size_t num_extruders = m_config.nozzle_diameter.size();
|
||||
bool num_extruders_changed = false;
|
||||
if (! full_config_diff.empty() || ! placeholder_parser_overrides.empty()) {
|
||||
if (! full_config_diff.empty()) {
|
||||
update_apply_status(this->invalidate_step(psGCodeExport));
|
||||
m_placeholder_parser.apply_config(std::move(placeholder_parser_overrides));
|
||||
// Set the profile aliases for the PrintBase::output_filename()
|
||||
m_placeholder_parser.set("print_preset", new_full_config.option("print_settings_id")->clone());
|
||||
m_placeholder_parser.set("filament_preset", new_full_config.option("filament_settings_id")->clone());
|
||||
|
@ -435,7 +435,6 @@ private:
|
||||
const DynamicPrintConfig &new_full_config,
|
||||
t_config_option_keys &print_diff, t_config_option_keys &object_diff, t_config_option_keys ®ion_diff,
|
||||
t_config_option_keys &full_config_diff,
|
||||
DynamicPrintConfig &placeholder_parser_overrides,
|
||||
DynamicPrintConfig &filament_overrides) const;
|
||||
|
||||
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
|
||||
|
@ -718,8 +718,9 @@ void PrintConfigDef::init_fff_params()
|
||||
def->gui_type = "f_enum_open";
|
||||
def->gui_flags = "show_value";
|
||||
def->enum_values.push_back("PLA");
|
||||
def->enum_values.push_back("ABS");
|
||||
def->enum_values.push_back("PET");
|
||||
def->enum_values.push_back("ABS");
|
||||
def->enum_values.push_back("ASA");
|
||||
def->enum_values.push_back("FLEX");
|
||||
def->enum_values.push_back("HIPS");
|
||||
def->enum_values.push_back("EDGE");
|
||||
|
@ -46,12 +46,6 @@ enum SeamPosition {
|
||||
spRandom, spNearest, spAligned, spRear
|
||||
};
|
||||
|
||||
/*
|
||||
enum FilamentType {
|
||||
ftPLA, ftABS, ftPET, ftHIPS, ftFLEX, ftSCAFF, ftEDGE, ftNGEN, ftPVA
|
||||
};
|
||||
*/
|
||||
|
||||
enum SLAMaterial {
|
||||
slamTough,
|
||||
slamFlex,
|
||||
@ -149,24 +143,6 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<SeamPosition>::ge
|
||||
return keys_map;
|
||||
}
|
||||
|
||||
/*
|
||||
template<> inline const t_config_enum_values& ConfigOptionEnum<FilamentType>::get_enum_values() {
|
||||
static t_config_enum_values keys_map;
|
||||
if (keys_map.empty()) {
|
||||
keys_map["PLA"] = ftPLA;
|
||||
keys_map["ABS"] = ftABS;
|
||||
keys_map["PET"] = ftPET;
|
||||
keys_map["HIPS"] = ftHIPS;
|
||||
keys_map["FLEX"] = ftFLEX;
|
||||
keys_map["SCAFF"] = ftSCAFF;
|
||||
keys_map["EDGE"] = ftEDGE;
|
||||
keys_map["NGEN"] = ftNGEN;
|
||||
keys_map["PVA"] = ftPVA;
|
||||
}
|
||||
return keys_map;
|
||||
}
|
||||
*/
|
||||
|
||||
template<> inline const t_config_enum_values& ConfigOptionEnum<SLADisplayOrientation>::get_enum_values() {
|
||||
static const t_config_enum_values keys_map = {
|
||||
{ "landscape", sladoLandscape},
|
||||
@ -354,6 +330,9 @@ protected:
|
||||
#define STATIC_PRINT_CONFIG_CACHE_BASE(CLASS_NAME) \
|
||||
public: \
|
||||
/* Overrides ConfigBase::optptr(). Find ando/or create a ConfigOption instance for a given name. */ \
|
||||
const ConfigOption* optptr(const t_config_option_key &opt_key) const override \
|
||||
{ return s_cache_##CLASS_NAME.optptr(opt_key, this); } \
|
||||
/* Overrides ConfigBase::optptr(). Find ando/or create a ConfigOption instance for a given name. */ \
|
||||
ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) override \
|
||||
{ return s_cache_##CLASS_NAME.optptr(opt_key, this); } \
|
||||
/* Overrides ConfigBase::keys(). Collect names of all configuration values maintained by this configuration store. */ \
|
||||
|
@ -14,6 +14,14 @@ SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") {
|
||||
{ "nozzle_diameter", "0.6;0.6;0.6;0.6" },
|
||||
{ "temperature", "357;359;363;378" }
|
||||
});
|
||||
// To test the "first_layer_extrusion_width" over "first_layer_heigth" over "layer_height" chain.
|
||||
config.option<ConfigOptionFloatOrPercent>("first_layer_height")->value = 150.;
|
||||
config.option<ConfigOptionFloatOrPercent>("first_layer_height")->percent = true;
|
||||
// To let the PlaceholderParser throw when referencing first_layer_speed if it is set to percent, as the PlaceholderParser does not know
|
||||
// a percent to what.
|
||||
config.option<ConfigOptionFloatOrPercent>("first_layer_speed")->value = 50.;
|
||||
config.option<ConfigOptionFloatOrPercent>("first_layer_speed")->percent = true;
|
||||
|
||||
parser.apply_config(config);
|
||||
parser.set("foo", 0);
|
||||
parser.set("bar", 2);
|
||||
@ -41,6 +49,19 @@ SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") {
|
||||
SECTION("math: int(13.4)") { REQUIRE(parser.process("{int(13.4)}") == "13"); }
|
||||
SECTION("math: int(-13.4)") { REQUIRE(parser.process("{int(-13.4)}") == "-13"); }
|
||||
|
||||
// Test the "coFloatOrPercent" and "xxx_extrusion_width" substitutions.
|
||||
// first_layer_extrusion_width ratio_over first_layer_heigth ratio_over layer_height
|
||||
SECTION("perimeter_extrusion_width") { REQUIRE(std::stod(parser.process("{perimeter_extrusion_width}")) == Approx(0.67500001192092896)); }
|
||||
SECTION("first_layer_extrusion_width") { REQUIRE(std::stod(parser.process("{first_layer_extrusion_width}")) == Approx(0.9)); }
|
||||
SECTION("support_material_xy_spacing") { REQUIRE(std::stod(parser.process("{support_material_xy_spacing}")) == Approx(0.3375)); }
|
||||
// external_perimeter_speed over perimeter_speed
|
||||
SECTION("external_perimeter_speed") { REQUIRE(std::stod(parser.process("{external_perimeter_speed}")) == Approx(30.)); }
|
||||
// infill_overlap over perimeter_extrusion_width
|
||||
SECTION("infill_overlap") { REQUIRE(std::stod(parser.process("{infill_overlap}")) == Approx(0.16875)); }
|
||||
// If first_layer_speed is set to percent, then it is applied over respective extrusion types by overriding their respective speeds.
|
||||
// The PlaceholderParser has no way to know which extrusion type the caller has in mind, therefore it throws.
|
||||
SECTION("first_layer_speed") { REQUIRE_THROWS(parser.process("{first_layer_speed}")); }
|
||||
|
||||
// Test the boolean expression parser.
|
||||
auto boolean_expression = [&parser](const std::string& templ) { return parser.evaluate_boolean_expression(templ, parser.config()); };
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user