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.
|
// 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 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)
|
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"));
|
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;
|
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)
|
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;
|
std::vector<const char*> args;
|
||||||
|
@ -1494,8 +1494,49 @@ protected:
|
|||||||
ConfigOptionDef* add_nullable(const t_config_option_key &opt_key, ConfigOptionType type);
|
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.
|
// An abstract configuration store.
|
||||||
class ConfigBase
|
class ConfigBase : public ConfigOptionResolver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Definition of configuration values for the purpose of GUI presentation, editing, value mapping and config file handling.
|
// 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.
|
// but it carries the defaults of the configuration values.
|
||||||
|
|
||||||
ConfigBase() {}
|
ConfigBase() {}
|
||||||
virtual ~ConfigBase() {}
|
~ConfigBase() override {}
|
||||||
|
|
||||||
// Virtual overridables:
|
// Virtual overridables:
|
||||||
public:
|
public:
|
||||||
@ -1513,6 +1554,7 @@ public:
|
|||||||
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) = 0;
|
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.
|
// Collect names of all configuration values maintained by this configuration store.
|
||||||
virtual t_config_option_keys keys() const = 0;
|
virtual t_config_option_keys keys() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Verify whether the opt_key has not been obsoleted or renamed.
|
// Verify whether the opt_key has not been obsoleted or renamed.
|
||||||
// Both opt_key and value may be modified by handle_legacy().
|
// 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 {}
|
virtual void handle_legacy(t_config_option_key &/*opt_key*/, std::string &/*value*/) const {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
using ConfigOptionResolver::option;
|
||||||
|
using ConfigOptionResolver::option_throw;
|
||||||
|
|
||||||
// Non-virtual methods:
|
// 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)
|
ConfigOption* option(const t_config_option_key &opt_key, bool create = false)
|
||||||
{ return this->optptr(opt_key, create); }
|
{ return this->optptr(opt_key, create); }
|
||||||
|
|
||||||
@ -1537,10 +1577,6 @@ public:
|
|||||||
return (opt == nullptr || opt->type() != TYPE::static_type()) ? nullptr : static_cast<TYPE*>(opt);
|
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* option_throw(const t_config_option_key &opt_key, bool create = false)
|
||||||
{
|
{
|
||||||
ConfigOption *opt = this->optptr(opt_key, create);
|
ConfigOption *opt = this->optptr(opt_key, create);
|
||||||
@ -1549,9 +1585,6 @@ public:
|
|||||||
return opt;
|
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>
|
template<typename TYPE>
|
||||||
TYPE* option_throw(const t_config_option_key &opt_key, bool create = false)
|
TYPE* option_throw(const t_config_option_key &opt_key, bool create = false)
|
||||||
{
|
{
|
||||||
@ -1561,10 +1594,6 @@ public:
|
|||||||
return static_cast<TYPE*>(opt);
|
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.
|
// 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(),
|
// 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.
|
// 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)); }
|
{ return dynamic_cast<T*>(this->option(opt_key, create)); }
|
||||||
template<class T> const T* opt(const t_config_option_key &opt_key) const
|
template<class T> const T* opt(const t_config_option_key &opt_key) const
|
||||||
{ return dynamic_cast<const T*>(this->option(opt_key)); }
|
{ 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.
|
// 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;
|
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.
|
// Overrides ConfigBase::keys(). Collect names of all configuration values maintained by this configuration store.
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
#include "Flow.hpp"
|
#include "Flow.hpp"
|
||||||
|
#include "I18N.hpp"
|
||||||
#include "Print.hpp"
|
#include "Print.hpp"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Mark string for localization and translate.
|
||||||
|
#define L(s) Slic3r::I18N::translate(s)
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
// This static method returns a sane extrusion width default.
|
// 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) {
|
switch (role) {
|
||||||
case frSupportMaterial:
|
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
|
// This constructor builds a Flow object from an extrusion width config setting
|
||||||
// and other context properties.
|
// and other context properties.
|
||||||
Flow Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height, float bridge_flow_ratio)
|
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;
|
sqrt(bridge_flow_ratio) * nozzle_diameter;
|
||||||
} else if (! width.percent && width.value == 0.) {
|
} else if (! width.percent && width.value == 0.) {
|
||||||
// If user left option to 0, calculate a sane default width.
|
// 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 {
|
} else {
|
||||||
// If user set a manual value, use it.
|
// If user set a manual value, use it.
|
||||||
w = float(width.get_abs_value(height));
|
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
|
// 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.
|
// to fit a region with integer number of lines.
|
||||||
static Flow new_from_spacing(float spacing, float nozzle_diameter, float height, bool bridge);
|
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);
|
extern Flow support_material_flow(const PrintObject *object, float layer_height = 0.f);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "PlaceholderParser.hpp"
|
#include "PlaceholderParser.hpp"
|
||||||
|
#include "Flow.hpp"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <iomanip>
|
#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_old = config_old.option(opt_key);
|
||||||
const ConfigOption *opt_new = config_new.option(opt_key);
|
const ConfigOption *opt_new = config_new.option(opt_key);
|
||||||
assert(opt_new != nullptr);
|
assert(opt_new != nullptr);
|
||||||
if (opt_old == nullptr)
|
return opt_old != nullptr && *opt_new == *opt_old;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> PlaceholderParser::config_diff(const DynamicPrintConfig &rhs)
|
std::vector<std::string> PlaceholderParser::config_diff(const DynamicPrintConfig &rhs)
|
||||||
@ -126,14 +123,7 @@ bool PlaceholderParser::apply_config(const DynamicPrintConfig &rhs)
|
|||||||
bool modified = false;
|
bool modified = false;
|
||||||
for (const t_config_option_key &opt_key : rhs.keys()) {
|
for (const t_config_option_key &opt_key : rhs.keys()) {
|
||||||
if (! opts_equal(m_config, rhs, opt_key)) {
|
if (! opts_equal(m_config, rhs, opt_key)) {
|
||||||
// Store a copy of the config option.
|
this->set(opt_key, rhs.option(opt_key)->clone());
|
||||||
// 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());
|
|
||||||
modified = true;
|
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)
|
void PlaceholderParser::apply_only(const DynamicPrintConfig &rhs, const std::vector<std::string> &keys)
|
||||||
{
|
{
|
||||||
for (const t_config_option_key &opt_key : keys) {
|
for (const t_config_option_key &opt_key : keys)
|
||||||
// Store a copy of the config option.
|
this->set(opt_key, rhs.option(opt_key)->clone());
|
||||||
// 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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaceholderParser::apply_config(DynamicPrintConfig &&rhs)
|
void PlaceholderParser::apply_config(DynamicPrintConfig &&rhs)
|
||||||
@ -635,7 +617,7 @@ namespace client
|
|||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MyContext {
|
struct MyContext : public ConfigOptionResolver {
|
||||||
const DynamicConfig *external_config = nullptr;
|
const DynamicConfig *external_config = nullptr;
|
||||||
const DynamicConfig *config = nullptr;
|
const DynamicConfig *config = nullptr;
|
||||||
const DynamicConfig *config_override = 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; }
|
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;
|
const ConfigOption *opt = nullptr;
|
||||||
if (config_override != nullptr)
|
if (config_override != nullptr)
|
||||||
@ -662,6 +644,8 @@ namespace client
|
|||||||
return opt;
|
return opt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ConfigOption* resolve_symbol(const std::string &opt_key) const { return this->optptr(opt_key); }
|
||||||
|
|
||||||
template <typename Iterator>
|
template <typename Iterator>
|
||||||
static void legacy_variable_expansion(
|
static void legacy_variable_expansion(
|
||||||
const MyContext *ctx,
|
const MyContext *ctx,
|
||||||
@ -758,7 +742,43 @@ namespace client
|
|||||||
case coPoint: output.set_s(opt.opt->serialize()); break;
|
case coPoint: output.set_s(opt.opt->serialize()); break;
|
||||||
case coBool: output.set_b(opt.opt->getBool()); break;
|
case coBool: output.set_b(opt.opt->getBool()); break;
|
||||||
case coFloatOrPercent:
|
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:
|
default:
|
||||||
ctx->throw_exception("Unknown scalar variable type", opt.it_range);
|
ctx->throw_exception("Unknown scalar variable type", opt.it_range);
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,7 @@
|
|||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
//! macro used to mark string used at localization,
|
// Mark string for localization and translate.
|
||||||
//! return same string
|
|
||||||
#define L(s) Slic3r::I18N::translate(s)
|
#define L(s) Slic3r::I18N::translate(s)
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
@ -527,7 +526,6 @@ void Print::config_diffs(
|
|||||||
const DynamicPrintConfig &new_full_config,
|
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 &print_diff, t_config_option_keys &object_diff, t_config_option_keys ®ion_diff,
|
||||||
t_config_option_keys &full_config_diff,
|
t_config_option_keys &full_config_diff,
|
||||||
DynamicPrintConfig &placeholder_parser_overrides,
|
|
||||||
DynamicPrintConfig &filament_overrides) const
|
DynamicPrintConfig &filament_overrides) const
|
||||||
{
|
{
|
||||||
// Collect changes to print config, account for overrides of extruder retract values by filament presets.
|
// 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);
|
object_diff = m_default_object_config.diff(new_full_config);
|
||||||
region_diff = m_default_region_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.
|
// 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()) {
|
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_old = m_full_print_config.option(opt_key);
|
||||||
const ConfigOption *opt_new = new_full_config.option(opt_key);
|
const ConfigOption *opt_new = new_full_config.option(opt_key);
|
||||||
if (opt_old == nullptr || *opt_new != *opt_old)
|
if (opt_old == nullptr || *opt_new != *opt_old)
|
||||||
full_config_diff.emplace_back(opt_key);
|
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.
|
// 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;
|
t_config_option_keys print_diff, object_diff, region_diff, full_config_diff;
|
||||||
DynamicPrintConfig placeholder_parser_overrides, filament_overrides;
|
DynamicPrintConfig filament_overrides;
|
||||||
this->config_diffs(new_full_config, print_diff, object_diff, region_diff, full_config_diff, placeholder_parser_overrides, 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.
|
// Do not use the ApplyStatus as we will use the max function when updating apply_status.
|
||||||
unsigned int apply_status = APPLY_STATUS_UNCHANGED;
|
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.
|
// which should be stopped if print_diff is not empty.
|
||||||
size_t num_extruders = m_config.nozzle_diameter.size();
|
size_t num_extruders = m_config.nozzle_diameter.size();
|
||||||
bool num_extruders_changed = false;
|
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));
|
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()
|
// 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("print_preset", new_full_config.option("print_settings_id")->clone());
|
||||||
m_placeholder_parser.set("filament_preset", new_full_config.option("filament_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,
|
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 &print_diff, t_config_option_keys &object_diff, t_config_option_keys ®ion_diff,
|
||||||
t_config_option_keys &full_config_diff,
|
t_config_option_keys &full_config_diff,
|
||||||
DynamicPrintConfig &placeholder_parser_overrides,
|
|
||||||
DynamicPrintConfig &filament_overrides) const;
|
DynamicPrintConfig &filament_overrides) const;
|
||||||
|
|
||||||
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
|
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_type = "f_enum_open";
|
||||||
def->gui_flags = "show_value";
|
def->gui_flags = "show_value";
|
||||||
def->enum_values.push_back("PLA");
|
def->enum_values.push_back("PLA");
|
||||||
def->enum_values.push_back("ABS");
|
|
||||||
def->enum_values.push_back("PET");
|
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("FLEX");
|
||||||
def->enum_values.push_back("HIPS");
|
def->enum_values.push_back("HIPS");
|
||||||
def->enum_values.push_back("EDGE");
|
def->enum_values.push_back("EDGE");
|
||||||
|
@ -46,12 +46,6 @@ enum SeamPosition {
|
|||||||
spRandom, spNearest, spAligned, spRear
|
spRandom, spNearest, spAligned, spRear
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
enum FilamentType {
|
|
||||||
ftPLA, ftABS, ftPET, ftHIPS, ftFLEX, ftSCAFF, ftEDGE, ftNGEN, ftPVA
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum SLAMaterial {
|
enum SLAMaterial {
|
||||||
slamTough,
|
slamTough,
|
||||||
slamFlex,
|
slamFlex,
|
||||||
@ -149,24 +143,6 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<SeamPosition>::ge
|
|||||||
return keys_map;
|
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() {
|
template<> inline const t_config_enum_values& ConfigOptionEnum<SLADisplayOrientation>::get_enum_values() {
|
||||||
static const t_config_enum_values keys_map = {
|
static const t_config_enum_values keys_map = {
|
||||||
{ "landscape", sladoLandscape},
|
{ "landscape", sladoLandscape},
|
||||||
@ -354,6 +330,9 @@ protected:
|
|||||||
#define STATIC_PRINT_CONFIG_CACHE_BASE(CLASS_NAME) \
|
#define STATIC_PRINT_CONFIG_CACHE_BASE(CLASS_NAME) \
|
||||||
public: \
|
public: \
|
||||||
/* Overrides ConfigBase::optptr(). Find ando/or create a ConfigOption instance for a given name. */ \
|
/* 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 \
|
ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) override \
|
||||||
{ return s_cache_##CLASS_NAME.optptr(opt_key, this); } \
|
{ return s_cache_##CLASS_NAME.optptr(opt_key, this); } \
|
||||||
/* Overrides ConfigBase::keys(). Collect names of all configuration values maintained by this configuration store. */ \
|
/* 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" },
|
{ "nozzle_diameter", "0.6;0.6;0.6;0.6" },
|
||||||
{ "temperature", "357;359;363;378" }
|
{ "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.apply_config(config);
|
||||||
parser.set("foo", 0);
|
parser.set("foo", 0);
|
||||||
parser.set("bar", 2);
|
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"); }
|
||||||
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.
|
// Test the boolean expression parser.
|
||||||
auto boolean_expression = [&parser](const std::string& templ) { return parser.evaluate_boolean_expression(templ, parser.config()); };
|
auto boolean_expression = [&parser](const std::string& templ) { return parser.evaluate_boolean_expression(templ, parser.config()); };
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user