Skip to content

Commit

Permalink
add custom vars, fix min/max layer height, custom gcode unsaved change
Browse files Browse the repository at this point in the history
  • Loading branch information
supermerill committed Nov 9, 2021
2 parents 710016b + c9c9581 commit 704740c
Show file tree
Hide file tree
Showing 15 changed files with 312 additions and 42 deletions.
2 changes: 2 additions & 0 deletions resources/ui_layout/filament.ui
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ group:no_title:End G-code
page:Notes:note.png
group:label_width$0:Notes
setting:full_width:height$25:filament_notes
group:label_width$0:Custom variables
setting:full_width:height$15:filament_custom_variables

page:Dependencies:wrench.png
group:Profile dependencies
Expand Down
2 changes: 2 additions & 0 deletions resources/ui_layout/print.ui
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,8 @@ group:Post-processing script
page:Notes:note
group:no_title:Notes
setting:full_width:height$25:notes
group:no_title:Custom variables
setting:full_width:height$15:print_custom_variables

page:Dependencies:wrench
group:Profile dependencies
Expand Down
2 changes: 2 additions & 0 deletions resources/ui_layout/printer_fff.ui
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ height:0
page:Notes:note.png
group:no_title:Notes
setting:full_width:height$25:printer_notes
group:no_title:Custom variables
setting:full_width:height$15:printer_custom_variables

page:Dependencies:wrench.png
group:Profile dependencies
Expand Down
46 changes: 28 additions & 18 deletions src/libslic3r/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,15 @@ bool ConfigBase::set_deserialize_raw(const t_config_option_key &opt_key_src, con
return success;
}

const ConfigOptionDef* ConfigBase::get_option_def(const t_config_option_key& opt_key) const {
// Get option definition.
const ConfigDef* def = this->def();
if (def == nullptr)
throw NoDefinitionException(opt_key);
const ConfigOptionDef* opt_def = def->get(opt_key);
return opt_def;
}

// 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_computed_value(const t_config_option_key &opt_key, int extruder_id) const
Expand All @@ -674,12 +683,6 @@ double ConfigBase::get_computed_value(const t_config_option_key &opt_key, int ex
std::stringstream ss; ss << "You can't define an option that need " << opt_key << " without defining it!";
throw std::runtime_error(ss.str());
}
// Get option definition.
const ConfigDef* def = this->def();
if (def == nullptr)
throw NoDefinitionException(opt_key);
const ConfigOptionDef* opt_def = def->get(opt_key);
assert(opt_def != nullptr);

