Ported PrintConfigBase::_handle_legacy from Perl to C++,

merged from upstream Slic3r, thanks to @alexrj.
This commit is contained in:
bubnikv 2017-09-18 09:56:48 +02:00
parent cd084a33c6
commit e16f827223
6 changed files with 116 additions and 95 deletions

View File

@ -98,9 +98,7 @@ sub merge {
# Load a flat ini file without a category into the underlying C++ Slic3r::DynamicConfig class, # Load a flat ini file without a category into the underlying C++ Slic3r::DynamicConfig class,
# convert legacy configuration names. # convert legacy configuration names.
sub load { sub load {
my $class = shift; my ($class, $file) = @_;
my ($file) = @_;
# Instead of using the /i modifier for case-insensitive matching, the case insensitivity is expressed # Instead of using the /i modifier for case-insensitive matching, the case insensitivity is expressed
# explicitely to avoid having to bundle the UTF8 Perl library. # explicitely to avoid having to bundle the UTF8 Perl library.
if ($file =~ /\.[gG][cC][oO][dD][eE]/ || $file =~ /\.[gG]/) { if ($file =~ /\.[gG][cC][oO][dD][eE]/ || $file =~ /\.[gG]/) {
@ -108,102 +106,47 @@ sub load {
$config->_load_from_gcode($file); $config->_load_from_gcode($file);
return $config; return $config;
} else { } else {
my $ini = __PACKAGE__->read_ini($file); my $config = $class->new;
return $class->load_ini_hash($ini->{_}); $config->_load($file);
return $config;
} }
} }
# 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.
sub load_ini_hash { sub load_ini_hash {
my $class = shift; my ($class, $ini_hash) = @_;
my ($ini_hash) = @_;
my $config = $class->new; my $config = $class->new;
foreach my $opt_key (keys %$ini_hash) { $config->set_deserialize($_, $ini_hash->{$_}) for keys %$ini_hash;
($opt_key, my $value) = _handle_legacy($opt_key, $ini_hash->{$opt_key});
next if !defined $opt_key;
$config->set_deserialize($opt_key, $value);
}
return $config; return $config;
} }
sub clone { sub clone {
my $self = shift; my $self = shift;
my $new = (ref $self)->new; my $new = (ref $self)->new;
$new->apply($self); $new->apply($self);
return $new; return $new;
} }
sub get_value { sub get_value {
my $self = shift; my ($self, $opt_key) = @_;
my ($opt_key) = @_;
return $Options->{$opt_key}{ratio_over} return $Options->{$opt_key}{ratio_over}
? $self->get_abs_value($opt_key) ? $self->get_abs_value($opt_key)
: $self->get($opt_key); : $self->get($opt_key);
} }
sub _handle_legacy {
my ($opt_key, $value) = @_;
# handle legacy options
if ($opt_key =~ /^(extrusion_width|bottom_layer_speed|first_layer_height)_ratio$/) {
$opt_key = $1;
$opt_key =~ s/^bottom_layer_speed$/first_layer_speed/;
$value = $value =~ /^\d+(?:\.\d+)?$/ && $value != 0 ? ($value*100) . "%" : 0;
}
if ($opt_key eq 'threads' && !$Slic3r::have_threads) {
$value = 1;
}
if ($opt_key eq 'gcode_flavor' && $value eq 'makerbot') {
$value = 'makerware';
}
if ($opt_key eq 'fill_density' && defined($value) && $value !~ /%/ && $value <= 1) {
# fill_density was turned into a percent value
$value *= 100;
$value = "$value"; # force update of the PV value, workaround for bug https://rt.cpan.org/Ticket/Display.html?id=94110
}
if ($opt_key eq 'randomize_start' && $value) {
$opt_key = 'seam_position';
$value = 'random';
}
if ($opt_key eq 'bed_size' && $value) {
$opt_key = 'bed_shape';
my ($x, $y) = split /,/, $value;
$value = "0x0,${x}x0,${x}x${y},0x${y}";
}
return () if first { $_ eq $opt_key } @Ignore;
# For historical reasons, the world's full of configs having these very low values;
# to avoid unexpected behavior we need to ignore them. Banning these two hard-coded
# values is a dirty hack and will need to be removed sometime in the future, but it
# will avoid lots of complaints for now.
if ($opt_key eq 'perimeter_acceleration' && $value == '25') {
$value = 0;
}
if ($opt_key eq 'infill_acceleration' && $value == '50') {
$value = 0;
}
if (!exists $Options->{$opt_key}) {
my @keys = grep { $Options->{$_}{aliases} && grep $_ eq $opt_key, @{$Options->{$_}{aliases}} } keys %$Options;
if (!@keys) {
warn "Unknown option $opt_key\n";
return ();
}
$opt_key = $keys[0];
}
return ($opt_key, $value);
}
# Create a hash of hashes from the underlying C++ Slic3r::DynamicPrintConfig. # Create a hash of hashes from the underlying C++ Slic3r::DynamicPrintConfig.
# The first hash key is '_' meaning no category. # The first hash key is '_' meaning no category.
# Used to create a config bundle.
sub as_ini { sub as_ini {
my ($self) = @_; my ($self) = @_;
my $ini = { _ => {} }; my $ini = { _ => {} };
foreach my $opt_key (sort @{$self->get_keys}) { foreach my $opt_key (sort @{$self->get_keys}) {
next if $Options->{$opt_key}{shortcut}; next if $Options->{$opt_key}{shortcut};
@ -212,14 +155,6 @@ sub as_ini {
return $ini; return $ini;
} }
# Save the content of the underlying C++ Slic3r::DynamicPrintConfig as a flat ini file without any category.
sub save {
my $self = shift;
my ($file) = @_;
__PACKAGE__->write_ini($file, $self->as_ini);
}
# this method is idempotent by design and only applies to ::DynamicConfig or ::Full # this method is idempotent by design and only applies to ::DynamicConfig or ::Full
# objects because it performs cross checks # objects because it performs cross checks
sub validate { sub validate {

View File

@ -112,7 +112,6 @@ sub add_volume {
sub add_instance { sub add_instance {
my $self = shift; my $self = shift;
my %params = @_;
if (@_ == 1) { if (@_ == 1) {
# we have a Model::Instance # we have a Model::Instance

View File

@ -385,21 +385,17 @@ void ConfigBase::load_from_gcode(const std::string &file)
void ConfigBase::save(const std::string &file) const void ConfigBase::save(const std::string &file) const
{ {
using namespace std;
boost::nowide::ofstream c; boost::nowide::ofstream c;
c.open(file, ios::out | ios::trunc); c.open(file, std::ios::out | std::ios::trunc);
{ {
time_t now; std::time_t now;
time(&now); time(&now);
char buf[sizeof "0000-00-00 00:00:00"]; char buf[sizeof "0000-00-00 00:00:00"];
strftime(buf, sizeof buf, "%F %T", gmtime(&now)); strftime(buf, sizeof(buf), "%F %T", gmtime(&now));
c << "# generated by Slic3r " << SLIC3R_VERSION << " on " << buf << endl; c << "# generated by Slic3r " << SLIC3R_VERSION << " on " << buf << std::endl;
} }
for (const std::string &opt_key : this->keys())
t_config_option_keys my_keys = this->keys(); c << opt_key << " = " << this->serialize(opt_key) << std::endl;
for (t_config_option_keys::const_iterator opt_key = my_keys.begin(); opt_key != my_keys.end(); ++opt_key)
c << *opt_key << " = " << this->serialize(*opt_key) << endl;
c.close(); c.close();
} }

View File

@ -646,6 +646,7 @@ public:
opt->type = type; opt->type = type;
return opt; return opt;
} }
bool has(const t_config_option_key &opt_key) const { return this->options.count(opt_key) > 0; }
const ConfigOptionDef* get(const t_config_option_key &opt_key) const { const ConfigOptionDef* get(const t_config_option_key &opt_key) const {
t_optiondef_map::iterator it = const_cast<ConfigDef*>(this)->options.find(opt_key); t_optiondef_map::iterator it = const_cast<ConfigDef*>(this)->options.find(opt_key);
return (it == this->options.end()) ? nullptr : &it->second; return (it == this->options.end()) ? nullptr : &it->second;

View File

@ -1,4 +1,6 @@
#include "PrintConfig.hpp" #include "PrintConfig.hpp"
#include <boost/algorithm/string/replace.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp> #include <boost/thread.hpp>
namespace Slic3r { namespace Slic3r {
@ -119,6 +121,10 @@ PrintConfigDef::PrintConfigDef()
def->cli = "clip-multipart-objects!"; def->cli = "clip-multipart-objects!";
def->default_value = new ConfigOptionBool(false); def->default_value = new ConfigOptionBool(false);
def = this->add("compatible_printers", coStrings);
def->label = "Compatible printers";
def->default_value = new ConfigOptionStrings();
def = this->add("complete_objects", coBool); def = this->add("complete_objects", coBool);
def->label = "Complete individual objects"; def->label = "Complete individual objects";
def->tooltip = "When printing multiple objects or copies, this feature will complete each object before moving onto next one (and starting it from its bottom layer). This feature is useful to avoid the risk of ruined prints. Slic3r should warn and prevent you from extruder collisions, but beware."; def->tooltip = "When printing multiple objects or copies, this feature will complete each object before moving onto next one (and starting it from its bottom layer). This feature is useful to avoid the risk of ruined prints. Slic3r should warn and prevent you from extruder collisions, but beware.";
@ -1704,8 +1710,87 @@ DynamicPrintConfig::normalize() {
} }
} }
double
PrintConfigBase::min_object_distance() const 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
if (opt_key == "extrusion_width_ratio" || opt_key == "bottom_layer_speed_ratio"
|| opt_key == "first_layer_height_ratio") {
boost::replace_first(opt_key, "_ratio", "");
if (opt_key == "bottom_layer_speed") opt_key = "first_layer_speed";
try {
float v = boost::lexical_cast<float>(value);
if (v != 0)
value = boost::lexical_cast<std::string>(v*100) + "%";
} catch (boost::bad_lexical_cast &) {
value = "0";
}
} else if (opt_key == "gcode_flavor" && value == "makerbot") {
value = "makerware";
} else if (opt_key == "fill_density" && value.find("%") == std::string::npos) {
try {
// fill_density was turned into a percent value
float v = boost::lexical_cast<float>(value);
value = boost::lexical_cast<std::string>(v*100) + "%";
} catch (boost::bad_lexical_cast &) {}
} else if (opt_key == "randomize_start" && value == "1") {
opt_key = "seam_position";
value = "random";
} else if (opt_key == "bed_size" && !value.empty()) {
opt_key = "bed_shape";
ConfigOptionPoint p;
p.deserialize(value);
std::ostringstream oss;
oss << "0x0," << p.value.x << "x0," << p.value.x << "x" << p.value.y << ",0x" << p.value.y;
value = oss.str();
} else if (opt_key == "octoprint_host" && !value.empty()) {
opt_key = "print_host";
} else if ((opt_key == "perimeter_acceleration" && value == "25")
|| (opt_key == "infill_acceleration" && value == "50")) {
/* For historical reasons, the world's full of configs having these very low values;
to avoid unexpected behavior we need to ignore them. Banning these two hard-coded
values is a dirty hack and will need to be removed sometime in the future, but it
will avoid lots of complaints for now. */
value = "0";
} else if (opt_key == "support_material_threshold" && value == "0") {
// 0 used to be automatic threshold, but we introduced percent values so let's
// transform it into the default value
value = "60%";
}
// cemetery of old config settings
if (opt_key == "duplicate_x" || opt_key == "duplicate_y" || opt_key == "multiply_x"
|| opt_key == "multiply_y" || opt_key == "support_material_tool"
|| opt_key == "acceleration" || opt_key == "adjust_overhang_flow"
|| opt_key == "standby_temperature" || opt_key == "scale" || opt_key == "rotate"
|| opt_key == "duplicate" || opt_key == "duplicate_grid" || opt_key == "rotate"
|| opt_key == "scale" || opt_key == "duplicate_grid"
|| opt_key == "start_perimeters_at_concave_points"
|| opt_key == "start_perimeters_at_non_overhang" || opt_key == "randomize_start"
|| opt_key == "seal_position" || opt_key == "bed_size" || opt_key == "octoprint_host"
|| opt_key == "print_center" || opt_key == "g0" || opt_key == "threads")
{
opt_key = "";
return;
}
if (!this->def->has(opt_key)) {
//printf("Unknown option %s\n", opt_key.c_str());
opt_key = "";
return;
}
}
double PrintConfigBase::min_object_distance() const
{ {
double extruder_clearance_radius = this->option("extruder_clearance_radius")->getFloat(); double extruder_clearance_radius = this->option("extruder_clearance_radius")->getFloat();
double duplicate_distance = this->option("duplicate_distance")->getFloat(); double duplicate_distance = this->option("duplicate_distance")->getFloat();

View File

@ -124,12 +124,17 @@ extern PrintConfigDef print_config_def;
// Slic3r configuration storage with print_config_def assigned. // Slic3r configuration storage with print_config_def assigned.
class PrintConfigBase : public virtual ConfigBase class PrintConfigBase : public virtual ConfigBase
{ {
public: public:
PrintConfigBase() { PrintConfigBase() {
this->def = &print_config_def; 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; 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