Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/supermerill/SuperSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/xs
diff options
context:
space:
mode:
authorbubnikv <bubnikv@gmail.com>2016-11-01 15:41:24 +0300
committerbubnikv <bubnikv@gmail.com>2016-11-01 15:41:24 +0300
commit3d3654707b97f679037cb66c2143338cf8baf917 (patch)
treee13ed4e8725d1f4d4c1b713f518ac5167e72e16a /xs
parent4e66ed81d26774a6196259dee35a5da0c678d081 (diff)
Added "Notes" page to the filament configuration.
Added "filament_max_volumetric_speed", a cap on the maximum volumetric extrusion role, filament specific. This is very useful when mixing rigid filament with a soft filament. Extended the import / export of multi-string values into configuration values, including the test cases. Multi-line strings will be enclosed into quotes, quotes escaped using a C-style escape sequences. Single word strings could still be stored without quotes.
Diffstat (limited to 'xs')
-rw-r--r--xs/src/libslic3r/Config.cpp165
-rw-r--r--xs/src/libslic3r/Config.hpp53
-rw-r--r--xs/src/libslic3r/GCode.cpp7
-rw-r--r--xs/src/libslic3r/PrintConfig.cpp25
-rw-r--r--xs/src/libslic3r/PrintConfig.hpp4
-rw-r--r--xs/t/15_config.t46
6 files changed, 255 insertions, 45 deletions
diff --git a/xs/src/libslic3r/Config.cpp b/xs/src/libslic3r/Config.cpp
index 39c0da2bb..cdeee4dd8 100644
--- a/xs/src/libslic3r/Config.cpp
+++ b/xs/src/libslic3r/Config.cpp
@@ -8,6 +8,159 @@
namespace Slic3r {
+std::string escape_string_cstyle(const std::string &str)
+{
+ // Allocate a buffer twice the input string length,
+ // so the output will fit even if all input characters get escaped.
+ std::vector<char> out(str.size() * 2, 0);
+ char *outptr = out.data();
+ for (size_t i = 0; i < str.size(); ++ i) {
+ char c = str[i];
+ if (c == '\n' || c == '\r') {
+ (*outptr ++) = '\\';
+ (*outptr ++) = 'n';
+ } else
+ (*outptr ++) = c;
+ }
+ return std::string(out.data(), outptr - out.data());
+}
+
+std::string escape_strings_cstyle(const std::vector<std::string> &strs)
+{
+ // 1) Estimate the output buffer size to avoid buffer reallocation.
+ size_t outbuflen = 0;
+ for (size_t i = 0; i < strs.size(); ++ i)
+ // Reserve space for every character escaped + quotes + semicolon.
+ outbuflen += strs[i].size() * 2 + 3;
+ // 2) Fill in the buffer.
+ std::vector<char> out(outbuflen, 0);
+ char *outptr = out.data();
+ for (size_t j = 0; j < strs.size(); ++ j) {
+ if (j > 0)
+ // Separate the strings.
+ (*outptr ++) = ';';
+ const std::string &str = strs[j];
+ // Is the string simple or complex? Complex string contains spaces, tabs, new lines and other
+ // escapable characters. Empty string shall be quoted as well, if it is the only string in strs.
+ bool should_quote = strs.size() == 1 && str.empty();
+ for (size_t i = 0; i < str.size(); ++ i) {
+ char c = str[i];
+ if (c == ' ' || c == '\t' || c == '\\' || c == '"' || c == '\r' || c == '\n') {
+ should_quote = true;
+ break;
+ }
+ }
+ if (should_quote) {
+ (*outptr ++) = '"';
+ for (size_t i = 0; i < str.size(); ++ i) {
+ char c = str[i];
+ if (c == '\\' || c == '"') {
+ (*outptr ++) = '\\';
+ (*outptr ++) = c;
+ } else if (c == '\n' || c == '\r') {
+ (*outptr ++) = '\\';
+ (*outptr ++) = 'n';
+ } else
+ (*outptr ++) = c;
+ }
+ (*outptr ++) = '"';
+ } else {
+ memcpy(outptr, str.data(), str.size());
+ outptr += str.size();
+ }
+ }
+ return std::string(out.data(), outptr - out.data());
+}
+
+bool unescape_string_cstyle(const std::string &str, std::string &str_out)
+{
+ std::vector<char> out(str.size(), 0);
+ char *outptr = out.data();
+ for (size_t i = 0; i < str.size(); ++ i) {
+ char c = str[i];
+ if (c == '\\') {
+ if (++ i == str.size())
+ return false;
+ c = str[i];
+ if (c == 'n')
+ (*outptr ++) = '\n';
+ } else
+ (*outptr ++) = c;
+ }
+ str_out.assign(out.data(), outptr - out.data());
+ return true;
+}
+
+bool unescape_strings_cstyle(const std::string &str, std::vector<std::string> &out)
+{
+ out.clear();
+ if (str.empty())
+ return true;
+
+ size_t i = 0;
+ for (;;) {
+ // Skip white spaces.
+ char c = str[i];
+ while (c == ' ' || c == '\t') {
+ if (++ i == str.size())
+ return true;
+ c = str[i];
+ }
+ // Start of a word.
+ std::vector<char> buf;
+ buf.reserve(16);
+ // Is it enclosed in quotes?
+ c = str[i];
+ if (c == '"') {
+ // Complex case, string is enclosed in quotes.
+ for (++ i; i < str.size(); ++ i) {
+ c = str[i];
+ if (c == '"') {
+ // End of string.
+ break;
+ }
+ if (c == '\\') {
+ if (++ i == str.size())
+ return false;
+ c = str[i];
+ if (c == 'n')
+ c = '\n';
+ }
+ buf.push_back(c);
+ }
+ if (i == str.size())
+ return false;
+ ++ i;
+ } else {
+ for (; i < str.size(); ++ i) {
+ c = str[i];
+ if (c == ';')
+ break;
+ buf.push_back(c);
+ }
+ }
+ // Store the string into the output vector.
+ out.push_back(std::string(buf.data(), buf.size()));
+ if (i == str.size())
+ break;
+ // Skip white spaces.
+ c = str[i];
+ while (c == ' ' || c == '\t') {
+ if (++ i == str.size())
+ // End of string. This is correct.
+ return true;
+ c = str[i];
+ }
+ if (c != ';')
+ return false;
+ if (++ i == str.size()) {
+ // Emit one additional empty string.
+ out.push_back(std::string());
+ return true;
+ }
+ }
+}
+
bool
operator== (const ConfigOption &a, const ConfigOption &b)
{
@@ -116,16 +269,16 @@ ConfigBase::set_deserialize(const t_config_option_key &opt_key, std::string str)
// 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.
double
-ConfigBase::get_abs_value(const t_config_option_key &opt_key) {
- ConfigOption* opt = this->option(opt_key, false);
- if (ConfigOptionFloatOrPercent* optv = dynamic_cast<ConfigOptionFloatOrPercent*>(opt)) {
+ConfigBase::get_abs_value(const t_config_option_key &opt_key) const {
+ const ConfigOption* opt = this->option(opt_key);
+ if (const ConfigOptionFloatOrPercent* optv = dynamic_cast<const ConfigOptionFloatOrPercent*>(opt)) {
// get option definition
const ConfigOptionDef* def = this->def->get(opt_key);
assert(def != NULL);
// compute absolute value over the absolute value of the base option
return optv->get_abs_value(this->get_abs_value(def->ratio_over));
- } else if (ConfigOptionFloat* optv = dynamic_cast<ConfigOptionFloat*>(opt)) {
+ } else if (const ConfigOptionFloat* optv = dynamic_cast<const ConfigOptionFloat*>(opt)) {
return optv->value;
} else {
throw "Not a valid option type for get_abs_value()";
@@ -135,9 +288,9 @@ ConfigBase::get_abs_value(const t_config_option_key &opt_key) {
// 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.
double
-ConfigBase::get_abs_value(const t_config_option_key &opt_key, double ratio_over) {
+ConfigBase::get_abs_value(const t_config_option_key &opt_key, double ratio_over) const {
// get stored option value
- ConfigOptionFloatOrPercent* opt = dynamic_cast<ConfigOptionFloatOrPercent*>(this->option(opt_key));
+ const ConfigOptionFloatOrPercent* opt = dynamic_cast<const ConfigOptionFloatOrPercent*>(this->option(opt_key));
assert(opt != NULL);
// compute absolute value
diff --git a/xs/src/libslic3r/Config.hpp b/xs/src/libslic3r/Config.hpp
index ac6b03a49..3fbd82060 100644
--- a/xs/src/libslic3r/Config.hpp
+++ b/xs/src/libslic3r/Config.hpp
@@ -18,6 +18,11 @@ namespace Slic3r {
typedef std::string t_config_option_key;
typedef std::vector<std::string> t_config_option_keys;
+extern std::string escape_string_cstyle(const std::string &str);
+extern std::string escape_strings_cstyle(const std::vector<std::string> &strs);
+extern bool unescape_string_cstyle(const std::string &str, std::string &out);
+extern bool unescape_strings_cstyle(const std::string &str, std::vector<std::string> &out);
+
// A generic value of a configuration option.
class ConfigOption {
public:
@@ -112,6 +117,7 @@ class ConfigOptionFloats : public ConfigOptionVector<double>
std::vector<std::string> vserialize() const {
std::vector<std::string> vv;
+ vv.reserve(this->values.size());
for (std::vector<double>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
std::ostringstream ss;
ss << *it;
@@ -171,6 +177,7 @@ class ConfigOptionInts : public ConfigOptionVector<int>
std::vector<std::string> vserialize() const {
std::vector<std::string> vv;
+ vv.reserve(this->values.size());
for (std::vector<int>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
std::ostringstream ss;
ss << *it;
@@ -199,29 +206,12 @@ class ConfigOptionString : public ConfigOptionSingle<std::string>
ConfigOptionString() : ConfigOptionSingle<std::string>("") {};
ConfigOptionString(std::string _value) : ConfigOptionSingle<std::string>(_value) {};
- std::string serialize() const {
- std::string str = this->value;
-
- // s/\R/\\n/g
- size_t pos = 0;
- while ((pos = str.find("\n", pos)) != std::string::npos || (pos = str.find("\r", pos)) != std::string::npos) {
- str.replace(pos, 1, "\\n");
- pos += 2; // length of "\\n"
- }
-
- return str;
- };
-
+ std::string serialize() const {
+ return escape_string_cstyle(this->value);
+ }
+
bool deserialize(std::string str) {
- // s/\\n/\n/g
- size_t pos = 0;
- while ((pos = str.find("\\n", pos)) != std::string::npos) {
- str.replace(pos, 2, "\n");
- pos += 1; // length of "\n"
- }
-
- this->value = str;
- return true;
+ return unescape_string_cstyle(str, this->value);
};
};
@@ -231,12 +221,7 @@ class ConfigOptionStrings : public ConfigOptionVector<std::string>
public:
std::string serialize() const {
- std::ostringstream ss;
- for (std::vector<std::string>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
- if (it - this->values.begin() != 0) ss << ";";
- ss << *it;
- }
- return ss.str();
+ return escape_strings_cstyle(this->values);
};
std::vector<std::string> vserialize() const {
@@ -244,13 +229,7 @@ class ConfigOptionStrings : public ConfigOptionVector<std::string>
};
bool deserialize(std::string str) {
- this->values.clear();
- std::istringstream is(str);
- std::string item_str;
- while (std::getline(is, item_str, ';')) {
- this->values.push_back(item_str);
- }
- return true;
+ return unescape_strings_cstyle(str, this->values);
};
};
@@ -637,8 +616,8 @@ class ConfigBase
std::string serialize(const t_config_option_key &opt_key) const;
bool set_deserialize(const t_config_option_key &opt_key, std::string str);
- double get_abs_value(const t_config_option_key &opt_key);
- double get_abs_value(const t_config_option_key &opt_key, double ratio_over);
+ double get_abs_value(const t_config_option_key &opt_key) const;
+ double get_abs_value(const t_config_option_key &opt_key, double ratio_over) const;
void setenv_();
};
diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp
index ffc10b9a4..ee76e75d9 100644
--- a/xs/src/libslic3r/GCode.cpp
+++ b/xs/src/libslic3r/GCode.cpp
@@ -865,6 +865,13 @@ GCode::_extrude(ExtrusionPath path, std::string description, double speed)
this->config.max_volumetric_speed.value / path.mm3_per_mm
);
}
+ if (EXTRUDER_CONFIG(filament_max_volumetric_speed) > 0) {
+ // cap speed with max_volumetric_speed anyway (even if user is not using autospeed)
+ speed = std::min(
+ speed,
+ EXTRUDER_CONFIG(filament_max_volumetric_speed) / path.mm3_per_mm
+ );
+ }
double F = speed * 60; // convert mm/sec to mm/min
// extrude arc or line
diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp
index 21a441a49..78b79d77d 100644
--- a/xs/src/libslic3r/PrintConfig.cpp
+++ b/xs/src/libslic3r/PrintConfig.cpp
@@ -298,6 +298,31 @@ PrintConfigDef::PrintConfigDef()
def->default_value = opt;
}
+ def = this->add("filament_notes", coStrings);
+ def->label = "Filament notes";
+ def->tooltip = "You can put your notes regarding the filament here.";
+ def->cli = "filament-notes=s@";
+ def->multiline = true;
+ def->full_width = true;
+ def->height = 130;
+ {
+ ConfigOptionStrings* opt = new ConfigOptionStrings();
+ opt->values.push_back("");
+ def->default_value = opt;
+ }
+
+ def = this->add("filament_max_volumetric_speed", coFloats);
+ def->label = "Max volumetric speed";
+ def->tooltip = "Maximum volumetric speed allowed for this filament. Limits the maximum volumetric speed of a print to the minimum of print and filament volumetric speed. Set to zero for no limit.";
+ def->sidetext = "mm³/s";
+ def->cli = "filament-max-volumetric-speed=f@";
+ def->min = 0;
+ {
+ ConfigOptionFloats* opt = new ConfigOptionFloats();
+ opt->values.push_back(0.f);
+ def->default_value = opt;
+ }
+
def = this->add("filament_diameter", coFloats);
def->label = "Diameter";
def->tooltip = "Enter your filament diameter here. Good precision is required, so use a caliper and do multiple measurements along the filament, then compute the average.";
diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp
index 55d34368d..4efdd4173 100644
--- a/xs/src/libslic3r/PrintConfig.hpp
+++ b/xs/src/libslic3r/PrintConfig.hpp
@@ -292,6 +292,7 @@ class GCodeConfig : public virtual StaticPrintConfig
ConfigOptionString extrusion_axis;
ConfigOptionFloats extrusion_multiplier;
ConfigOptionFloats filament_diameter;
+ ConfigOptionFloats filament_max_volumetric_speed;
ConfigOptionBool gcode_comments;
ConfigOptionEnum<GCodeFlavor> gcode_flavor;
ConfigOptionString layer_gcode;
@@ -326,6 +327,7 @@ class GCodeConfig : public virtual StaticPrintConfig
OPT_PTR(extrusion_axis);
OPT_PTR(extrusion_multiplier);
OPT_PTR(filament_diameter);
+ OPT_PTR(filament_max_volumetric_speed);
OPT_PTR(gcode_comments);
OPT_PTR(gcode_flavor);
OPT_PTR(layer_gcode);
@@ -385,6 +387,7 @@ class PrintConfig : public GCodeConfig
ConfigOptionBool fan_always_on;
ConfigOptionInt fan_below_layer_time;
ConfigOptionStrings filament_colour;
+ ConfigOptionStrings filament_notes;
ConfigOptionFloat first_layer_acceleration;
ConfigOptionInt first_layer_bed_temperature;
ConfigOptionFloatOrPercent first_layer_extrusion_width;
@@ -441,6 +444,7 @@ class PrintConfig : public GCodeConfig
OPT_PTR(fan_always_on);
OPT_PTR(fan_below_layer_time);
OPT_PTR(filament_colour);
+ OPT_PTR(filament_notes);
OPT_PTR(first_layer_acceleration);
OPT_PTR(first_layer_bed_temperature);
OPT_PTR(first_layer_extrusion_width);
diff --git a/xs/t/15_config.t b/xs/t/15_config.t
index 838ce18b0..a4c5d5925 100644
--- a/xs/t/15_config.t
+++ b/xs/t/15_config.t
@@ -4,7 +4,8 @@ use strict;
use warnings;
use Slic3r::XS;
-use Test::More tests => 110;
+use Test::More tests => 146;
+use Data::Dumper;
foreach my $config (Slic3r::Config->new, Slic3r::Config::Static::new_FullPrintConfig) {
$config->set('layer_height', 0.3);
@@ -24,7 +25,48 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Static::new_FullPrintCo
is $config->serialize('notes'), 'foo\nbar', 'serialize string with newline';
$config->set_deserialize('notes', 'bar\nbaz');
is $config->get('notes'), "bar\nbaz", 'deserialize string with newline';
-
+
+ foreach my $test_data (
+ {
+ name => 'empty',
+ values => [],
+ serialized => ''
+ },
+ {
+ name => 'single empty',
+ values => [''],
+ serialized => '""'
+ },
+ {
+ name => 'single noempty, simple',
+ values => ['RGB'],
+ serialized => 'RGB'
+ },
+ {
+ name => 'multiple noempty, simple',
+ values => ['ABC', 'DEF', '09182745@!#$*(&'],
+ serialized => 'ABC;DEF;09182745@!#$*(&'
+ },
+ {
+ name => 'multiple, simple, some empty',
+ values => ['ABC', 'DEF', '', '09182745@!#$*(&', ''],
+ serialized => 'ABC;DEF;;09182745@!#$*(&;'
+ },
+ {
+ name => 'complex',
+ values => ['some "quoted" notes', "yet\n some notes", "whatever \n notes", ''],
+ serialized => '"some \"quoted\" notes";"yet\n some notes";"whatever \n notes";'
+ }
+ )
+ {
+ $config->set('filament_notes', $test_data->{values});
+ is $config->serialize('filament_notes'), $test_data->{serialized}, 'serialize multi-string value ' . $test_data->{name};
+ $config->set_deserialize('filament_notes', '');
+ is_deeply $config->get('filament_notes'), [], 'deserialize multi-string value - empty ' . $test_data->{name};
+ $config->set_deserialize('filament_notes', $test_data->{serialized});
+ is_deeply $config->get('filament_notes'), $test_data->{values}, 'deserialize complex multi-string value ' . $test_data->{name};
+ }
+
$config->set('first_layer_height', 0.3);
ok abs($config->get('first_layer_height') - 0.3) < 1e-4, 'set/get absolute floatOrPercent';
is $config->serialize('first_layer_height'), '0.3', 'serialize absolute floatOrPercent';