if (!raw_opt->is_vector()) {
if (raw_opt->type() == coFloat)
Expand All @@ -697,19 +700,20 @@ double ConfigBase::get_computed_value(const t_config_option_key &opt_key, int ex
if (raw_opt->type() == coPercent) {
cast_opt = static_cast<const ConfigOptionPercent*>(raw_opt);
}
if (opt_def != nullptr) {
//if over no other key, it's most probably a simple %
if (opt_def->ratio_over == "")
return cast_opt->get_abs_value(1);
// Compute absolute value over the absolute value of the base option.
//FIXME there are some ratio_over chains, which end with empty ratio_with.
// For example, XXX_extrusion_width parameters are not handled by get_abs_value correctly.
if (!opt_def->ratio_over.empty() && opt_def->ratio_over != "depends")
return cast_opt->get_abs_value(this->get_computed_value(opt_def->ratio_over));
const ConfigOptionDef* opt_def = get_option_def(opt_key);
if (opt_def == nullptr) // maybe a placeholder?
return cast_opt->get_abs_value(1);
//if over no other key, it's most probably a simple %
if (opt_def->ratio_over == "")
return cast_opt->get_abs_value(1);
// Compute absolute value over the absolute value of the base option.
//FIXME there are some ratio_over chains, which end with empty ratio_with.
// For example, XXX_extrusion_width parameters are not handled by get_abs_value correctly.
if (!opt_def->ratio_over.empty() && opt_def->ratio_over != "depends")
return cast_opt->get_abs_value(this->get_computed_value(opt_def->ratio_over));

std::stringstream ss; ss << "ConfigBase::get_abs_value(): " << opt_key << " has no valid ratio_over to compute of";
throw ConfigurationError(ss.str());
}
std::stringstream ss; ss << "ConfigBase::get_abs_value(): " << opt_key << " has no valid ratio_over to compute of";
throw ConfigurationError(ss.str());
} else {
// check if it's an extruder_id array
const ConfigOptionVectorBase* vector_opt = static_cast<const ConfigOptionVectorBase*>(raw_opt);
Expand Down Expand Up @@ -741,6 +745,9 @@ double ConfigBase::get_computed_value(const t_config_option_key &opt_key, int ex
if (!opt_fl_per->values[idx].percent)
return opt_fl_per->values[idx].value;

const ConfigOptionDef* opt_def = get_option_def(opt_key);
if (opt_def == nullptr) // maybe a placeholder?
return opt_fl_per->get_abs_value(extruder_id, 1);
if (opt_def->ratio_over.empty())
return opt_fl_per->get_abs_value(idx, 1);
if (opt_def->ratio_over != "depends")
Expand All @@ -750,6 +757,9 @@ double ConfigBase::get_computed_value(const t_config_option_key &opt_key, int ex
}
if (raw_opt->type() == coPercents) {
const ConfigOptionPercents* opt_per = static_cast<const ConfigOptionPercents*>(raw_opt);
const ConfigOptionDef* opt_def = get_option_def(opt_key);
if (opt_def == nullptr) // maybe a placeholder?
return opt_per->get_abs_value(extruder_id, 1);
if (opt_def->ratio_over.empty())
return opt_per->get_abs_value(idx, 1);
if (opt_def->ratio_over != "depends")
Expand Down
1 change: 1 addition & 0 deletions src/libslic3r/Config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2084,6 +2084,7 @@ class ConfigBase : public ConfigOptionResolver
void set_deserialize_strict(std::initializer_list<SetDeserializeItem> items)
{ ConfigSubstitutionContext ctxt{ ForwardCompatibilitySubstitutionRule::Disable }; this->set_deserialize(items, ctxt); }

const ConfigOptionDef* get_option_def(const t_config_option_key& opt_key) const;
double get_computed_value(const t_config_option_key &opt_key, int extruder_id = -1) const;
double get_abs_value(const t_config_option_key &opt_key, double ratio_over) const;
void setenv_() const;
Expand Down
6 changes: 5 additions & 1 deletion src/libslic3r/GCode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <cstdlib>
#include <math.h>
#include <string_view>
#include <map>

#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/find.hpp>
Expand Down Expand Up @@ -1107,7 +1108,6 @@ void GCode::_init_multiextruders(FILE *file, Print &print, GCodeWriter & writer,
}
}


void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thumbnail_cb)
{
PROFILE_FUNC();
Expand Down Expand Up @@ -1359,6 +1359,10 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
// Emit machine envelope limits for the Marlin firmware.
this->print_machine_envelope(file, print);

//add variables from filament_custom_variables
m_placeholder_parser.parse_custom_variables(m_config.print_custom_variables);
m_placeholder_parser.parse_custom_variables(m_config.printer_custom_variables);
m_placeholder_parser.parse_custom_variables(m_config.filament_custom_variables);

// Let the start-up script prime the 1st printing tool.
m_placeholder_parser.set("initial_tool", initial_extruder_id);
Expand Down
183 changes: 173 additions & 10 deletions src/libslic3r/PlaceholderParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -836,9 +836,10 @@ namespace client
expr<Iterator> &output)
{
std::string opt_key(opt.it_range.begin(), opt.it_range.end());
const ConfigOptionVectorBase* vector_opt = nullptr;
if (opt.opt->is_vector()) {
const ConfigOptionDef* opt_def = print_config_def.get(opt_key);
if (!opt_def->is_vector_extruder)
vector_opt = static_cast<const ConfigOptionVectorBase*>(opt.opt);
if (!vector_opt->is_extruder_size())
ctx->throw_exception("Referencing a vector variable when scalar is expected", opt.it_range);
}
const ConfigOptionDef* opt_def;
Expand Down Expand Up @@ -898,29 +899,29 @@ namespace client
ctx->throw_exception("Unknown scalar variable type", opt.it_range);
case coFloats:
case coPercents:
opt_def = print_config_def.get(opt_key);
if (opt_def->is_vector_extruder) {
vector_opt = static_cast<const ConfigOptionVectorBase*>(opt.opt);
if (vector_opt->is_extruder_size()) {
output.set_d(((ConfigOptionVectorBase*)opt.opt)->getFloat(ctx->current_extruder_id));
break;
} else
ctx->throw_exception("Unknown scalar variable type", opt.it_range);
case coFloatsOrPercents:
opt_def = print_config_def.get(opt_key);
if (opt_def->is_vector_extruder) {
vector_opt = static_cast<const ConfigOptionVectorBase*>(opt.opt);
if (vector_opt->is_extruder_size()) {
output.set_d(ctx->get_computed_value(opt_key));
break;
} else
ctx->throw_exception("Unknown scalar variable type", opt.it_range);
case coStrings:
opt_def = print_config_def.get(opt_key);
if (opt_def->is_vector_extruder) {
vector_opt = static_cast<const ConfigOptionVectorBase*>(opt.opt);
if (vector_opt->is_extruder_size()) {
output.set_s(((ConfigOptionStrings*)opt.opt)->values[ctx->current_extruder_id]);
break;
} else
ctx->throw_exception("Unknown scalar variable type", opt.it_range);
case coPoints:
opt_def = print_config_def.get(opt_key);
if (opt_def->is_vector_extruder) {
vector_opt = static_cast<const ConfigOptionVectorBase*>(opt.opt);
if (vector_opt->is_extruder_size()) {
output.set_s(to_string(((ConfigOptionPoints*)opt.opt)->values[ctx->current_extruder_id]));
break;
}else
Expand Down Expand Up @@ -1493,4 +1494,166 @@ bool PlaceholderParser::evaluate_boolean_expression(const std::string &templ, co
return process_macro(templ, context) == "true";
}


void PlaceholderParser::append_custom_variables(std::map<std::string, std::vector<std::string>> name2var_array, int nb_extruders) {
std::regex is_a_name("[a-zA-Z_]+");
for (const auto& entry : name2var_array) {
if (entry.first.empty())
continue;
if (!std::regex_match(entry.first, is_a_name))
continue;
const std::vector<std::string>& values = entry.second;
//check if all values are empty
bool is_not_string = false;
for (int extruder_id = 0; extruder_id < nb_extruders; ++extruder_id) {
if (!values[extruder_id].empty()) {
is_not_string = true;
break;
}
}
std::vector<std::string> string_values;
//check if all values are strings
if (is_not_string) {
is_not_string = false;
for (int extruder_id = 0; extruder_id < nb_extruders; ++extruder_id) {
if (!values[extruder_id].empty()) {
if (values[extruder_id].front() != '\"' && values[extruder_id].back() != '\"') {
is_not_string = true;
break;
}
string_values.push_back(values[extruder_id].substr(1, values[extruder_id].size() - 2));
} else {
string_values.push_back("");
}
}
}
//check if all values are bools
bool is_not_bool = !is_not_string;
std::vector<unsigned char> bool_values;
if (!is_not_bool) {
for (int extruder_id = 0; extruder_id < nb_extruders; ++extruder_id) {
if (!values[extruder_id].empty()) {
if (boost::algorithm::to_lower_copy(values[extruder_id]) == "true") {
bool_values.push_back(true);
} else if (boost::algorithm::to_lower_copy(values[extruder_id]) == "false") {
bool_values.push_back(false);
} else {
is_not_bool = true;
break;
}
} else {
bool_values.push_back(false);
}
}
}
//check if all values are numeric
bool is_not_numeric = !is_not_string || !is_not_bool;
std::vector<double> double_values;
//std::regex("\\s*[+-]?([0-9]+\\.[0-9]*([Ee][+-]?[0-9]+)?|\\.[0-9]+([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+)");
if (!is_not_numeric) {
for (int extruder_id = 0; extruder_id < nb_extruders; ++extruder_id) {
if (!values[extruder_id].empty()) {
try {
double_values.push_back(boost::lexical_cast<float>(values[extruder_id]));
}
catch (boost::bad_lexical_cast&) {
is_not_numeric = true;
break;
}
} else {
double_values.push_back(0);
}
}
}
//if nothing, then it's strings
if (is_not_string && is_not_numeric && is_not_bool) {
string_values = values;
is_not_string = false;
}
if (!is_not_numeric) {
std::stringstream log;
log << "Parsing NUM custom variable '" << entry.first << "' : ";
for (auto s : double_values) log << ", " << s;
BOOST_LOG_TRIVIAL(trace) << log.str();
ConfigOptionFloats* conf = new ConfigOptionFloats(double_values);
conf->set_is_extruder_size(true);
this->set(entry.first, conf);
} else if (!is_not_bool) {
std::stringstream log;
log << "Parsing BOOL custom variable '" << entry.first << "' : ";
for (auto s : bool_values) log << ", " << s;
BOOST_LOG_TRIVIAL(trace) << log.str();
ConfigOptionBools* conf = new ConfigOptionBools(bool_values);
conf->set_is_extruder_size(true);
this->set(entry.first, conf);
} else {
for (std::string& s : string_values)
boost::replace_all(s, "\\n", "\n");
std::stringstream log;
log << "Parsing STR custom variable '" << entry.first << "' : ";
for (auto s : string_values) log << ", " << s;
BOOST_LOG_TRIVIAL(trace) << log.str();
ConfigOptionStrings* conf = new ConfigOptionStrings(string_values);
conf->set_is_extruder_size(true);
this->set(entry.first, conf);
}
}

}

void PlaceholderParser::parse_custom_variables(const ConfigOptionString& custom_variables) {

std::map<std::string, std::vector<std::string>> name2var_array;

std::string raw_text = custom_variables.value;
boost::erase_all(raw_text, "\r");
std::vector<std::string> lines;
boost::algorithm::split(lines, raw_text, boost::is_any_of("\n"));
for (const std::string& line : lines) {
int equal_pos = line.find_first_of('=');
if (equal_pos != std::string::npos) {
std::string name = line.substr(0, equal_pos);
std::string value = line.substr(equal_pos + 1);
boost::algorithm::trim(name);
boost::algorithm::trim(value);
if (name2var_array.find(name) == name2var_array.end()) {
name2var_array.emplace(name, std::vector<std::string>{ 1, value });
} else
name2var_array[name][0] = value;

}
}
append_custom_variables(name2var_array, 1);
}

void PlaceholderParser::parse_custom_variables(const ConfigOptionStrings& filament_custom_variables)
{
std::map<std::string, std::vector<std::string>> name2var_array;
const std::vector<std::string> empty_array(filament_custom_variables.values.size());

for (int extruder_id = 0; extruder_id < filament_custom_variables.values.size(); ++extruder_id)
{
std::string raw_text = filament_custom_variables.values[extruder_id];
boost::erase_all(raw_text, "\r");
std::vector<std::string> lines;
boost::algorithm::split(lines, raw_text, boost::is_any_of("\n"));
for (const std::string& line : lines) {
int equal_pos = line.find_first_of('=');
if (equal_pos != std::string::npos) {
std::string name = line.substr(0, equal_pos);
std::string value = line.substr(equal_pos + 1);
boost::algorithm::trim(name);
boost::algorithm::trim(value);
if (name2var_array.find(name) == name2var_array.end()) {
name2var_array.emplace(name, empty_array);
}
name2var_array[name][extruder_id] = value;

}
}
}
append_custom_variables(name2var_array, filament_custom_variables.values.size());
}


}
7 changes: 7 additions & 0 deletions src/libslic3r/PlaceholderParser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,14 @@ class PlaceholderParser
// Update timestamp, year, month, day, hour, minute, second variables at m_config.
void update_timestamp() { update_timestamp(m_config); }

// set custom variables
void parse_custom_variables(const ConfigOptionString& custom_variables);
void parse_custom_variables(const ConfigOptionStrings& filament_custom_variables);


private:
void append_custom_variables(std::map<std::string, std::vector<std::string>> name2var_array, int nb_extruders);

// config has a higher priority than external_config when looking up a symbol.
DynamicConfig m_config;
const DynamicConfig *m_external_config;
Expand Down
Loading

0 comments on commit 704740c

Please sign in to comment.