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.
This commit is contained in:
bubnikv 2016-11-01 13:41:24 +01:00
parent 4e66ed81d2
commit 3d3654707b
7 changed files with 280 additions and 46 deletions

View file

@ -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