Optimization of the configuration layer:

The values of StaticPrintConfig derived objects were searched by a name
walking through a huge chained if.
Now they are being mapped with a std::map.
Also initialization of StaticPrintConfig classes from their ConfigOptionDef
defaults is done by maintaining a single global definition of each
StaticPrintConfig derived class, and a new instance is initialized
from this static copy.

Also the ConfigOption instances are casted using static_cast
wherever possible, and their types are verified by a virtual type() method.
This approach avoids insiginificant performance penalty of a dynamic_cast.

Also the compare and clone methods were added to ConfigOption,
and the cloning & compare work on binary values, not by serialization.
This commit is contained in:
bubnikv 2017-10-17 16:01:18 +02:00
parent a91d7cb2f7
commit 3731820c48
14 changed files with 1475 additions and 934 deletions

View File

@ -31,10 +31,9 @@ $Options->{threads}{readonly} = !$Slic3r::have_threads;
# Fill in the underlying C++ Slic3r::DynamicPrintConfig with the content of the defaults # Fill in the underlying C++ Slic3r::DynamicPrintConfig with the content of the defaults
# provided by the C++ class Slic3r::FullPrintConfig. # provided by the C++ class Slic3r::FullPrintConfig.
# Used by the UI.
sub new_from_defaults { sub new_from_defaults {
my $class = shift; my ($class, @opt_keys) = @_;
my (@opt_keys) = @_;
my $self = $class->new; my $self = $class->new;
# Instantiating the C++ class Slic3r::FullPrintConfig. # Instantiating the C++ class Slic3r::FullPrintConfig.
my $defaults = Slic3r::Config::Full->new; my $defaults = Slic3r::Config::Full->new;
@ -47,7 +46,7 @@ sub new_from_defaults {
return $self; return $self;
} }
# From command line parameters # From command line parameters, used by slic3r.pl
sub new_from_cli { sub new_from_cli {
my $class = shift; my $class = shift;
my %args = @_; my %args = @_;
@ -112,12 +111,6 @@ sub load {
} }
} }
# Save the content of the underlying C++ Slic3r::DynamicPrintConfig as a flat ini file without any category.
sub save {
my ($self, $file) = @_;
return $self->_save($file);
}
# Deserialize a perl hash into the underlying C++ Slic3r::DynamicConfig class, # Deserialize a perl hash into the underlying C++ Slic3r::DynamicConfig class,
# convert legacy configuration names. # convert legacy configuration names.
# Used to load a config bundle. # Used to load a config bundle.
@ -309,6 +302,7 @@ sub validate {
# CLASS METHODS: # CLASS METHODS:
# Write a "Windows" style ini file with categories enclosed in squre brackets. # Write a "Windows" style ini file with categories enclosed in squre brackets.
# Used by config-bundle-to-config.pl and to save slic3r.ini.
sub write_ini { sub write_ini {
my $class = shift; my $class = shift;
my ($file, $ini) = @_; my ($file, $ini) = @_;
@ -331,6 +325,7 @@ sub write_ini {
# Returns a hash of hashes over strings. # Returns a hash of hashes over strings.
# {category}{name}=value # {category}{name}=value
# Non-categorized entries are stored under a category '_'. # Non-categorized entries are stored under a category '_'.
# Used by config-bundle-to-config.pl and to read slic3r.ini.
sub read_ini { sub read_ini {
my $class = shift; my $class = shift;
my ($file) = @_; my ($file) = @_;

View File

@ -177,20 +177,24 @@ bool unescape_strings_cstyle(const std::string &str, std::vector<std::string> &o
} }
} }
void ConfigBase::apply(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent) void ConfigBase::apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent)
{ {
// loop through options and apply them // loop through options and apply them
for (const t_config_option_key &key : keys) { for (const t_config_option_key &opt_key : keys) {
ConfigOption *my_opt = this->option(key, true); // Create a new option with default value for the key.
// If the key is not in the parameter definition, or this ConfigBase is a static type and it does not support the parameter,
// an exception is thrown if not ignore_nonexistent.
ConfigOption *my_opt = this->option(opt_key, true);
if (my_opt == nullptr) { if (my_opt == nullptr) {
if (! ignore_nonexistent) // opt_key does not exist in this ConfigBase and it cannot be created, because it is not defined by this->def().
throw "Attempt to apply non-existent option"; // This is only possible if other is of DynamicConfig type.
continue; if (ignore_nonexistent)
continue;
throw UnknownOptionException();
} }
// not the most efficient way, but easier than casting pointers to subclasses const ConfigOption *other_opt = other.option(opt_key);
const ConfigOption *other_opt = other.option(key); if (other_opt != nullptr)
if (other_opt != nullptr && ! my_opt->deserialize(other_opt->serialize())) my_opt->set(other_opt);
CONFESS((std::string("Unexpected failure when deserializing serialized value for ") + key).c_str());
} }
} }
@ -198,9 +202,12 @@ void ConfigBase::apply(const ConfigBase &other, const t_config_option_keys &keys
t_config_option_keys ConfigBase::diff(const ConfigBase &other) const t_config_option_keys ConfigBase::diff(const ConfigBase &other) const
{ {
t_config_option_keys diff; t_config_option_keys diff;
for (const t_config_option_key &opt_key : this->keys()) for (const t_config_option_key &opt_key : this->keys()) {
if (other.has(opt_key) && other.serialize(opt_key) != this->serialize(opt_key)) const ConfigOption *this_opt = this->option(opt_key);
diff.push_back(opt_key); const ConfigOption *other_opt = other.option(opt_key);
if (this_opt != nullptr && other_opt != nullptr && *this_opt != *other_opt)
diff.emplace_back(opt_key);
}
return diff; return diff;
} }
@ -211,12 +218,27 @@ std::string ConfigBase::serialize(const t_config_option_key &opt_key) const
return opt->serialize(); return opt->serialize();
} }
bool ConfigBase::set_deserialize(t_config_option_key opt_key, const std::string &str, bool append) bool ConfigBase::set_deserialize(const t_config_option_key &opt_key_src, const std::string &value_src, bool append)
{ {
const ConfigOptionDef* optdef = this->def->get(opt_key); t_config_option_key opt_key = opt_key_src;
std::string value = value_src;
// Both opt_key and value may be modified by _handle_legacy().
// If the opt_key is no more valid in this version of Slic3r, opt_key is cleared by _handle_legacy().
this->handle_legacy(opt_key, value);
if (opt_key.empty())
// Ignore the option.
return true;
return this->set_deserialize_raw(opt_key, value, append);
}
bool ConfigBase::set_deserialize_raw(const t_config_option_key &opt_key_src, const std::string &value, bool append)
{
t_config_option_key opt_key = opt_key_src;
// Try to deserialize the option by its name.
const ConfigOptionDef* optdef = this->def()->get(opt_key);
if (optdef == nullptr) { if (optdef == nullptr) {
// If we didn't find an option, look for any other option having this as an alias. // If we didn't find an option, look for any other option having this as an alias.
for (const auto &opt : this->def->options) { for (const auto &opt : this->def()->options) {
for (const t_config_option_key &opt_key2 : opt.second.aliases) { for (const t_config_option_key &opt_key2 : opt.second.aliases) {
if (opt_key2 == opt_key) { if (opt_key2 == opt_key) {
opt_key = opt_key2; opt_key = opt_key2;
@ -232,44 +254,49 @@ bool ConfigBase::set_deserialize(t_config_option_key opt_key, const std::string
} }
if (! optdef->shortcut.empty()) { if (! optdef->shortcut.empty()) {
// Aliasing for example "solid_layers" to "top_solid_layers" and "bottom_solid_layers".
for (const t_config_option_key &shortcut : optdef->shortcut) for (const t_config_option_key &shortcut : optdef->shortcut)
if (! this->set_deserialize(shortcut, str)) // Recursive call.
if (! this->set_deserialize_raw(shortcut, value, append))
return false; return false;
return true; return true;
} }
ConfigOption *opt = this->option(opt_key, true); ConfigOption *opt = this->option(opt_key, true);
assert(opt != nullptr); assert(opt != nullptr);
return opt->deserialize(str, append); return opt->deserialize(value, append);
} }
// Return an absolute value of a possibly relative config variable. // Return an absolute value of a possibly relative config variable.
// For example, return absolute infill extrusion width, either from an absolute value, or relative to the layer height. // For example, return absolute infill extrusion width, either from an absolute value, or relative to the layer height.
double ConfigBase::get_abs_value(const t_config_option_key &opt_key) const double ConfigBase::get_abs_value(const t_config_option_key &opt_key) const
{ {
const ConfigOption* opt = this->option(opt_key); // Get stored option value.
if (const ConfigOptionFloatOrPercent* optv = dynamic_cast<const ConfigOptionFloatOrPercent*>(opt)) { const ConfigOption *raw_opt = this->option(opt_key);
// get option definition assert(raw_opt != nullptr);
const ConfigOptionDef* def = this->def->get(opt_key); if (raw_opt->type() == coFloat)
return static_cast<const ConfigOptionFloat*>(raw_opt)->value;
if (raw_opt->type() == coFloatOrPercent) {
// Get option definition.
const ConfigOptionDef *def = this->def()->get(opt_key);
assert(def != nullptr); assert(def != nullptr);
// compute absolute value over the absolute value of the base option // Compute absolute value over the absolute value of the base option.
return optv->get_abs_value(this->get_abs_value(def->ratio_over)); return static_cast<const ConfigOptionFloatOrPercent*>(raw_opt)->get_abs_value(this->get_abs_value(def->ratio_over));
} else if (const ConfigOptionFloat* optv = dynamic_cast<const ConfigOptionFloat*>(opt)) {
return optv->value;
} else {
throw "Not a valid option type for get_abs_value()";
} }
throw std::runtime_error("ConfigBase::get_abs_value(): Not a valid option type for get_abs_value()");
} }
// Return an absolute value of a possibly relative config variable. // Return an absolute value of a possibly relative config variable.
// For example, return absolute infill extrusion width, either from an absolute value, or relative to a provided value. // For example, return absolute infill extrusion width, either from an absolute value, or relative to a provided value.
double ConfigBase::get_abs_value(const t_config_option_key &opt_key, double ratio_over) const double ConfigBase::get_abs_value(const t_config_option_key &opt_key, double ratio_over) const
{ {
// get stored option value // Get stored option value.
const ConfigOptionFloatOrPercent* opt = dynamic_cast<const ConfigOptionFloatOrPercent*>(this->option(opt_key)); const ConfigOption *raw_opt = this->option(opt_key);
assert(opt != nullptr); assert(raw_opt != nullptr);
// compute absolute value if (raw_opt->type() != coFloatOrPercent)
return opt->get_abs_value(ratio_over); throw std::runtime_error("ConfigBase::get_abs_value(): opt_key is not of coFloatOrPercent");
// Compute absolute value.
return static_cast<const ConfigOptionFloatOrPercent*>(raw_opt)->get_abs_value(ratio_over);
} }
void ConfigBase::setenv_() void ConfigBase::setenv_()
@ -301,8 +328,7 @@ void ConfigBase::load(const std::string &file)
for (const pt::ptree::value_type &v : tree) { for (const pt::ptree::value_type &v : tree) {
try { try {
t_config_option_key opt_key = v.first; t_config_option_key opt_key = v.first;
std::string value = v.second.get_value<std::string>(); this->set_deserialize(opt_key, v.second.get_value<std::string>());
this->set_deserialize(opt_key, value);
} catch (UnknownOptionException & /* e */) { } catch (UnknownOptionException & /* e */) {
// ignore // ignore
} }
@ -400,64 +426,43 @@ void ConfigBase::save(const std::string &file) const
c.close(); c.close();
} }
ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool create) { ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool create)
{
t_options_map::iterator it = options.find(opt_key); t_options_map::iterator it = options.find(opt_key);
if (it == options.end()) { if (it != options.end())
if (create) { // Option was found.
const ConfigOptionDef* optdef = this->def->get(opt_key); return it->second;
assert(optdef != NULL); if (! create)
ConfigOption* opt; // Option was not found and a new option shall not be created.
if (optdef->type == coFloat) { return nullptr;
opt = new ConfigOptionFloat (); // Try to create a new ConfigOption.
} else if (optdef->type == coFloats) { const ConfigOptionDef *optdef = this->def()->get(opt_key);
opt = new ConfigOptionFloats (); if (optdef == nullptr)
} else if (optdef->type == coInt) { // throw std::runtime_error(std::string("Invalid option name: ") + opt_key);
opt = new ConfigOptionInt (); // Let the parent decide what to do if the opt_key is not defined by this->def().
} else if (optdef->type == coInts) { return nullptr;
opt = new ConfigOptionInts (); ConfigOption *opt = nullptr;
} else if (optdef->type == coString) { switch (optdef->type) {
opt = new ConfigOptionString (); case coFloat: opt = new ConfigOptionFloat(); break;
} else if (optdef->type == coStrings) { case coFloats: opt = new ConfigOptionFloats(); break;
opt = new ConfigOptionStrings (); case coInt: opt = new ConfigOptionInt(); break;
} else if (optdef->type == coPercent) { case coInts: opt = new ConfigOptionInts(); break;
opt = new ConfigOptionPercent (); case coString: opt = new ConfigOptionString(); break;
} else if (optdef->type == coPercents) { case coStrings: opt = new ConfigOptionStrings(); break;
opt = new ConfigOptionPercents (); case coPercent: opt = new ConfigOptionPercent(); break;
} else if (optdef->type == coFloatOrPercent) { case coPercents: opt = new ConfigOptionPercents(); break;
opt = new ConfigOptionFloatOrPercent (); case coFloatOrPercent: opt = new ConfigOptionFloatOrPercent(); break;
} else if (optdef->type == coPoint) { case coPoint: opt = new ConfigOptionPoint(); break;
opt = new ConfigOptionPoint (); case coPoints: opt = new ConfigOptionPoints(); break;
} else if (optdef->type == coPoints) { case coBool: opt = new ConfigOptionBool(); break;
opt = new ConfigOptionPoints (); case coBools: opt = new ConfigOptionBools(); break;
} else if (optdef->type == coBool) { case coEnum: opt = new ConfigOptionEnumGeneric(optdef->enum_keys_map); break;
opt = new ConfigOptionBool (); default: throw std::runtime_error(std::string("Unknown option type for option ") + opt_key);
} else if (optdef->type == coBools) {
opt = new ConfigOptionBools ();
} else if (optdef->type == coEnum) {
ConfigOptionEnumGeneric* optv = new ConfigOptionEnumGeneric ();
optv->keys_map = &optdef->enum_keys_map;
opt = static_cast<ConfigOption*>(optv);
} else {
throw "Unknown option type";
}
this->options[opt_key] = opt;
return opt;
} else {
return NULL;
}
} }
return it->second; this->options[opt_key] = opt;
return opt;
} }
template<class T>
T* DynamicConfig::opt(const t_config_option_key &opt_key, bool create) {
return dynamic_cast<T*>(this->option(opt_key, create));
}
template ConfigOptionInt* DynamicConfig::opt<ConfigOptionInt>(const t_config_option_key &opt_key, bool create);
template ConfigOptionBool* DynamicConfig::opt<ConfigOptionBool>(const t_config_option_key &opt_key, bool create);
template ConfigOptionBools* DynamicConfig::opt<ConfigOptionBools>(const t_config_option_key &opt_key, bool create);
template ConfigOptionPercent* DynamicConfig::opt<ConfigOptionPercent>(const t_config_option_key &opt_key, bool create);
t_config_option_keys DynamicConfig::keys() const t_config_option_keys DynamicConfig::keys() const
{ {
t_config_option_keys keys; t_config_option_keys keys;
@ -470,11 +475,13 @@ t_config_option_keys DynamicConfig::keys() const
void StaticConfig::set_defaults() void StaticConfig::set_defaults()
{ {
// use defaults from definition // use defaults from definition
if (this->def != nullptr) { auto *defs = this->def();
if (defs != nullptr) {
for (const std::string &key : this->keys()) { for (const std::string &key : this->keys()) {
const ConfigOptionDef* def = this->def->get(key); const ConfigOptionDef *def = defs->get(key);
if (def->default_value != nullptr) ConfigOption *opt = this->option(key);
this->option(key)->set(*def->default_value); if (def != nullptr && opt != nullptr && def->default_value != nullptr)
opt->set(def->default_value);
} }
} }
} }
@ -483,7 +490,7 @@ t_config_option_keys StaticConfig::keys() const
{ {
t_config_option_keys keys; t_config_option_keys keys;
assert(this->def != nullptr); assert(this->def != nullptr);
for (const auto &opt_def : this->def->options) for (const auto &opt_def : this->def()->options)
if (this->option(opt_def.first) != nullptr) if (this->option(opt_def.first) != nullptr)
keys.push_back(opt_def.first); keys.push_back(opt_def.first);
return keys; return keys;

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,13 @@
namespace Slic3r { namespace Slic3r {
void GCodeReader::apply_config(const PrintConfigBase &config) void GCodeReader::apply_config(const GCodeConfig &config)
{
m_config = config;
m_extrusion_axis = m_config.get_extrusion_axis()[0];
}
void GCodeReader::apply_config(const DynamicPrintConfig &config)
{ {
m_config.apply(config, true); m_config.apply(config, true);
m_extrusion_axis = m_config.get_extrusion_axis()[0]; m_extrusion_axis = m_config.get_extrusion_axis()[0];

View File

@ -50,7 +50,8 @@ public:
callback_t callback; callback_t callback;
GCodeReader() : X(0), Y(0), Z(0), E(0), F(0), verbose(false), m_extrusion_axis('E') {}; GCodeReader() : X(0), Y(0), Z(0), E(0), F(0), verbose(false), m_extrusion_axis('E') {};
void apply_config(const PrintConfigBase &config); void apply_config(const GCodeConfig &config);
void apply_config(const DynamicPrintConfig &config);
void parse(const std::string &gcode, callback_t callback); void parse(const std::string &gcode, callback_t callback);
void parse_line(std::string line, callback_t callback); void parse_line(std::string line, callback_t callback);
void parse_file(const std::string &file, callback_t callback); void parse_file(const std::string &file, callback_t callback);

View File

@ -260,7 +260,7 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer)
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG
printf("Processing bridge at layer " PRINTF_ZU ":\n", this->layer()->id()); printf("Processing bridge at layer " PRINTF_ZU ":\n", this->layer()->id());
#endif #endif
if (bd.detect_angle(Geometry::deg2rad(this->region()->config.bridge_angle))) { if (bd.detect_angle(Geometry::deg2rad(this->region()->config.bridge_angle.value))) {
bridges[idx_last].bridge_angle = bd.angle; bridges[idx_last].bridge_angle = bd.angle;
if (this->layer()->object()->config.support_material) { if (this->layer()->object()->config.support_material) {
polygons_append(this->bridged, bd.coverage()); polygons_append(this->bridged, bd.coverage());

View File

@ -64,7 +64,7 @@ void PlaceholderParser::update_timestamp()
void PlaceholderParser::apply_config(const DynamicPrintConfig &config) void PlaceholderParser::apply_config(const DynamicPrintConfig &config)
{ {
for (const t_config_option_key &opt_key : config.keys()) { for (const t_config_option_key &opt_key : config.keys()) {
const ConfigOptionDef* def = config.def->get(opt_key); const ConfigOptionDef* def = config.def()->get(opt_key);
if (def->multiline || opt_key == "post_process") if (def->multiline || opt_key == "post_process")
continue; continue;

View File

@ -389,7 +389,7 @@ bool Print::apply_config(DynamicPrintConfig config)
// handle changes to print config // handle changes to print config
t_config_option_keys print_diff = this->config.diff(config); t_config_option_keys print_diff = this->config.diff(config);
this->config.apply(config, print_diff, true); this->config.apply_only(config, print_diff, true);
bool invalidated = this->invalidate_state_by_config_options(print_diff); bool invalidated = this->invalidate_state_by_config_options(print_diff);
// handle changes to object config defaults // handle changes to object config defaults
@ -410,7 +410,7 @@ bool Print::apply_config(DynamicPrintConfig config)
} }
// check whether the new config is different from the current one // check whether the new config is different from the current one
t_config_option_keys diff = object->config.diff(new_config); t_config_option_keys diff = object->config.diff(new_config);
object->config.apply(new_config, diff, true); object->config.apply_only(new_config, diff, true);
invalidated |= object->invalidate_state_by_config_options(diff); invalidated |= object->invalidate_state_by_config_options(diff);
} }
@ -460,7 +460,7 @@ bool Print::apply_config(DynamicPrintConfig config)
if (this_region_config_set) { if (this_region_config_set) {
t_config_option_keys diff = region.config.diff(this_region_config); t_config_option_keys diff = region.config.diff(this_region_config);
if (! diff.empty()) { if (! diff.empty()) {
region.config.apply(this_region_config, diff); region.config.apply_only(this_region_config, diff);
for (PrintObject *object : this->objects) for (PrintObject *object : this->objects)
if (region_id < object->region_volumes.size() && ! object->region_volumes[region_id].empty()) if (region_id < object->region_volumes.size() && ! object->region_volumes[region_id].empty())
invalidated |= object->invalidate_state_by_config_options(diff); invalidated |= object->invalidate_state_by_config_options(diff);

View File

@ -2,6 +2,7 @@
#include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/replace.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include <float.h>
namespace Slic3r { namespace Slic3r {
@ -221,7 +222,7 @@ PrintConfigDef::PrintConfigDef()
def->category = "Infill"; def->category = "Infill";
def->tooltip = "Fill pattern for top/bottom infill. This only affects the external visible layer, and not its adjacent solid shells."; def->tooltip = "Fill pattern for top/bottom infill. This only affects the external visible layer, and not its adjacent solid shells.";
def->cli = "external-fill-pattern|solid-fill-pattern=s"; def->cli = "external-fill-pattern|solid-fill-pattern=s";
def->enum_keys_map = ConfigOptionEnum<InfillPattern>::get_enum_values(); def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
def->enum_values.push_back("rectilinear"); def->enum_values.push_back("rectilinear");
def->enum_values.push_back("concentric"); def->enum_values.push_back("concentric");
def->enum_values.push_back("hilbertcurve"); def->enum_values.push_back("hilbertcurve");
@ -529,7 +530,7 @@ PrintConfigDef::PrintConfigDef()
def->category = "Infill"; def->category = "Infill";
def->tooltip = "Fill pattern for general low-density infill."; def->tooltip = "Fill pattern for general low-density infill.";
def->cli = "fill-pattern=s"; def->cli = "fill-pattern=s";
def->enum_keys_map = ConfigOptionEnum<InfillPattern>::get_enum_values(); def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
def->enum_values.push_back("rectilinear"); def->enum_values.push_back("rectilinear");
def->enum_values.push_back("grid"); def->enum_values.push_back("grid");
def->enum_values.push_back("triangles"); def->enum_values.push_back("triangles");
@ -633,7 +634,7 @@ PrintConfigDef::PrintConfigDef()
def->label = "G-code flavor"; def->label = "G-code flavor";
def->tooltip = "Some G/M-code commands, including temperature control and others, are not universal. Set this option to your printer's firmware to get a compatible output. The \"No extrusion\" flavor prevents Slic3r from exporting any extrusion value at all."; def->tooltip = "Some G/M-code commands, including temperature control and others, are not universal. Set this option to your printer's firmware to get a compatible output. The \"No extrusion\" flavor prevents Slic3r from exporting any extrusion value at all.";
def->cli = "gcode-flavor=s"; def->cli = "gcode-flavor=s";
def->enum_keys_map = ConfigOptionEnum<GCodeFlavor>::get_enum_values(); def->enum_keys_map = &ConfigOptionEnum<GCodeFlavor>::get_enum_values();
def->enum_values.push_back("reprap"); def->enum_values.push_back("reprap");
def->enum_values.push_back("repetier"); def->enum_values.push_back("repetier");
def->enum_values.push_back("teacup"); def->enum_values.push_back("teacup");
@ -1136,7 +1137,7 @@ PrintConfigDef::PrintConfigDef()
def->category = "Layers and Perimeters"; def->category = "Layers and Perimeters";
def->tooltip = "Position of perimeters starting points."; def->tooltip = "Position of perimeters starting points.";
def->cli = "seam-position=s"; def->cli = "seam-position=s";
def->enum_keys_map = ConfigOptionEnum<SeamPosition>::get_enum_values(); def->enum_keys_map = &ConfigOptionEnum<SeamPosition>::get_enum_values();
def->enum_values.push_back("random"); def->enum_values.push_back("random");
def->enum_values.push_back("nearest"); def->enum_values.push_back("nearest");
def->enum_values.push_back("aligned"); def->enum_values.push_back("aligned");
@ -1458,7 +1459,7 @@ PrintConfigDef::PrintConfigDef()
def->category = "Support material"; def->category = "Support material";
def->tooltip = "Pattern used to generate support material."; def->tooltip = "Pattern used to generate support material.";
def->cli = "support-material-pattern=s"; def->cli = "support-material-pattern=s";
def->enum_keys_map = ConfigOptionEnum<SupportMaterialPattern>::get_enum_values(); def->enum_keys_map = &ConfigOptionEnum<SupportMaterialPattern>::get_enum_values();
def->enum_values.push_back("rectilinear"); def->enum_values.push_back("rectilinear");
def->enum_values.push_back("rectilinear-grid"); def->enum_values.push_back("rectilinear-grid");
def->enum_values.push_back("honeycomb"); def->enum_values.push_back("honeycomb");
@ -1538,7 +1539,7 @@ PrintConfigDef::PrintConfigDef()
def->readonly = true; def->readonly = true;
def->min = 1; def->min = 1;
{ {
unsigned int threads = boost::thread::hardware_concurrency(); int threads = (unsigned int)boost::thread::hardware_concurrency();
def->default_value = new ConfigOptionInt(threads > 0 ? threads : 2); def->default_value = new ConfigOptionInt(threads > 0 ? threads : 2);
} }
@ -1671,56 +1672,7 @@ PrintConfigDef::PrintConfigDef()
def->default_value = new ConfigOptionFloat(0); def->default_value = new ConfigOptionFloat(0);
} }
PrintConfigDef print_config_def; void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value)
void
DynamicPrintConfig::normalize() {
if (this->has("extruder")) {
int extruder = this->option("extruder")->getInt();
this->erase("extruder");
if (extruder != 0) {
if (!this->has("infill_extruder"))
this->option("infill_extruder", true)->setInt(extruder);
if (!this->has("perimeter_extruder"))
this->option("perimeter_extruder", true)->setInt(extruder);
// Don't propagate the current extruder to support.
// For non-soluble supports, the default "0" extruder means to use the active extruder,
// for soluble supports one certainly does not want to set the extruder to non-soluble.
// if (!this->has("support_material_extruder"))
// this->option("support_material_extruder", true)->setInt(extruder);
// if (!this->has("support_material_interface_extruder"))
// this->option("support_material_interface_extruder", true)->setInt(extruder);
}
}
if (!this->has("solid_infill_extruder") && this->has("infill_extruder"))
this->option("solid_infill_extruder", true)->setInt(this->option("infill_extruder")->getInt());
if (this->has("spiral_vase") && this->opt<ConfigOptionBool>("spiral_vase", true)->value) {
{
// this should be actually done only on the spiral layers instead of all
ConfigOptionBools* opt = this->opt<ConfigOptionBools>("retract_layer_change", true);
opt->values.assign(opt->values.size(), false); // set all values to false
}
{
this->opt<ConfigOptionInt>("perimeters", true)->value = 1;
this->opt<ConfigOptionInt>("top_solid_layers", true)->value = 0;
this->opt<ConfigOptionPercent>("fill_density", true)->value = 0;
}
}
}
bool PrintConfigBase::set_deserialize(t_config_option_key opt_key, std::string str, bool append)
{
this->_handle_legacy(opt_key, str);
return opt_key.empty() ?
// ignore option
true :
ConfigBase::set_deserialize(opt_key, str, append);
}
void PrintConfigBase::_handle_legacy(t_config_option_key &opt_key, std::string &value) const
{ {
// handle legacy options // handle legacy options
if (opt_key == "extrusion_width_ratio" || opt_key == "bottom_layer_speed_ratio" if (opt_key == "extrusion_width_ratio" || opt_key == "bottom_layer_speed_ratio"
@ -1783,22 +1735,249 @@ void PrintConfigBase::_handle_legacy(t_config_option_key &opt_key, std::string &
return; return;
} }
if (!this->def->has(opt_key)) { if (! print_config_def.has(opt_key)) {
//printf("Unknown option %s\n", opt_key.c_str()); //printf("Unknown option %s\n", opt_key.c_str());
opt_key = ""; opt_key = "";
return; return;
} }
} }
double PrintConfigBase::min_object_distance() const PrintConfigDef print_config_def;
void DynamicPrintConfig::normalize()
{ {
double extruder_clearance_radius = this->option("extruder_clearance_radius")->getFloat(); if (this->has("extruder")) {
double duplicate_distance = this->option("duplicate_distance")->getFloat(); int extruder = this->option("extruder")->getInt();
this->erase("extruder");
if (extruder != 0) {
if (!this->has("infill_extruder"))
this->option("infill_extruder", true)->setInt(extruder);
if (!this->has("perimeter_extruder"))
this->option("perimeter_extruder", true)->setInt(extruder);
// Don't propagate the current extruder to support.
// For non-soluble supports, the default "0" extruder means to use the active extruder,
// for soluble supports one certainly does not want to set the extruder to non-soluble.
// if (!this->has("support_material_extruder"))
// this->option("support_material_extruder", true)->setInt(extruder);
// if (!this->has("support_material_interface_extruder"))
// this->option("support_material_interface_extruder", true)->setInt(extruder);
}
}
if (!this->has("solid_infill_extruder") && this->has("infill_extruder"))
this->option("solid_infill_extruder", true)->setInt(this->option("infill_extruder")->getInt());
if (this->has("spiral_vase") && this->opt<ConfigOptionBool>("spiral_vase", true)->value) {
{
// this should be actually done only on the spiral layers instead of all
ConfigOptionBools* opt = this->opt<ConfigOptionBools>("retract_layer_change", true);
opt->values.assign(opt->values.size(), false); // set all values to false
}
{
this->opt<ConfigOptionInt>("perimeters", true)->value = 1;
this->opt<ConfigOptionInt>("top_solid_layers", true)->value = 0;
this->opt<ConfigOptionPercent>("fill_density", true)->value = 0;
}
}
}
std::string DynamicPrintConfig::validate()
{
// Full print config is initialized from the defaults.
FullPrintConfig fpc;
fpc.apply(*this);
// Verify this print options through the FullPrintConfig.
return fpc.validate();
}
double PrintConfig::min_object_distance() const
{
return PrintConfig::min_object_distance(static_cast<const ConfigBase*>(this));
}
double PrintConfig::min_object_distance(const ConfigBase *config)
{
double extruder_clearance_radius = config->option("extruder_clearance_radius")->getFloat();
double duplicate_distance = config->option("duplicate_distance")->getFloat();
// min object distance is max(duplicate_distance, clearance_radius) // min object distance is max(duplicate_distance, clearance_radius)
return (this->option("complete_objects")->getBool() && extruder_clearance_radius > duplicate_distance) return (config->option("complete_objects")->getBool() && extruder_clearance_radius > duplicate_distance)
? extruder_clearance_radius ? extruder_clearance_radius
: duplicate_distance; : duplicate_distance;
} }
std::string FullPrintConfig::validate()
{
// --layer-height
if (this->get_abs_value("layer_height") <= 0)
return "Invalid value for --layer-height";
if (fabs(fmod(this->get_abs_value("layer_height"), SCALING_FACTOR)) > 1e-4)
return "--layer-height must be a multiple of print resolution";
// --first-layer-height
if (this->get_abs_value("first_layer_height") <= 0)
return "Invalid value for --first-layer-height";
// --filament-diameter
for (double fd : this->filament_diameter.values)
if (fd < 1)
return "Invalid value for --filament-diameter";
// --nozzle-diameter
for (double nd : this->nozzle_diameter.values)
if (nd < 1)
return "Invalid value for --nozzle-diameter";
// --perimeters
if (this->perimeters.value < 0)
return "Invalid value for --perimeters";
// --solid-layers
if (this->top_solid_layers < 0)
return "Invalid value for --top-solid-layers";
if (this->bottom_solid_layers < 0)
return "Invalid value for --bottom-solid-layers";
if (this->use_firmware_retraction.value &&
this->gcode_flavor.value != gcfSmoothie &&
this->gcode_flavor.value != gcfRepRap &&
this->gcode_flavor.value != gcfMachinekit &&
this->gcode_flavor.value != gcfRepetier)
return "--use-firmware-retraction is only supported by Marlin, Smoothie, Repetier and Machinekit firmware";
if (this->use_firmware_retraction.value)
for (bool wipe : this->wipe.values)
if (wipe)
return "--use-firmware-retraction is not compatible with --wipe";
// --gcode-flavor
if (! print_config_def.get("gcode_flavor")->has_enum_value(this->gcode_flavor.serialize()))
return "Invalid value for --gcode-flavor";
// --fill-pattern
if (! print_config_def.get("fill_pattern")->has_enum_value(this->fill_pattern.serialize()))
return "Invalid value for --fill-pattern";
// --external-fill-pattern
if (! print_config_def.get("external_fill_pattern")->has_enum_value(this->external_fill_pattern.serialize()))
return "Invalid value for --external-fill-pattern";
// --fill-density
if (fabs(this->fill_density.value - 100.) < EPSILON &&
! print_config_def.get("external_fill_pattern")->has_enum_value(this->fill_pattern.serialize()))
return "The selected fill pattern is not supposed to work at 100% density";
// --infill-every-layers
if (this->infill_every_layers < 1)
return "Invalid value for --infill-every-layers";
// --skirt-height
if (this->skirt_height < -1) // -1 means as tall as the object
return "Invalid value for --skirt-height";
// --bridge-flow-ratio
if (this->bridge_flow_ratio <= 0)
return "Invalid value for --bridge-flow-ratio";
// extruder clearance
if (this->extruder_clearance_radius <= 0)
return "Invalid value for --extruder-clearance-radius";
if (this->extruder_clearance_height <= 0)
return "Invalid value for --extruder-clearance-height";
// --extrusion-multiplier
for (float em : this->extrusion_multiplier.values)
if (em <= 0)
return "Invalid value for --extrusion-multiplier";
// --default-acceleration
if ((this->perimeter_acceleration != 0. || this->infill_acceleration != 0. || this->bridge_acceleration != 0. || this->first_layer_acceleration != 0.) &&
this->default_acceleration == 0.)
return "Invalid zero value for --default-acceleration when using other acceleration settings";
// --spiral-vase
if (this->spiral_vase) {
// Note that we might want to have more than one perimeter on the bottom
// solid layers.
if (this->perimeters > 1)
return "Can't make more than one perimeter when spiral vase mode is enabled";
else if (this->perimeters < 1)
return "Can't make less than one perimeter when spiral vase mode is enabled";
if (this->fill_density > 0)
return "Spiral vase mode can only print hollow objects, so you need to set Fill density to 0";
if (this->top_solid_layers > 0)
return "Spiral vase mode is not compatible with top solid layers";
if (this->support_material || this->support_material_enforce_layers > 0)
return "Spiral vase mode is not compatible with support material";
}
// extrusion widths
{
double max_nozzle_diameter = 0.;
for (double dmr : this->nozzle_diameter.values)
max_nozzle_diameter = std::max(max_nozzle_diameter, dmr);
const char *widths[] = { "external_perimeter", "perimeter", "infill", "solid_infill", "top_infill", "support_material", "first_layer" };
for (size_t i = 0; i < sizeof(widths) / sizeof(widths[i]); ++ i) {
std::string key(widths[i]);
key += "_extrusion_width";
if (this->get_abs_value(key, max_nozzle_diameter) > 10. * max_nozzle_diameter)
return std::string("Invalid extrusion width (too large): ") + key;
}
}
// Out of range validation of numeric values.
for (const std::string &opt_key : this->keys()) {
const ConfigOption *opt = this->optptr(opt_key);
assert(opt != nullptr);
const ConfigOptionDef *optdef = print_config_def.get(opt_key);
assert(optdef != nullptr);
bool out_of_range = false;
switch (opt->type()) {
case coFloat:
case coPercent:
case coFloatOrPercent:
{
auto *fopt = static_cast<const ConfigOptionFloat*>(opt);
out_of_range = fopt->value < optdef->min || fopt->value > optdef->max;
break;
}
case coFloats:
case coPercents:
for (double v : static_cast<const ConfigOptionFloats*>(opt)->values)
if (v < optdef->min || v > optdef->max) {
out_of_range = true;
break;
}
break;
case coInt:
{
auto *iopt = static_cast<const ConfigOptionInt*>(opt);
out_of_range = iopt->value < optdef->min || iopt->value > optdef->max;
break;
}
case coInts:
for (int v : static_cast<const ConfigOptionInts*>(opt)->values)
if (v < optdef->min || v > optdef->max) {
out_of_range = true;
break;
}
break;
default:;
}
if (out_of_range)
return std::string("Value out of range: " + opt_key);
}
// The configuration is valid.
return "";
}
// Declare the static caches for each StaticPrintConfig derived class.
StaticPrintConfig::StaticCache<class Slic3r::PrintObjectConfig> PrintObjectConfig::s_cache;
StaticPrintConfig::StaticCache<class Slic3r::PrintRegionConfig> PrintRegionConfig::s_cache;
StaticPrintConfig::StaticCache<class Slic3r::GCodeConfig> GCodeConfig::s_cache;
StaticPrintConfig::StaticCache<class Slic3r::PrintConfig> PrintConfig::s_cache;
StaticPrintConfig::StaticCache<class Slic3r::HostConfig> HostConfig::s_cache;
StaticPrintConfig::StaticCache<class Slic3r::FullPrintConfig> FullPrintConfig::s_cache;
} }

View File

@ -5,7 +5,6 @@
// during the slicing and the g-code generation. // during the slicing and the g-code generation.
// //
// The classes derived from StaticPrintConfig form a following hierarchy. // The classes derived from StaticPrintConfig form a following hierarchy.
// Virtual inheritance is used for some of the parent objects.
// //
// FullPrintConfig // FullPrintConfig
// PrintObjectConfig // PrintObjectConfig
@ -21,8 +20,6 @@
#include "libslic3r.h" #include "libslic3r.h"
#include "Config.hpp" #include "Config.hpp"
#define OPT_PTR(KEY) if (opt_key == #KEY) return &this->KEY
namespace Slic3r { namespace Slic3r {
enum GCodeFlavor { enum GCodeFlavor {
@ -46,66 +43,76 @@ enum FilamentType {
ftPLA, ftABS, ftPET, ftHIPS, ftFLEX, ftSCAFF, ftEDGE, ftNGEN, ftPVA ftPLA, ftABS, ftPET, ftHIPS, ftFLEX, ftSCAFF, ftEDGE, ftNGEN, ftPVA
}; };
template<> inline t_config_enum_values ConfigOptionEnum<GCodeFlavor>::get_enum_values() { template<> inline t_config_enum_values& ConfigOptionEnum<GCodeFlavor>::get_enum_values() {
t_config_enum_values keys_map; static t_config_enum_values keys_map;
keys_map["reprap"] = gcfRepRap; if (keys_map.empty()) {
keys_map["repetier"] = gcfRepetier; keys_map["reprap"] = gcfRepRap;
keys_map["teacup"] = gcfTeacup; keys_map["repetier"] = gcfRepetier;
keys_map["makerware"] = gcfMakerWare; keys_map["teacup"] = gcfTeacup;
keys_map["sailfish"] = gcfSailfish; keys_map["makerware"] = gcfMakerWare;
keys_map["smoothie"] = gcfSmoothie; keys_map["sailfish"] = gcfSailfish;
keys_map["mach3"] = gcfMach3; keys_map["smoothie"] = gcfSmoothie;
keys_map["machinekit"] = gcfMachinekit; keys_map["mach3"] = gcfMach3;
keys_map["no-extrusion"] = gcfNoExtrusion; keys_map["machinekit"] = gcfMachinekit;
keys_map["no-extrusion"] = gcfNoExtrusion;
}
return keys_map; return keys_map;
} }
template<> inline t_config_enum_values ConfigOptionEnum<InfillPattern>::get_enum_values() { template<> inline t_config_enum_values& ConfigOptionEnum<InfillPattern>::get_enum_values() {
t_config_enum_values keys_map; static t_config_enum_values keys_map;
keys_map["rectilinear"] = ipRectilinear; if (keys_map.empty()) {
keys_map["grid"] = ipGrid; keys_map["rectilinear"] = ipRectilinear;
keys_map["triangles"] = ipTriangles; keys_map["grid"] = ipGrid;
keys_map["stars"] = ipStars; keys_map["triangles"] = ipTriangles;
keys_map["cubic"] = ipCubic; keys_map["stars"] = ipStars;
keys_map["line"] = ipLine; keys_map["cubic"] = ipCubic;
keys_map["concentric"] = ipConcentric; keys_map["line"] = ipLine;
keys_map["honeycomb"] = ipHoneycomb; keys_map["concentric"] = ipConcentric;
keys_map["3dhoneycomb"] = ip3DHoneycomb; keys_map["honeycomb"] = ipHoneycomb;
keys_map["hilbertcurve"] = ipHilbertCurve; keys_map["3dhoneycomb"] = ip3DHoneycomb;
keys_map["archimedeanchords"] = ipArchimedeanChords; keys_map["hilbertcurve"] = ipHilbertCurve;
keys_map["octagramspiral"] = ipOctagramSpiral; keys_map["archimedeanchords"] = ipArchimedeanChords;
keys_map["octagramspiral"] = ipOctagramSpiral;
}
return keys_map; return keys_map;
} }
template<> inline t_config_enum_values ConfigOptionEnum<SupportMaterialPattern>::get_enum_values() { template<> inline t_config_enum_values& ConfigOptionEnum<SupportMaterialPattern>::get_enum_values() {
t_config_enum_values keys_map; static t_config_enum_values keys_map;
keys_map["rectilinear"] = smpRectilinear; if (keys_map.empty()) {
keys_map["rectilinear-grid"] = smpRectilinearGrid; keys_map["rectilinear"] = smpRectilinear;
keys_map["honeycomb"] = smpHoneycomb; keys_map["rectilinear-grid"] = smpRectilinearGrid;
keys_map["pillars"] = smpPillars; keys_map["honeycomb"] = smpHoneycomb;
keys_map["pillars"] = smpPillars;
}
return keys_map; return keys_map;
} }
template<> inline t_config_enum_values ConfigOptionEnum<SeamPosition>::get_enum_values() { template<> inline t_config_enum_values& ConfigOptionEnum<SeamPosition>::get_enum_values() {
t_config_enum_values keys_map; static t_config_enum_values keys_map;
keys_map["random"] = spRandom; if (keys_map.empty()) {
keys_map["nearest"] = spNearest; keys_map["random"] = spRandom;
keys_map["aligned"] = spAligned; keys_map["nearest"] = spNearest;
keys_map["rear"] = spRear; keys_map["aligned"] = spAligned;
keys_map["rear"] = spRear;
}
return keys_map; return keys_map;
} }
template<> inline t_config_enum_values ConfigOptionEnum<FilamentType>::get_enum_values() { template<> inline t_config_enum_values& ConfigOptionEnum<FilamentType>::get_enum_values() {
t_config_enum_values keys_map; static t_config_enum_values keys_map;
keys_map["PLA"] = ftPLA; if (keys_map.empty()) {
keys_map["ABS"] = ftABS; keys_map["PLA"] = ftPLA;
keys_map["PET"] = ftPET; keys_map["ABS"] = ftABS;
keys_map["HIPS"] = ftHIPS; keys_map["PET"] = ftPET;
keys_map["FLEX"] = ftFLEX; keys_map["HIPS"] = ftHIPS;
keys_map["SCAFF"] = ftSCAFF; keys_map["FLEX"] = ftFLEX;
keys_map["EDGE"] = ftEDGE; keys_map["SCAFF"] = ftSCAFF;
keys_map["NGEN"] = ftNGEN; keys_map["EDGE"] = ftEDGE;
keys_map["PVA"] = ftPVA; keys_map["NGEN"] = ftNGEN;
keys_map["PVA"] = ftPVA;
}
return keys_map; return keys_map;
} }
@ -113,60 +120,177 @@ template<> inline t_config_enum_values ConfigOptionEnum<FilamentType>::get_enum_
// Does not store the actual values, but defines default values. // Does not store the actual values, but defines default values.
class PrintConfigDef : public ConfigDef class PrintConfigDef : public ConfigDef
{ {
public: public:
PrintConfigDef(); PrintConfigDef();
static void handle_legacy(t_config_option_key &opt_key, std::string &value);
}; };
// The one and only global definition of SLic3r configuration options. // The one and only global definition of SLic3r configuration options.
// This definition is constant. // This definition is constant.
extern PrintConfigDef print_config_def; extern PrintConfigDef print_config_def;
// Slic3r configuration storage with print_config_def assigned.
class PrintConfigBase : public virtual ConfigBase
{
public:
PrintConfigBase() {
this->def = &print_config_def;
};
bool set_deserialize(t_config_option_key opt_key, std::string str, bool append = false);
double min_object_distance() const;
protected:
void _handle_legacy(t_config_option_key &opt_key, std::string &value) const;
};
// Slic3r dynamic configuration, used to override the configuration // Slic3r dynamic configuration, used to override the configuration
// per object, per modification volume or per printing material. // per object, per modification volume or per printing material.
// The dynamic configuration is also used to store user modifications of the print global parameters, // The dynamic configuration is also used to store user modifications of the print global parameters,
// so the modified configuration values may be diffed against the active configuration // so the modified configuration values may be diffed against the active configuration
// to invalidate the proper slicing resp. g-code generation processing steps. // to invalidate the proper slicing resp. g-code generation processing steps.
// This object is mapped to Perl as Slic3r::Config. // This object is mapped to Perl as Slic3r::Config.
class DynamicPrintConfig : public PrintConfigBase, public DynamicConfig class DynamicPrintConfig : public DynamicConfig
{ {
public: public:
DynamicPrintConfig() : PrintConfigBase(), DynamicConfig() {}; DynamicPrintConfig() {}
void normalize(); DynamicPrintConfig(const DynamicPrintConfig &other) : DynamicConfig(other) {}
// Overrides ConfigBase::def(). Static configuration definition. Any value stored into this ConfigBase shall have its definition here.
const ConfigDef* def() const override { return &print_config_def; }
void normalize();
// Validate the PrintConfig. Returns an empty string on success, otherwise an error message is returned.
std::string validate();
}; };
template<typename CONFIG> template<typename CONFIG>
void normalize_and_apply_config(CONFIG &dst, const DynamicPrintConfig &src) void normalize_and_apply_config(CONFIG &dst, const DynamicPrintConfig &src)
{ {
DynamicPrintConfig src_normalized = src; DynamicPrintConfig src_normalized(src);
src_normalized.normalize(); src_normalized.normalize();
dst.apply(src_normalized, true); dst.apply(src_normalized, true);
} }
class StaticPrintConfig : public PrintConfigBase, public StaticConfig class StaticPrintConfig : public StaticConfig
{ {
public:
StaticPrintConfig() {}
// Overrides ConfigBase::def(). Static configuration definition. Any value stored into this ConfigBase shall have its definition here.
const ConfigDef* def() const override { return &print_config_def; }
protected:
// Verify whether the opt_key has not been obsoleted or renamed.
// Both opt_key and value may be modified by handle_legacy().
// If the opt_key is no more valid in this version of Slic3r, opt_key is cleared by handle_legacy().
// handle_legacy() is called internally by set_deserialize().
void handle_legacy(t_config_option_key &opt_key, std::string &value) const override
{ PrintConfigDef::handle_legacy(opt_key, value); }
// Internal class for keeping a dynamic map to static options.
class StaticCacheBase
{
public: public:
StaticPrintConfig() : PrintConfigBase(), StaticConfig() {}; // To be called during the StaticCache setup.
// Add one ConfigOption into m_map_name_to_offset.
template<typename T>
void opt_add(const std::string &name, const char *base_ptr, const T &opt)
{
assert(m_map_name_to_offset.find(name) == m_map_name_to_offset.end());
m_map_name_to_offset[name] = (const char*)&opt - base_ptr;
}
protected:
std::map<std::string, ptrdiff_t> m_map_name_to_offset;
};
// Parametrized by the type of the topmost class owning the options.
template<typename T>
class StaticCache : public StaticCacheBase
{
public:
// Calling the constructor of m_defaults with 0 forces m_defaults to not run the initialization.
StaticCache() : m_defaults(nullptr) {}
~StaticCache() { delete m_defaults; m_defaults = nullptr; }
bool initialized() const { return ! m_keys.empty(); }
ConfigOption* optptr(const std::string &name, T *owner) const
{
const auto it = m_map_name_to_offset.find(name);
return (it == m_map_name_to_offset.end()) ? nullptr : reinterpret_cast<ConfigOption*>((char*)owner + it->second);
}
const ConfigOption* optptr(const std::string &name, const T *owner) const
{
const auto it = m_map_name_to_offset.find(name);
return (it == m_map_name_to_offset.end()) ? nullptr : reinterpret_cast<const ConfigOption*>((const char*)owner + it->second);
}
const std::vector<std::string>& keys() const { return m_keys; }
const T& defaults() const { return *m_defaults; }
// To be called during the StaticCache setup.
// Collect option keys from m_map_name_to_offset,
// assign default values to m_defaults.
void finalize(T *defaults, const ConfigDef *defs)
{
assert(defs != nullptr);
m_defaults = defaults;
m_keys.clear();
m_keys.reserve(m_map_name_to_offset.size());
for (const auto &kvp : defs->options) {
// Find the option given the option name kvp.first by an offset from (char*)m_defaults.
ConfigOption *opt = this->optptr(kvp.first, m_defaults);
if (opt == nullptr)
// This option is not defined by the ConfigBase of type T.
continue;
m_keys.emplace_back(kvp.first);
const ConfigOptionDef *def = defs->get(kvp.first);
assert(def != nullptr);
if (def->default_value != nullptr)
opt->set(def->default_value);
}
}
private:
T *m_defaults;
std::vector<std::string> m_keys;
};
}; };
#define STATIC_PRINT_CONFIG_CACHE_BASE(CLASS_NAME) \
public: \
/* 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.optptr(opt_key, this); } \
/* Overrides ConfigBase::keys(). Collect names of all configuration values maintained by this configuration store. */ \
t_config_option_keys keys() const override { return s_cache.keys(); } \
static const CLASS_NAME& defaults() { initialize_cache(); return s_cache.defaults(); } \
protected: \
static void initialize_cache() \
{ \
if (! s_cache.initialized()) { \
CLASS_NAME *inst = new CLASS_NAME(1); \
inst->initialize(s_cache, (const char*)inst); \
s_cache.finalize(inst, inst->def()); \
} \
} \
/* Cache object holding a key/option map, a list of option keys and a copy of this static config initialized with the defaults. */ \
static StaticCache<CLASS_NAME> s_cache;
#define STATIC_PRINT_CONFIG_CACHE(CLASS_NAME) \
STATIC_PRINT_CONFIG_CACHE_BASE(CLASS_NAME) \
public: \
/* Public default constructor will initialize the key/option cache and the default object copy if needed. */ \
CLASS_NAME() { initialize_cache(); *this = s_cache.defaults(); } \
protected: \
/* Protected constructor to be called when compounded. */ \
CLASS_NAME(int) {}
#define STATIC_PRINT_CONFIG_CACHE_DERIVED(CLASS_NAME) \
STATIC_PRINT_CONFIG_CACHE_BASE(CLASS_NAME) \
public: \
/* Overrides ConfigBase::def(). Static configuration definition. Any value stored into this ConfigBase shall have its definition here. */ \
const ConfigDef* def() const override { return &print_config_def; } \
/* Handle legacy and obsoleted config keys */ \
void handle_legacy(t_config_option_key &opt_key, std::string &value) const override \
{ PrintConfigDef::handle_legacy(opt_key, value); }
#define OPT_PTR(KEY) cache.opt_add(#KEY, base_ptr, this->KEY)
// This object is mapped to Perl as Slic3r::Config::PrintObject. // This object is mapped to Perl as Slic3r::Config::PrintObject.
class PrintObjectConfig : public virtual StaticPrintConfig class PrintObjectConfig : public StaticPrintConfig
{ {
STATIC_PRINT_CONFIG_CACHE(PrintObjectConfig)
public: public:
ConfigOptionBool clip_multipart_objects; ConfigOptionBool clip_multipart_objects;
ConfigOptionBool dont_support_bridges; ConfigOptionBool dont_support_bridges;
@ -201,13 +325,9 @@ public:
ConfigOptionFloatOrPercent support_material_xy_spacing; ConfigOptionFloatOrPercent support_material_xy_spacing;
ConfigOptionFloat xy_size_compensation; ConfigOptionFloat xy_size_compensation;
PrintObjectConfig(bool initialize = true) : StaticPrintConfig() { protected:
if (initialize) void initialize(StaticCacheBase &cache, const char *base_ptr)
this->set_defaults(); {
}
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) {
UNUSED(create);
OPT_PTR(clip_multipart_objects); OPT_PTR(clip_multipart_objects);
OPT_PTR(dont_support_bridges); OPT_PTR(dont_support_bridges);
OPT_PTR(elefant_foot_compensation); OPT_PTR(elefant_foot_compensation);
@ -240,14 +360,13 @@ public:
OPT_PTR(support_material_threshold); OPT_PTR(support_material_threshold);
OPT_PTR(support_material_with_sheath); OPT_PTR(support_material_with_sheath);
OPT_PTR(xy_size_compensation); OPT_PTR(xy_size_compensation);
}
return NULL;
};
}; };
// This object is mapped to Perl as Slic3r::Config::PrintRegion. // This object is mapped to Perl as Slic3r::Config::PrintRegion.
class PrintRegionConfig : public virtual StaticPrintConfig class PrintRegionConfig : public StaticPrintConfig
{ {
STATIC_PRINT_CONFIG_CACHE(PrintRegionConfig)
public: public:
ConfigOptionFloat bridge_angle; ConfigOptionFloat bridge_angle;
ConfigOptionInt bottom_solid_layers; ConfigOptionInt bottom_solid_layers;
@ -284,13 +403,9 @@ public:
ConfigOptionInt top_solid_layers; ConfigOptionInt top_solid_layers;
ConfigOptionFloatOrPercent top_solid_infill_speed; ConfigOptionFloatOrPercent top_solid_infill_speed;
PrintRegionConfig(bool initialize = true) : StaticPrintConfig() { protected:
if (initialize) void initialize(StaticCacheBase &cache, const char *base_ptr)
this->set_defaults(); {
}
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) {
UNUSED(create);
OPT_PTR(bridge_angle); OPT_PTR(bridge_angle);
OPT_PTR(bottom_solid_layers); OPT_PTR(bottom_solid_layers);
OPT_PTR(bridge_flow_ratio); OPT_PTR(bridge_flow_ratio);
@ -325,14 +440,13 @@ public:
OPT_PTR(top_infill_extrusion_width); OPT_PTR(top_infill_extrusion_width);
OPT_PTR(top_solid_infill_speed); OPT_PTR(top_solid_infill_speed);
OPT_PTR(top_solid_layers); OPT_PTR(top_solid_layers);
}
return NULL;
};
}; };
// This object is mapped to Perl as Slic3r::Config::GCode. // This object is mapped to Perl as Slic3r::Config::GCode.
class GCodeConfig : public virtual StaticPrintConfig class GCodeConfig : public StaticPrintConfig
{ {
STATIC_PRINT_CONFIG_CACHE(GCodeConfig)
public: public:
ConfigOptionString before_layer_gcode; ConfigOptionString before_layer_gcode;
ConfigOptionFloats deretract_speed; ConfigOptionFloats deretract_speed;
@ -372,13 +486,16 @@ public:
ConfigOptionBool use_volumetric_e; ConfigOptionBool use_volumetric_e;
ConfigOptionBool variable_layer_height; ConfigOptionBool variable_layer_height;
GCodeConfig(bool initialize = true) : StaticPrintConfig() { std::string get_extrusion_axis() const
if (initialize) {
this->set_defaults(); return
((this->gcode_flavor.value == gcfMach3) || (this->gcode_flavor.value == gcfMachinekit)) ? "A" :
(this->gcode_flavor.value == gcfNoExtrusion) ? "" : this->extrusion_axis.value;
} }
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) { protected:
UNUSED(create); void initialize(StaticCacheBase &cache, const char *base_ptr)
{
OPT_PTR(before_layer_gcode); OPT_PTR(before_layer_gcode);
OPT_PTR(deretract_speed); OPT_PTR(deretract_speed);
OPT_PTR(end_gcode); OPT_PTR(end_gcode);
@ -416,25 +533,18 @@ public:
OPT_PTR(use_relative_e_distances); OPT_PTR(use_relative_e_distances);
OPT_PTR(use_volumetric_e); OPT_PTR(use_volumetric_e);
OPT_PTR(variable_layer_height); OPT_PTR(variable_layer_height);
return NULL; }
};
std::string get_extrusion_axis() const
{
if ((this->gcode_flavor.value == gcfMach3) || (this->gcode_flavor.value == gcfMachinekit)) {
return "A";
} else if (this->gcode_flavor.value == gcfNoExtrusion) {
return "";
} else {
return this->extrusion_axis.value;
}
};
}; };
// This object is mapped to Perl as Slic3r::Config::Print. // This object is mapped to Perl as Slic3r::Config::Print.
class PrintConfig : public GCodeConfig class PrintConfig : public GCodeConfig
{ {
STATIC_PRINT_CONFIG_CACHE_DERIVED(PrintConfig)
PrintConfig() : GCodeConfig(0) { initialize_cache(); *this = s_cache.defaults(); }
public: public:
double min_object_distance() const;
static double min_object_distance(const ConfigBase *config);
ConfigOptionBool avoid_crossing_perimeters; ConfigOptionBool avoid_crossing_perimeters;
ConfigOptionPoints bed_shape; ConfigOptionPoints bed_shape;
ConfigOptionInts bed_temperature; ConfigOptionInts bed_temperature;
@ -494,12 +604,11 @@ public:
ConfigOptionFloat wipe_tower_per_color_wipe; ConfigOptionFloat wipe_tower_per_color_wipe;
ConfigOptionFloat z_offset; ConfigOptionFloat z_offset;
PrintConfig(bool initialize = true) : GCodeConfig(false) { protected:
if (initialize) PrintConfig(int) : GCodeConfig(1) {}
this->set_defaults(); void initialize(StaticCacheBase &cache, const char *base_ptr)
} {
this->GCodeConfig::initialize(cache, base_ptr);
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) {
OPT_PTR(avoid_crossing_perimeters); OPT_PTR(avoid_crossing_perimeters);
OPT_PTR(bed_shape); OPT_PTR(bed_shape);
OPT_PTR(bed_temperature); OPT_PTR(bed_temperature);
@ -558,64 +667,58 @@ public:
OPT_PTR(wipe_tower_width); OPT_PTR(wipe_tower_width);
OPT_PTR(wipe_tower_per_color_wipe); OPT_PTR(wipe_tower_per_color_wipe);
OPT_PTR(z_offset); OPT_PTR(z_offset);
}
// look in parent class
ConfigOption* opt;
if ((opt = GCodeConfig::optptr(opt_key, create)) != NULL) return opt;
return NULL;
};
}; };
class HostConfig : public virtual StaticPrintConfig class HostConfig : public StaticPrintConfig
{ {
STATIC_PRINT_CONFIG_CACHE(HostConfig)
public: public:
ConfigOptionString octoprint_host; ConfigOptionString octoprint_host;
ConfigOptionString octoprint_apikey; ConfigOptionString octoprint_apikey;
ConfigOptionString serial_port; ConfigOptionString serial_port;
ConfigOptionInt serial_speed; ConfigOptionInt serial_speed;
HostConfig(bool initialize = true) : StaticPrintConfig() { protected:
if (initialize) void initialize(StaticCacheBase &cache, const char *base_ptr)
this->set_defaults(); {
}
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) {
UNUSED(create);
OPT_PTR(octoprint_host); OPT_PTR(octoprint_host);
OPT_PTR(octoprint_apikey); OPT_PTR(octoprint_apikey);
OPT_PTR(serial_port); OPT_PTR(serial_port);
OPT_PTR(serial_speed); OPT_PTR(serial_speed);
}
return NULL;
};
}; };
// This object is mapped to Perl as Slic3r::Config::Full. // This object is mapped to Perl as Slic3r::Config::Full.
class FullPrintConfig class FullPrintConfig :
: public PrintObjectConfig, public PrintRegionConfig, public PrintConfig, public HostConfig public PrintObjectConfig,
public PrintRegionConfig,
public PrintConfig,
public HostConfig
{ {
public: STATIC_PRINT_CONFIG_CACHE_DERIVED(FullPrintConfig)
FullPrintConfig(bool initialize = true) : FullPrintConfig() : PrintObjectConfig(0), PrintRegionConfig(0), PrintConfig(0), HostConfig(0) { initialize_cache(); *this = s_cache.defaults(); }
PrintObjectConfig(false),
PrintRegionConfig(false),
PrintConfig(false),
HostConfig(false)
{
if (initialize)
this->set_defaults();
}
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) { public:
ConfigOption* opt; // Validate the FullPrintConfig. Returns an empty string on success, otherwise an error message is returned.
if ((opt = PrintObjectConfig::optptr(opt_key, create)) != NULL) return opt; std::string validate();
if ((opt = PrintRegionConfig::optptr(opt_key, create)) != NULL) return opt; protected:
if ((opt = PrintConfig::optptr(opt_key, create)) != NULL) return opt; // Protected constructor to be called to initialize ConfigCache::m_default.
if ((opt = HostConfig::optptr(opt_key, create)) != NULL) return opt; FullPrintConfig(int) : PrintObjectConfig(0), PrintRegionConfig(0), PrintConfig(0), HostConfig(0) {}
return NULL; void initialize(StaticCacheBase &cache, const char *base_ptr)
}; {
this->PrintObjectConfig::initialize(cache, base_ptr);
this->PrintRegionConfig::initialize(cache, base_ptr);
this->PrintConfig ::initialize(cache, base_ptr);
this->HostConfig ::initialize(cache, base_ptr);
}
}; };
#undef STATIC_PRINT_CONFIG_CACHE
#undef STATIC_PRINT_CONFIG_CACHE_BASE
#undef STATIC_PRINT_CONFIG_CACHE_DERIVED
#undef OPT_PTR
} }
#endif #endif

View File

@ -948,7 +948,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
slices_margin_cached, slices_margin_cached,
// How much to offset the extracted contour outside of the grid. // How much to offset the extracted contour outside of the grid.
m_object_config->support_material_spacing.value + m_support_material_flow.spacing(), m_object_config->support_material_spacing.value + m_support_material_flow.spacing(),
Geometry::deg2rad(m_object_config->support_material_angle)); Geometry::deg2rad(m_object_config->support_material_angle.value));
// 1) infill polygons, expand them by half the extrusion width + a tiny bit of extra. // 1) infill polygons, expand them by half the extrusion width + a tiny bit of extra.
new_layer.polygons = support_grid_pattern.extract_support(m_support_material_flow.scaled_spacing()/2 + 5); new_layer.polygons = support_grid_pattern.extract_support(m_support_material_flow.scaled_spacing()/2 + 5);
// 2) Contact polygons will be projected down. To keep the interface and base layers to grow, return a contour a tiny bit smaller than the grid cells. // 2) Contact polygons will be projected down. To keep the interface and base layers to grow, return a contour a tiny bit smaller than the grid cells.
@ -1155,7 +1155,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
trimming, trimming,
// How much to offset the extracted contour outside of the grid. // How much to offset the extracted contour outside of the grid.
m_object_config->support_material_spacing.value + m_support_material_flow.spacing(), m_object_config->support_material_spacing.value + m_support_material_flow.spacing(),
Geometry::deg2rad(m_object_config->support_material_angle)); Geometry::deg2rad(m_object_config->support_material_angle.value));
tbb::task_group task_group_inner; tbb::task_group task_group_inner;
// 1) Cache the slice of a support volume. The support volume is expanded by 1/2 of support material flow spacing // 1) Cache the slice of a support volume. The support volume is expanded by 1/2 of support material flow spacing
// to allow a placement of suppot zig-zag snake along the grid lines. // to allow a placement of suppot zig-zag snake along the grid lines.
@ -2471,8 +2471,8 @@ void PrintObjectSupportMaterial::generate_toolpaths(
LoopInterfaceProcessor loop_interface_processor(1.5 * m_support_material_interface_flow.scaled_width()); LoopInterfaceProcessor loop_interface_processor(1.5 * m_support_material_interface_flow.scaled_width());
loop_interface_processor.n_contact_loops = this->has_contact_loops() ? 1 : 0; loop_interface_processor.n_contact_loops = this->has_contact_loops() ? 1 : 0;
float base_angle = Geometry::deg2rad(float(m_object_config->support_material_angle)); float base_angle = Geometry::deg2rad(float(m_object_config->support_material_angle.value));
float interface_angle = Geometry::deg2rad(float(m_object_config->support_material_angle + 90.)); float interface_angle = Geometry::deg2rad(float(m_object_config->support_material_angle.value + 90.));
coordf_t interface_spacing = m_object_config->support_material_interface_spacing.value + m_support_material_interface_flow.spacing(); coordf_t interface_spacing = m_object_config->support_material_interface_spacing.value + m_support_material_interface_flow.spacing();
coordf_t interface_density = std::min(1., m_support_material_interface_flow.spacing() / interface_spacing); coordf_t interface_density = std::min(1., m_support_material_interface_flow.spacing() / interface_spacing);
coordf_t support_spacing = m_object_config->support_material_spacing.value + m_support_material_flow.spacing(); coordf_t support_spacing = m_object_config->support_material_spacing.value + m_support_material_flow.spacing();
@ -2763,7 +2763,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
if (base_layer.layer->bottom_z < EPSILON) { if (base_layer.layer->bottom_z < EPSILON) {
// Base flange (the 1st layer). // Base flange (the 1st layer).
filler = filler_interface.get(); filler = filler_interface.get();
filler->angle = Geometry::deg2rad(float(m_object_config->support_material_angle + 90.)); filler->angle = Geometry::deg2rad(float(m_object_config->support_material_angle.value + 90.));
density = 0.5f; density = 0.5f;
flow = m_first_layer_flow; flow = m_first_layer_flow;
// use the proper spacing for first layer as we don't need to align // use the proper spacing for first layer as we don't need to align

View File

@ -77,7 +77,7 @@ ConfigBase__get(ConfigBase* THIS, const t_config_option_key &opt_key) {
ConfigOption* opt = THIS->option(opt_key); ConfigOption* opt = THIS->option(opt_key);
if (opt == NULL) return &PL_sv_undef; if (opt == NULL) return &PL_sv_undef;
const ConfigOptionDef* def = THIS->def->get(opt_key); const ConfigOptionDef* def = THIS->def()->get(opt_key);
return ConfigOption_to_SV(*opt, *def); return ConfigOption_to_SV(*opt, *def);
} }
@ -155,7 +155,7 @@ ConfigBase__get_at(ConfigBase* THIS, const t_config_option_key &opt_key, size_t
ConfigOption* opt = THIS->option(opt_key); ConfigOption* opt = THIS->option(opt_key);
if (opt == NULL) return &PL_sv_undef; if (opt == NULL) return &PL_sv_undef;
const ConfigOptionDef* def = THIS->def->get(opt_key); const ConfigOptionDef* def = THIS->def()->get(opt_key);
if (def->type == coFloats || def->type == coPercents) { if (def->type == coFloats || def->type == coPercents) {
ConfigOptionFloats* optv = dynamic_cast<ConfigOptionFloats*>(opt); ConfigOptionFloats* optv = dynamic_cast<ConfigOptionFloats*>(opt);
return newSVnv(optv->get_at(i)); return newSVnv(optv->get_at(i));
@ -183,7 +183,7 @@ ConfigBase__set(ConfigBase* THIS, const t_config_option_key &opt_key, SV* value)
ConfigOption* opt = THIS->option(opt_key, true); ConfigOption* opt = THIS->option(opt_key, true);
if (opt == NULL) CONFESS("Trying to set non-existing option"); if (opt == NULL) CONFESS("Trying to set non-existing option");
const ConfigOptionDef* def = THIS->def->get(opt_key); const ConfigOptionDef* def = THIS->def()->get(opt_key);
if (def->type == coFloat) { if (def->type == coFloat) {
if (!looks_like_number(value)) return false; if (!looks_like_number(value)) return false;
ConfigOptionFloat* optv = dynamic_cast<ConfigOptionFloat*>(opt); ConfigOptionFloat* optv = dynamic_cast<ConfigOptionFloat*>(opt);
@ -297,7 +297,7 @@ ConfigBase__set_ifndef(ConfigBase* THIS, const t_config_option_key &opt_key, SV*
bool bool
StaticConfig__set(StaticConfig* THIS, const t_config_option_key &opt_key, SV* value) { StaticConfig__set(StaticConfig* THIS, const t_config_option_key &opt_key, SV* value) {
const ConfigOptionDef* optdef = THIS->def->get(opt_key); const ConfigOptionDef* optdef = THIS->def()->get(opt_key);
if (!optdef->shortcut.empty()) { if (!optdef->shortcut.empty()) {
for (std::vector<t_config_option_key>::const_iterator it = optdef->shortcut.begin(); it != optdef->shortcut.end(); ++it) { for (std::vector<t_config_option_key>::const_iterator it = optdef->shortcut.begin(); it != optdef->shortcut.end(); ++it) {
if (!StaticConfig__set(THIS, *it, value)) return false; if (!StaticConfig__set(THIS, *it, value)) return false;

View File

@ -23,7 +23,7 @@ DynamicPrintConfig& Preset::load(const std::vector<std::string> &keys)
{ {
// Set the configuration from the defaults. // Set the configuration from the defaults.
Slic3r::FullPrintConfig defaults; Slic3r::FullPrintConfig defaults;
this->config.apply(defaults, keys.empty() ? defaults.keys() : keys); this->config.apply_only(defaults, keys.empty() ? defaults.keys() : keys);
if (! this->is_default) { if (! this->is_default) {
// Load the preset file, apply preset values on top of defaults. // Load the preset file, apply preset values on top of defaults.

View File

@ -37,7 +37,7 @@
void erase(t_config_option_key opt_key); void erase(t_config_option_key opt_key);
void normalize(); void normalize();
%name{setenv} void setenv_(); %name{setenv} void setenv_();
double min_object_distance(); double min_object_distance() %code{% RETVAL = PrintConfig::min_object_distance(THIS); %};
%name{_load} void load(std::string file); %name{_load} void load(std::string file);
%name{_load_from_gcode} void load_from_gcode(std::string input_file) %name{_load_from_gcode} void load_from_gcode(std::string input_file)
%code%{ %code%{
@ -47,20 +47,20 @@
croak("Error extracting configuration from a g-code %s:\n%s\n", input_file.c_str(), e.what()); croak("Error extracting configuration from a g-code %s:\n%s\n", input_file.c_str(), e.what());
} }
%}; %};
%name{_save} void save(std::string file); void save(std::string file);
}; };
%name{Slic3r::Config::Static} class StaticPrintConfig { %name{Slic3r::Config::Static} class StaticPrintConfig {
static StaticPrintConfig* new_GCodeConfig() static StaticPrintConfig* new_GCodeConfig()
%code{% RETVAL = new GCodeConfig (); %}; %code{% RETVAL = new GCodeConfig(); %};
static StaticPrintConfig* new_PrintConfig() static StaticPrintConfig* new_PrintConfig()
%code{% RETVAL = new PrintConfig (); %}; %code{% RETVAL = new PrintConfig(); %};
static StaticPrintConfig* new_PrintObjectConfig() static StaticPrintConfig* new_PrintObjectConfig()
%code{% RETVAL = new PrintObjectConfig (); %}; %code{% RETVAL = new PrintObjectConfig(); %};
static StaticPrintConfig* new_PrintRegionConfig() static StaticPrintConfig* new_PrintRegionConfig()
%code{% RETVAL = new PrintRegionConfig (); %}; %code{% RETVAL = new PrintRegionConfig(); %};
static StaticPrintConfig* new_FullPrintConfig() static StaticPrintConfig* new_FullPrintConfig()
%code{% RETVAL = new FullPrintConfig (); %}; %code{% RETVAL = static_cast<PrintObjectConfig*>(new FullPrintConfig()); %};
~StaticPrintConfig(); ~StaticPrintConfig();
bool has(t_config_option_key opt_key); bool has(t_config_option_key opt_key);
SV* as_hash() SV* as_hash()
@ -93,10 +93,10 @@
} }
%}; %};
%name{setenv} void setenv_(); %name{setenv} void setenv_();
double min_object_distance(); double min_object_distance() %code{% RETVAL = PrintConfig::min_object_distance(THIS); %};
%name{_load} void load(std::string file); %name{_load} void load(std::string file);
%name{_load_from_gcode} void load_from_gcode(std::string file); %name{_load_from_gcode} void load_from_gcode(std::string file);
%name{_save} void save(std::string file); void save(std::string file);
}; };
%package{Slic3r::Config}; %package{Slic3r::Config};