Merge branch 'ys_spe1916'

This commit is contained in:
Lukas Matena 2024-06-06 13:36:25 +02:00
commit e1b33bacf2
25 changed files with 2308 additions and 1674 deletions

View File

@ -1,4 +1,10 @@
min_slic3r_version = 2.7.5-rc
1.14.0 Added new settings for SLA material profiles.
min_slic3r_version = 2.7.3-beta1
1.13.4 Updated FW version notification (6.0.1). Added ROSA3D filaments. Updated print profiles for 0.6 nozzle. Updated perimeter speeds in "0.10mm FAST DETAIL" profile (MK4/XL). Slightly increased nozzle temperature for Generic PETG/Prusa PETG/Prusament PETG (0.6n).
1.13.3 Updated FW version notification.
1.13.2 Added material profiles for Prusament Resin Flex Anatomic Red and Prusament Resin Flex Gingiva Mask.
1.13.1 Added material profile for Prusament Resin Model Transparent Clear. Enabled stealth mode support for MINI, XL, MK3.5, MK3.9, MK4 (this mode will be available in FW 6.0.0).
1.13.0 Updated version for PrusaSlicer 2.7.3
1.13.0-beta3 Reduced number of top/bottom layers (0.6). Updated cooling thresholds.
1.13.0-beta2 Disabled ramping lift for MK3.5.

File diff suppressed because one or more lines are too long

View File

@ -153,8 +153,8 @@ namespace ImGui
const wchar_t PlugMarker = 0x1C;
const wchar_t DowelMarker = 0x1D;
const wchar_t SnapMarker = 0x1E;
const wchar_t HorizontalHide = 0xB1;
const wchar_t HorizontalShow = 0xB2;
const wchar_t HorizontalHide = 0xB4;
const wchar_t HorizontalShow = 0xB6;
// Do not forget use following letters only in wstring
const wchar_t DocumentationButton = 0x2600;
const wchar_t DocumentationHoverButton = 0x2601;

View File

@ -294,6 +294,7 @@ ConfigOption* ConfigOptionDef::create_empty_option() const
case coBool: return new ConfigOptionBool();
case coBools: return new ConfigOptionBools();
case coEnum: return new ConfigOptionEnumGeneric(this->enum_def->m_enum_keys_map);
case coEnums: return new ConfigOptionEnumsGeneric(this->enum_def->m_enum_keys_map);
default: throw ConfigurationError(std::string("Unknown option type for option ") + this->label);
}
}
@ -304,7 +305,10 @@ ConfigOption* ConfigOptionDef::create_default_option() const
if (this->default_value)
return (this->default_value->type() == coEnum) ?
// Special case: For a DynamicConfig, convert a templated enum to a generic enum.
new ConfigOptionEnumGeneric(this->enum_def->m_enum_keys_map, this->default_value->getInt()) :
new ConfigOptionEnumGeneric(this->enum_def->m_enum_keys_map, this->default_value->getInt()) :
(this->default_value->type() == coEnums) ?
// Special case: For a DynamicConfig, convert a templated enums to a generic enums.
new ConfigOptionEnumsGeneric(this->enum_def->m_enum_keys_map, this->default_value->getInts()) :
this->default_value->clone();
return this->create_empty_option();
}
@ -333,7 +337,7 @@ void ConfigDef::finalize()
// Validate & finalize open & closed enums.
for (std::pair<const t_config_option_key, ConfigOptionDef> &kvp : options) {
ConfigOptionDef& def = kvp.second;
if (def.type == coEnum) {
if (def.type == coEnum || def.type == coEnums) {
assert(def.enum_def);
assert(def.enum_def->is_valid_closed_enum());
assert(! def.is_gui_type_enum_open());
@ -1467,6 +1471,7 @@ CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionBool)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionBools)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionBoolsNullable)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionEnumGeneric)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionEnumsGeneric)
CEREAL_REGISTER_TYPE(Slic3r::ConfigBase)
CEREAL_REGISTER_TYPE(Slic3r::DynamicConfig)
@ -1508,4 +1513,5 @@ CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<bool>, Slic3r::C
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<unsigned char>, Slic3r::ConfigOptionBools)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<unsigned char>, Slic3r::ConfigOptionBoolsNullable)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionInt, Slic3r::ConfigOptionEnumGeneric)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionInts, Slic3r::ConfigOptionEnumsGeneric)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigBase, Slic3r::DynamicConfig)

View File

@ -214,6 +214,8 @@ enum ConfigOptionType {
coBools = coBool + coVectorType,
// a generic enum
coEnum = 9,
// vector of enum values
coEnums = coEnum + coVectorType,
};
enum ConfigOptionMode {
@ -290,6 +292,7 @@ public:
// Set a value from a ConfigOption. The two options should be compatible.
virtual void set(const ConfigOption *option) = 0;
virtual int getInt() const { throw BadOptionTypeException("Calling ConfigOption::getInt on a non-int ConfigOption"); }
virtual std::vector<int> getInts() const { throw BadOptionTypeException("Calling ConfigOption::getInts on a non-ints ConfigOption"); }
virtual double getFloat() const { throw BadOptionTypeException("Calling ConfigOption::getFloat on a non-float ConfigOption"); }
virtual bool getBool() const { throw BadOptionTypeException("Calling ConfigOption::getBool on a non-boolean ConfigOption"); }
virtual void setInt(int /* val */) { throw BadOptionTypeException("Calling ConfigOption::setInt on a non-int ConfigOption"); }
@ -1741,6 +1744,113 @@ public:
}
};
template <class T>
class ConfigOptionEnums : public ConfigOptionVector<T>
{
public:
// by default, use the first value (0) of the T enum type
ConfigOptionEnums() : ConfigOptionVector<T>() {}
explicit ConfigOptionEnums(size_t n, const T& value) : ConfigOptionVector<T>(n, value) {}
explicit ConfigOptionEnums(std::initializer_list<T> il) : ConfigOptionVector<T>(std::move(il)) {}
explicit ConfigOptionEnums(const std::vector<T>& values) : ConfigOptionVector<T>(values) {}
static ConfigOptionType static_type() { return coEnums; }
ConfigOptionType type() const override { return static_type(); }
ConfigOption* clone() const override { return new ConfigOptionEnums<T>(*this); }
ConfigOptionEnums<T>& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
bool operator==(const ConfigOptionEnums<T> &rhs) const throw() { return this->values == rhs.values; }
bool operator< (const ConfigOptionEnums<T> &rhs) const throw() { return this->values < rhs.values; }
bool is_nil(size_t) const override { return false; }
std::vector<int> getInts() const override {
std::vector<int> ret;
ret.reserve(this->values.size());
for (const auto& v : this->values)
ret.push_back(int(v));
return ret;
}
bool operator==(const ConfigOption& rhs) const override
{
if (rhs.type() != this->type())
throw ConfigurationError("ConfigOptionEnums<T>: Comparing incompatible types");
// rhs could be of the following type: ConfigOptionEnumsGeneric or ConfigOptionEnums<T>
return this->getInts() == rhs.getInts();
}
void set(const ConfigOption* rhs) override {
if (rhs->type() != this->type())
throw ConfigurationError("ConfigOptionEnums<T>: Assigning an incompatible type");
// rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum<T>
std::vector<T> ret;
std::vector<int> rhs_vals = rhs->getInts();
ret.reserve(rhs_vals.size());
for (const int& v : rhs_vals)
ret.push_back(T(v));
this->values = ret;
}
std::string serialize() const override
{
const t_config_enum_names& names = ConfigOptionEnum<T>::get_enum_names();
std::ostringstream ss;
for (const T& v : this->values) {
assert(static_cast<int>(v) < int(names.size()));
if (&v != &this->values.front())
ss << "," << names[static_cast<int>(v)];
}
return ss.str();
}
std::vector<std::string> vserialize() const override
{
std::vector<std::string> vv;
vv.reserve(this->values.size());
for (const T v : this->values) {
std::ostringstream ss;
serialize_single_value(ss, int(v));
vv.push_back(ss.str());
}
return vv;
}
bool deserialize(const std::string& str, bool append = false) override
{
if (!append)
this->values.clear();
std::istringstream is(str);
std::string item_str;
while (std::getline(is, item_str, ',')) {
boost::trim(item_str);
if (item_str == "nil") {
throw ConfigurationError("Deserializing nil into a non-nullable object");
}
else {
std::istringstream iss(item_str);
int value;
iss >> value;
this->values.push_back(static_cast<T>(value));
}
}
return true;
}
static bool from_string(const std::string &str, T &value)
{
const t_config_enum_values &enum_keys_map = ConfigOptionEnum<T>::get_enum_values();
auto it = enum_keys_map.find(str);
if (it == enum_keys_map.end())
return false;
value = static_cast<T>(it->second);
return true;
}
private:
void serialize_single_value(std::ostringstream& ss, const int v) const {
ss << v;
}
};
// Generic enum configuration value.
// We use this one in DynamicConfig objects when creating a config value object for ConfigOptionType == coEnum.
// In the StaticConfig, it is better to use the specialized ConfigOptionEnum<T> containers.
@ -1797,6 +1907,132 @@ private:
template<class Archive> void serialize(Archive& ar) { ar(cereal::base_class<ConfigOptionInt>(this)); }
};
template<bool NULLABLE>
class ConfigOptionEnumsGenericTempl : public ConfigOptionIntsTempl<NULLABLE>
{
public:
ConfigOptionEnumsGenericTempl(const t_config_enum_values* keys_map = nullptr) : keys_map(keys_map) {}
explicit ConfigOptionEnumsGenericTempl(const t_config_enum_values* keys_map, std::vector<int> values) : keys_map(keys_map) { this->values = values; }
const t_config_enum_values* keys_map;
ConfigOptionEnumsGenericTempl() : ConfigOptionIntsTempl<NULLABLE>() {}
explicit ConfigOptionEnumsGenericTempl(size_t n, int value) : ConfigOptionIntsTempl<NULLABLE>(n, value) {}
explicit ConfigOptionEnumsGenericTempl(std::initializer_list<int> il) : ConfigOptionIntsTempl<NULLABLE>(std::move(il)) {}
explicit ConfigOptionEnumsGenericTempl(const std::vector<int>& v) : ConfigOptionIntsTempl<NULLABLE>(v) {}
explicit ConfigOptionEnumsGenericTempl(std::vector<int>&& v) : ConfigOptionIntsTempl<NULLABLE>(std::move(v)) {}
static ConfigOptionType static_type() { return coEnums; }
ConfigOptionType type() const override { return static_type(); }
ConfigOption* clone() const override { return new ConfigOptionEnumsGenericTempl(*this); }
ConfigOptionEnumsGenericTempl& operator= (const ConfigOption* opt) { this->set(opt); return *this; }
bool operator==(const ConfigOptionEnumsGenericTempl& rhs) const throw() { return this->values == rhs.values; }
bool operator< (const ConfigOptionEnumsGenericTempl& rhs) const throw() { return this->values < rhs.values; }
std::vector<int> getInts() const override { return this->values; }
bool operator==(const ConfigOption& rhs) const override
{
if (rhs.type() != this->type())
throw ConfigurationError("ConfigOptionEnumsGeneric: Comparing incompatible types");
// rhs could be of the following type: ConfigOptionEnumsGeneric or ConfigOptionEnums<T>
return this->values == rhs.getInts();
}
void set(const ConfigOption* rhs) override {
if (rhs->type() != this->type())
throw ConfigurationError("ConfigOptionEnumsGeneric: Assigning an incompatible type");
// rhs could be of the following type: ConfigOptionEnumsGeneric or ConfigOptionEnums<T>
this->values = rhs->getInts();
}
// Could a special "nil" value be stored inside the vector, indicating undefined value?
bool nullable() const override { return NULLABLE; }
// Special "nil" value to be stored into the vector if this->supports_nil().
static int nil_value() { return std::numeric_limits<int>::max(); }
// A scalar is nil, or all values of a vector are nil.
bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; }
bool is_nil(size_t idx) const override { return this->values[idx < this->values.size() ? idx : 0] == nil_value(); }
int& get_at(size_t i) {
assert(!this->values.empty());
return *reinterpret_cast<int*>(&((i < this->values.size()) ? this->values[i] : this->values.front()));
}
int get_at(size_t i) const { return i < this->values.size() ? this->values[i] : this->values.front(); }
std::string serialize() const override
{
std::ostringstream ss;
for (const int& v : this->values) {
if (&v != &this->values.front())
ss << ",";
serialize_single_value(ss, v);
}
return ss.str();
}
std::vector<std::string> vserialize() const override
{
std::vector<std::string> vv;
vv.reserve(this->values.size());
for (const int v : this->values) {
std::ostringstream ss;
serialize_single_value(ss, v);
vv.push_back(ss.str());
}
return vv;
}
bool deserialize(const std::string& str, bool append = false) override
{
if (!append)
this->values.clear();
std::istringstream is(str);
std::string item_str;
while (std::getline(is, item_str, ',')) {
boost::trim(item_str);
if (item_str == "nil") {
if (NULLABLE)
this->values.push_back(nil_value());
else
throw ConfigurationError("Deserializing nil into a non-nullable object");
}
else {
auto it = this->keys_map->find(item_str);
if (it == this->keys_map->end())
return false;
this->values.push_back(it->second);
}
}
return true;
}
private:
void serialize_single_value(std::ostringstream& ss, const int v) const {
if (v == nil_value()) {
if (NULLABLE)
ss << "nil";
else
throw ConfigurationError("Serializing NaN");
}
else {
for (const auto& kvp : *this->keys_map)
if (kvp.second == v) {
ss << kvp.first;
return;
}
ss << std::string();
}
}
friend class cereal::access;
template<class Archive> void serialize(Archive& ar) { ar(cereal::base_class<ConfigOptionVector<int>>(this)); }
};
using ConfigOptionEnumsGeneric = ConfigOptionEnumsGenericTempl<false>;
using ConfigOptionEnumsGenericNullable = ConfigOptionEnumsGenericTempl<true>;
// Definition of values / labels for a combo box.
// Mostly used for closed enums (when type == coEnum), but may be used for
// open enums with ints resp. floats, if gui_type is set to GUIType::i_enum_open" resp. GUIType::f_enum_open.
@ -2043,6 +2279,7 @@ public:
case coBool: { auto opt = new ConfigOptionBool(); archive(*opt); return opt; }
case coBools: { auto opt = new ConfigOptionBools(); archive(*opt); return opt; }
case coEnum: { auto opt = new ConfigOptionEnumGeneric(this->enum_def->m_enum_keys_map); archive(*opt); return opt; }
case coEnums: { auto opt = new ConfigOptionEnumsGeneric(this->enum_def->m_enum_keys_map); archive(*opt); return opt; }
default: throw ConfigurationError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown option type for option ") + this->opt_key);
}
}
@ -2077,6 +2314,7 @@ public:
case coBool: archive(*static_cast<const ConfigOptionBool*>(opt)); break;
case coBools: archive(*static_cast<const ConfigOptionBools*>(opt)); break;
case coEnum: archive(*static_cast<const ConfigOptionEnumGeneric*>(opt)); break;
case coEnums: archive(*static_cast<const ConfigOptionEnumsGeneric*>(opt)); break;
default: throw ConfigurationError(std::string("ConfigOptionDef::save_option_to_archive(): Unknown option type for option ") + this->opt_key);
}
}
@ -2484,6 +2722,8 @@ public:
// Thus the virtual method getInt() is used to retrieve the enum value.
template<typename ENUM>
ENUM opt_enum(const t_config_option_key &opt_key) const { return static_cast<ENUM>(this->option(opt_key)->getInt()); }
template<typename ENUM>
ENUM opt_enum(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast<const ConfigOptionEnums<ENUM>*>(this->option(opt_key))->get_at(idx);}
bool opt_bool(const t_config_option_key &opt_key) const { return this->option<ConfigOptionBool>(opt_key)->value != 0; }
bool opt_bool(const t_config_option_key &opt_key, unsigned int idx) const { return this->option<ConfigOptionBools>(opt_key)->get_at(idx) != 0; }

View File

@ -19,6 +19,7 @@
#include "libslic3r/miniz_extension.hpp"
#include "libslic3r/LocalesUtils.hpp"
#include "libslic3r/GCode/ThumbnailData.hpp"
#include "libslic3r/Utils/JsonUtils.hpp"
#include "SLAArchiveReader.hpp"
#include "SLAArchiveFormatRegistry.hpp"
@ -33,6 +34,7 @@
#include <boost/property_tree/ini_parser.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/algorithm/string.hpp>
@ -51,6 +53,110 @@ std::string to_ini(const ConfMap &m)
return ret;
}
static std::string get_key(const std::string& opt_key)
{
static const std::set<std::string> ms_opts = {
"delay_before_exposure"
, "delay_after_exposure"
, "tilt_down_offset_delay"
, "tilt_up_offset_delay"
, "tilt_down_delay"
, "tilt_up_delay"
};
static const std::set<std::string> nm_opts = {
"tower_hop_height"
};
static const std::set<std::string> speed_opts = {
"tower_speed"
, "tilt_down_initial_speed"
, "tilt_down_finish_speed"
, "tilt_up_initial_speed"
, "tilt_up_finish_speed"
};
if (ms_opts.find(opt_key) != ms_opts.end())
return opt_key + "_ms";
if (nm_opts.find(opt_key) != nm_opts.end())
return opt_key + "_nm";
if (speed_opts.find(opt_key) != speed_opts.end())
return boost::replace_all_copy(opt_key, "_speed", "_profile");
return opt_key;
}
namespace pt = boost::property_tree;
std::string to_json(const SLAPrint& print, const ConfMap &m)
{
auto& cfg = print.full_print_config();
pt::ptree below_node;
pt::ptree above_node;
const t_config_enum_names& tilt_enum_names = ConfigOptionEnum< TiltSpeeds>::get_enum_names();
const t_config_enum_names& tower_enum_names = ConfigOptionEnum<TowerSpeeds>::get_enum_names();
for (const std::string& opt_key : tilt_options()) {
const ConfigOption* opt = cfg.option(opt_key);
assert(opt != nullptr);
switch (opt->type()) {
case coFloats: {
auto values = static_cast<const ConfigOptionFloats*>(opt);
// those options have to be exported in ms instead of s
below_node.put<double>(get_key(opt_key), int(1000 * values->get_at(0)));
above_node.put<double>(get_key(opt_key), int(1000 * values->get_at(1)));
}
break;
case coInts: {
auto values = static_cast<const ConfigOptionInts*>(opt);
int koef = opt_key == "tower_hop_height" ? 1000000 : 1;
below_node.put<int>(get_key(opt_key), koef * values->get_at(0));
above_node.put<int>(get_key(opt_key), koef * values->get_at(1));
}
break;
case coBools: {
auto values = static_cast<const ConfigOptionBools*>(opt);
below_node.put<bool>(get_key(opt_key), values->get_at(0));
above_node.put<bool>(get_key(opt_key), values->get_at(1));
}
break;
case coEnums: {
const t_config_enum_names& enum_names = opt_key == "tower_speed" ? tower_enum_names : tilt_enum_names;
auto values = static_cast<const ConfigOptionEnums<TiltSpeeds>*>(opt);
below_node.put(get_key(opt_key), enum_names[values->get_at(0)]);
above_node.put(get_key(opt_key), enum_names[values->get_at(1)]);
}
break;
case coNone:
default:
break;
}
}
pt::ptree profile_node;
profile_node.put("area_fill", cfg.option("area_fill")->serialize());
profile_node.add_child("below_area_fill", below_node);
profile_node.add_child("above_area_fill", above_node);
pt::ptree root;
// params from config.ini
for (auto& param : m)
root.put(param.first, param.second );
root.put("version", "1");
root.add_child("exposure_profile", profile_node);
// Boost confirms its implementation has no 100% conformance to JSON standard.
// In the boost libraries, boost will always serialize each value as string and parse all values to a string equivalent.
// so, post-prosess output
return write_json_with_post_process(root);
}
std::string get_cfg_value(const DynamicPrintConfig &cfg, const std::string &key)
{
std::string ret;
@ -123,10 +229,15 @@ void fill_slicerconf(ConfMap &m, const SLAPrint &print)
auto is_banned = [](const std::string &key) {
return std::binary_search(banned_keys.begin(), banned_keys.end(), key);
};
auto is_tilt_param = [](const std::string& key) -> bool {
const auto& keys = tilt_options();
return std::find(keys.begin(), keys.end(), key) != keys.end();
};
auto &cfg = print.full_print_config();
for (const std::string &key : cfg.keys())
if (! is_banned(key) && ! cfg.option(key)->is_nil())
if (! is_banned(key) && !is_tilt_param(key) && ! cfg.option(key)->is_nil())
m[key] = cfg.opt_serialize(key);
}
@ -212,6 +323,9 @@ void SL1Archive::export_print(Zipper &zipper,
zipper.add_entry("prusaslicer.ini");
zipper << to_ini(slicerconf);
zipper.add_entry("config.json");
zipper << to_json(print, iniconf);
size_t i = 0;
for (const sla::EncodedRaster &rst : m_layers) {

View File

@ -26,6 +26,7 @@
#include <fstream>
#include <stdexcept>
#include <unordered_map>
#include <boost/range/join.hpp>
#include <boost/format.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
@ -606,6 +607,7 @@ static std::vector<std::string> s_Preset_sla_material_options {
"material_notes",
"material_vendor",
"material_print_speed",
"area_fill",
"default_sla_material_profile",
"compatible_prints", "compatible_prints_condition",
"compatible_printers", "compatible_printers_condition", "inherits",
@ -622,20 +624,40 @@ static std::vector<std::string> s_Preset_sla_material_options {
"material_ow_branchingsupport_pillar_diameter",
"material_ow_support_points_density_relative",
"material_ow_relative_correction_x",
"material_ow_relative_correction_y",
"material_ow_relative_correction_z",
"material_ow_absolute_correction",
"material_ow_elefant_foot_compensation"
};
static std::vector<std::string> s_Preset_sla_tilt_options{
"delay_before_exposure"
,"delay_after_exposure"
,"tower_hop_height"
,"tower_speed"
,"use_tilt"
,"tilt_down_initial_speed"
,"tilt_down_offset_steps"
,"tilt_down_offset_delay"
,"tilt_down_finish_speed"
,"tilt_down_cycles"
,"tilt_down_delay"
,"tilt_up_initial_speed"
,"tilt_up_offset_steps"
,"tilt_up_offset_delay"
,"tilt_up_finish_speed"
,"tilt_up_cycles"
,"tilt_up_delay"
};
const std::vector<std::string>& tilt_options() { return s_Preset_sla_tilt_options; }
static std::vector<std::string> s_Preset_sla_material_options_all = boost::copy_range<std::vector<std::string>>(boost::join(s_Preset_sla_material_options, s_Preset_sla_tilt_options));
static std::vector<std::string> s_Preset_sla_printer_options {
"printer_technology",
"bed_shape", "bed_custom_texture", "bed_custom_model", "max_print_height",
"display_width", "display_height", "display_pixels_x", "display_pixels_y",
"display_mirror_x", "display_mirror_y",
"display_orientation",
"fast_tilt_time", "slow_tilt_time", "high_viscosity_tilt_time", "area_fill",
"fast_tilt_time", "slow_tilt_time", "high_viscosity_tilt_time", //"area_fill",
"relative_correction",
"relative_correction_x",
"relative_correction_y",
@ -659,7 +681,7 @@ const std::vector<std::string>& Preset::machine_limits_options() { return s_Pres
// of the nozzle_diameter vector.
const std::vector<std::string>& Preset::nozzle_options() { return print_config_def.extruder_option_keys(); }
const std::vector<std::string>& Preset::sla_print_options() { return s_Preset_sla_print_options; }
const std::vector<std::string>& Preset::sla_material_options() { return s_Preset_sla_material_options; }
const std::vector<std::string>& Preset::sla_material_options() { return s_Preset_sla_material_options_all; }
const std::vector<std::string>& Preset::sla_printer_options() { return s_Preset_sla_printer_options; }
const std::vector<std::string>& Preset::printer_options()
@ -1378,6 +1400,7 @@ inline t_config_option_keys deep_diff(const ConfigBase &config_this, const Confi
case coPercents:add_correct_opts_to_diff<ConfigOptionPercents >(opt_key, diff, config_other, config_this); break;
case coPoints: add_correct_opts_to_diff<ConfigOptionPoints >(opt_key, diff, config_other, config_this); break;
case coFloatsOrPercents: add_correct_opts_to_diff<ConfigOptionFloatsOrPercents >(opt_key, diff, config_other, config_this); break;
case coEnums: add_correct_opts_to_diff<ConfigOptionEnumsGeneric>(opt_key, diff, config_other, config_this); break;
default: diff.emplace_back(opt_key); break;
}
// "nozzle_diameter" is a vector option which contain info about diameter for each nozzle

View File

@ -257,6 +257,7 @@ static t_config_enum_values s_keys_map_PerimeterGeneratorType {
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PerimeterGeneratorType)
static t_config_enum_values s_keys_map_TopOnePerimeterType {
{ "none", int(TopOnePerimeterType::None) },
{ "top", int(TopOnePerimeterType::TopSurfaces) },
@ -264,6 +265,39 @@ static t_config_enum_values s_keys_map_TopOnePerimeterType {
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(TopOnePerimeterType)
static const t_config_enum_values s_keys_map_TowerSpeeds{
{ "layer1", tsLayer1 },
{ "layer2", tsLayer2 },
{ "layer3", tsLayer3 },
{ "layer4", tsLayer4 },
{ "layer5", tsLayer5 },
{ "layer8", tsLayer8 },
{ "layer11", tsLayer11 },
{ "layer14", tsLayer14 },
{ "layer18", tsLayer18 },
{ "layer22", tsLayer22 },
{ "layer24", tsLayer24 },
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(TowerSpeeds)
static const t_config_enum_values s_keys_map_TiltSpeeds{
{ "move120", tsMove120 },
{ "layer200", tsLayer200 },
{ "move300", tsMove300 },
{ "layer400", tsLayer400 },
{ "layer600", tsLayer600 },
{ "layer800", tsLayer800 },
{ "layer1000", tsLayer1000 },
{ "layer1250", tsLayer1250 },
{ "layer1500", tsLayer1500 },
{ "layer1750", tsLayer1750 },
{ "layer2000", tsLayer2000 },
{ "layer2250", tsLayer2250 },
{ "move5120", tsMove5120 },
{ "move8000", tsMove8000 },
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(TiltSpeeds)
static void assign_printer_technology_to_unknown(t_optiondef_map &options, PrinterTechnology printer_technology)
{
for (std::pair<const t_config_option_key, ConfigOptionDef> &kvp : options)
@ -284,6 +318,7 @@ PrintConfigDef::PrintConfigDef()
this->init_extruder_option_keys();
assign_printer_technology_to_unknown(this->options, ptFFF);
this->init_sla_params();
this->init_sla_tilt_params();
assign_printer_technology_to_unknown(this->options, ptSLA);
this->finalize();
}
@ -3949,12 +3984,14 @@ void PrintConfigDef::init_sla_params()
def->set_default_value(new ConfigOptionFloat(10.));
def = this->add("area_fill", coFloat);
def->label = L("Area fill");
def->tooltip = L("The percentage of the bed area. \nIf the print area exceeds the specified value, \nthen a slow tilt will be used, otherwise - a fast tilt");
def->label = L("Area fill threshold");
def->tooltip = L("The value is expressed as a percentage of the bed area. If the area of a particular layer "
"is smaller than 'area_fill', then 'Below area fill threshold' parameters are used to determine the "
"layer separation (tearing) procedure. Otherwise 'Above area fill threshold' parameters are used.");
def->sidetext = L("%");
def->min = 0;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(50.));
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(35.));
def = this->add("relative_correction", coFloats);
def->label = L("Printer scaling correction");
@ -3993,6 +4030,7 @@ void PrintConfigDef::init_sla_params()
def->full_label = L("Printer absolute correction");
def->tooltip = L("Will inflate or deflate the sliced 2D polygons according "
"to the sign of the correction.");
def->sidetext = L("mm");
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0.0));
@ -4444,8 +4482,7 @@ void PrintConfigDef::init_sla_params()
"support_head_penetration", "branchingsupport_head_penetration",
"support_head_width", "branchingsupport_head_width",
"support_pillar_diameter", "branchingsupport_pillar_diameter",
"relative_correction_x", "relative_correction_y", "relative_correction_z",
"elefant_foot_compensation",
"elefant_foot_compensation", "absolute_correction",
// int
"support_points_density_relative"
}) {
@ -4467,6 +4504,186 @@ void PrintConfigDef::init_sla_params()
}
}
// SLA Materials "sub-presets" settings
void PrintConfigDef::init_sla_tilt_params()
{
ConfigOptionDef* def;
def = this->add("delay_before_exposure", coFloats);
def->full_label = L("Delay before exposure");
def->tooltip = L("Delay before exposure after previous layer separation.");
def->sidetext = L("s");
def->min = 0;
def->max = 30;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloats({ 3., 3.}));
def = this->add("delay_after_exposure", coFloats);
def->full_label = L("Delay after exposure");
def->tooltip = L("Delay after exposure before layer separation.");
def->sidetext = L("s");
def->min = 0;
def->max = 30;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloats({ 0., 0.}));
def = this->add("tower_hop_height", coInts);
def->full_label = L("Tower hop height");
def->tooltip = L("The height of the tower raise.");
def->sidetext = L("mm");
def->min = 0;
def->max = 100;
def->mode = comExpert;
def->set_default_value(new ConfigOptionInts({ 0, 0}));
def = this->add("tower_speed", coEnums);
def->full_label = L("Tower speed");
def->tooltip = L("Tower speed used for tower raise.");
def->mode = comExpert;
def->sidetext = L("mm/s");
def->set_enum<TowerSpeeds>({
{ "layer1", "1" },
{ "layer2", "2" },
{ "layer3", "3" },
{ "layer4", "4" },
{ "layer5", "5" },
{ "layer8", "8" },
{ "layer11", "11" },
{ "layer14", "14" },
{ "layer18", "18" },
{ "layer22", "22" },
{ "layer24", "24" },
});
def->set_default_value(new ConfigOptionEnums<TowerSpeeds>({ tsLayer22, tsLayer22 }));
const std::initializer_list<std::pair<std::string_view, std::string_view>> tilt_speeds_il = {
{ "move120", "120" },
{ "layer200", "200" },
{ "move300", "300" },
{ "layer400", "400" },
{ "layer600", "600" },
{ "layer800", "800" },
{ "layer1000", "1000" },
{ "layer1250", "1250" },
{ "layer1500", "1500" },
{ "layer1750", "1750" },
{ "layer2000", "2000" },
{ "layer2250", "2250" },
{ "move5120", "5120" },
{ "move8000", "8000" },
};
def = this->add("tilt_down_initial_speed", coEnums);
def->full_label = L("Tilt down initial speed");
def->tooltip = L("Tilt speed used for an initial portion of tilt down move.");
def->mode = comExpert;
def->sidetext = L("μ-steps/s");
def->set_enum<TiltSpeeds>(tilt_speeds_il);
def->set_default_value(new ConfigOptionEnums<TiltSpeeds>({ tsLayer1750, tsLayer1750 }));
def = this->add("tilt_down_finish_speed", coEnums);
def->full_label = L("Tilt down finish speed");
def->tooltip = L("Tilt speed used for the rest of the tilt down move.");
def->mode = comExpert;
def->sidetext = L("μ-steps/s");
def->set_enum<TiltSpeeds>(tilt_speeds_il);
def->set_default_value(new ConfigOptionEnums<TiltSpeeds>({ tsLayer1750, tsLayer1750 }));
def = this->add("tilt_up_initial_speed", coEnums);
def->full_label = L("Tilt up initial speed");
def->tooltip = L("Tilt speed used for an initial portion of tilt up move.");
def->mode = comExpert;
def->sidetext = L("μ-steps/s");
def->set_enum<TiltSpeeds>(tilt_speeds_il);
def->set_default_value(new ConfigOptionEnums<TiltSpeeds>({ tsMove8000, tsMove8000 }));
def = this->add("tilt_up_finish_speed", coEnums);
def->full_label = L("Tilt up finish speed");
def->tooltip = L("Tilt speed used for the rest of the tilt-up.");
def->mode = comExpert;
def->sidetext = L("μ-steps/s");
def->set_enum<TiltSpeeds>(tilt_speeds_il);
def->set_default_value(new ConfigOptionEnums<TiltSpeeds>({ tsLayer1750, tsLayer1750 }));
def = this->add("use_tilt", coBools);
def->full_label = L("Use tilt");
def->tooltip = L("If enabled, tilt is used for layer separation. Otherwise, all the parameters below are ignored.");
def->mode = comExpert;
def->set_default_value(new ConfigOptionBools({ true, true }));
def = this->add("tilt_down_offset_steps", coInts);
def->full_label = L("Tilt down offset steps");
def->tooltip = L("Number of steps to move down from the calibrated (horizontal) position with 'tilt_down_initial_speed'.");
def->sidetext = L("μ-steps");
def->min = 0;
def->max = 10000;
def->mode = comExpert;
def->set_default_value(new ConfigOptionInts({ 0, 0 }));
def = this->add("tilt_down_offset_delay", coFloats);
def->full_label = L("Tilt down offset delay");
def->tooltip = L("Delay after the tilt reaches 'tilt_down_offset_steps' position.");
def->sidetext = L("s");
def->min = 0;
def->max = 20;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloats({ 0., 0. }));
def = this->add("tilt_down_cycles", coInts);
def->full_label = L("Tilt down cycles");
def->tooltip = L("Number of cycles to split the rest of the tilt down move.");
def->min = 0;
def->max = 10;
def->mode = comExpert;
def->set_default_value(new ConfigOptionInts({ 1, 1 }));
def = this->add("tilt_down_delay", coFloats);
def->full_label = L("Tilt down delay");
def->tooltip = L("The delay between tilt-down cycles.");
def->sidetext = L("s");
def->min = 0;
def->max = 20;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloats({ 0., 0. }));
def = this->add("tilt_up_offset_steps", coInts);
def->full_label = L("Tilt up offset steps");
def->tooltip = L("Move tilt up to calibrated (horizontal) position minus this offset.");
def->sidetext = L("μ-steps");
def->min = 0;
def->max = 10000;
def->mode = comExpert;
def->set_default_value(new ConfigOptionInts({ 1200, 1200 }));
def = this->add("tilt_up_offset_delay", coFloats);
def->full_label = L("Tilt up offset delay");
def->tooltip = L("Delay after the tilt reaches 'tilt_up_offset_steps' position.");
def->sidetext = L("s");
def->min = 0;
def->max = 20;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloats({ 0., 0. }));
def = this->add("tilt_up_cycles", coInts);
def->full_label = L("Tilt up cycles");
def->tooltip = L("Number of cycles to split the rest of the tilt-up.");
def->min = 0;
def->max = 10;
def->mode = comExpert;
def->set_default_value(new ConfigOptionInts({ 1, 1 }));
def = this->add("tilt_up_delay", coFloats);
def->full_label = L("Tilt up delay");
def->tooltip = L("The delay between tilt-up cycles.");
def->sidetext = L("s");
def->min = 0;
def->max = 20;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloats({ 0., 0. }));
}
// Ignore the following obsolete configuration keys:
static std::set<std::string> PrintConfigDef_ignore = {
"clip_multipart_objects",
@ -4741,6 +4958,87 @@ void DynamicPrintConfig::normalize_fdm()
opt_wall_transition_length->value = std::max(opt_wall_transition_length->value, 0.001);
}
// Default values containe option pair of values (Below and Above) for each titl modes
// (Slow, Fast, HighViscosity and NoTilt) -> used for SL1S and other vendors printers
const std::map<std::string, ConfigOptionFloats> tilt_options_floats_defs =
{
{"delay_before_exposure", ConfigOptionFloats({ 3., 3., 0., 1., 3.5, 3.5, 0., 0. }) } ,
{"delay_after_exposure", ConfigOptionFloats({ 0., 0., 0., 0., 0., 0., 0., 0. }) } ,
{"tilt_down_offset_delay", ConfigOptionFloats({ 0., 0., 0., 0., 0., 0., 0., 0. }) } ,
{"tilt_down_delay", ConfigOptionFloats({ 0., 0., 0., 0.5, 0., 0., 0., 0. }) } ,
{"tilt_up_offset_delay", ConfigOptionFloats({ 0., 0., 0., 0., 0., 0., 0., 0. }) } ,
{"tilt_up_delay", ConfigOptionFloats({ 0., 0., 0., 0., 0., 0., 0., 0. }) } ,
};
const std::map<std::string, ConfigOptionInts> tilt_options_ints_defs =
{
{"tower_hop_height", ConfigOptionInts({ 0, 0, 0, 0, 5, 5, 0, 0 }) } ,
{"tilt_down_offset_steps", ConfigOptionInts({ 0, 0, 0, 0, 2200, 2200, 0, 0 }) } ,
{"tilt_down_cycles", ConfigOptionInts({ 1, 1, 1, 1, 1, 1, 0, 0 }) } ,
{"tilt_up_offset_steps", ConfigOptionInts({ 1200, 1200, 600, 600, 2200, 2200, 0, 0 }) } ,
{"tilt_up_cycles", ConfigOptionInts({ 1, 1, 1, 1, 1, 1, 0, 0 }) } ,
};
const std::map<std::string, ConfigOptionBools> tilt_options_bools_defs =
{
{"use_tilt", ConfigOptionBools({ true, true, true, true, true, true, false, false })} ,
};
const std::map<std::string, ConfigOptionEnums<TowerSpeeds>> tower_tilt_options_enums_defs =
{
{"tower_speed", ConfigOptionEnums<TowerSpeeds>({ tsLayer22, tsLayer22, tsLayer22, tsLayer22, tsLayer2, tsLayer2, tsLayer1, tsLayer1 })} ,
};
const std::map<std::string, ConfigOptionEnums<TiltSpeeds>> tilt_options_enums_defs =
{
{"tilt_down_initial_speed", ConfigOptionEnums<TiltSpeeds>({ tsLayer1750, tsLayer1750, tsLayer1750, tsLayer1750, tsLayer800, tsLayer800, tsMove120, tsMove120 }) } ,
{"tilt_down_finish_speed", ConfigOptionEnums<TiltSpeeds>({ tsLayer1750, tsLayer1750, tsMove8000, tsLayer1750, tsLayer1750, tsLayer1750, tsMove120, tsMove120 }) } ,
{"tilt_up_initial_speed", ConfigOptionEnums<TiltSpeeds>({ tsMove8000, tsMove8000, tsMove8000, tsMove8000, tsLayer1750, tsLayer1750, tsMove120, tsMove120 }) } ,
{"tilt_up_finish_speed", ConfigOptionEnums<TiltSpeeds>({ tsLayer1750, tsLayer1750, tsLayer1750, tsLayer1750, tsLayer800, tsLayer800, tsMove120, tsMove120 }) } ,
};
// Default values containe option pair of values (Below and Above) for each titl modes
// (Slow, Fast, HighViscosity and NoTilt) -> used for SL1 printer
const std::map<std::string, ConfigOptionFloats> tilt_options_floats_sl1_defs =
{
{"delay_before_exposure", ConfigOptionFloats({ 3., 3., 0., 1., 3.5, 3.5, 0., 0. }) } ,
{"delay_after_exposure", ConfigOptionFloats({ 0., 0., 0., 0., 0., 0., 0., 0. }) } ,
{"tilt_down_offset_delay", ConfigOptionFloats({ 1., 1., 0., 0., 0., 0., 0., 0. }) } ,
{"tilt_down_delay", ConfigOptionFloats({ 0., 0., 0., 0., 0., 0., 0., 0. }) } ,
{"tilt_up_offset_delay", ConfigOptionFloats({ 0., 0., 0., 0., 1., 1., 0., 0. }) } ,
{"tilt_up_delay", ConfigOptionFloats({ 0., 0., 0., 0., 0., 0., 0., 0. }) } ,
};
const std::map<std::string, ConfigOptionInts> tilt_options_ints_sl1_defs =
{
{"tower_hop_height", ConfigOptionInts({ 0, 0, 0, 0, 5, 5, 0, 0 }) } ,
{"tilt_down_offset_steps", ConfigOptionInts({ 650, 650, 0, 0, 2200, 2200, 0, 0 }) } ,
{"tilt_down_cycles", ConfigOptionInts({ 1, 1, 1, 1, 1, 1, 0, 0 }) } ,
{"tilt_up_offset_steps", ConfigOptionInts({ 400, 400, 400, 400, 2200, 2200, 0, 0 }) } ,
{"tilt_up_cycles", ConfigOptionInts({ 1, 1, 1, 1, 1, 1, 0, 0 }) } ,
};
const std::map<std::string, ConfigOptionBools> tilt_options_bools_sl1_defs =
{
{"use_tilt", ConfigOptionBools({ true, true, true, true, true, true, false, false })} ,
};
const std::map<std::string, ConfigOptionEnums<TowerSpeeds>> tower_tilt_options_enums_sl1_defs =
{
{"tower_speed", ConfigOptionEnums<TowerSpeeds>({ tsLayer22, tsLayer22, tsLayer22, tsLayer22, tsLayer2, tsLayer2, tsLayer1, tsLayer1 })} ,
};
const std::map<std::string, ConfigOptionEnums<TiltSpeeds>> tilt_options_enums_sl1_defs =
{
{"tilt_down_initial_speed", ConfigOptionEnums<TiltSpeeds>({ tsLayer400, tsLayer400, tsLayer400, tsLayer400, tsLayer600, tsLayer600, tsMove120, tsMove120 }) } ,
{"tilt_down_finish_speed", ConfigOptionEnums<TiltSpeeds>({ tsLayer1500, tsLayer1500, tsLayer1750, tsLayer1500, tsLayer1500, tsLayer1500, tsMove120, tsMove120 }) } ,
{"tilt_up_initial_speed", ConfigOptionEnums<TiltSpeeds>({ tsMove5120, tsMove5120, tsMove5120, tsMove5120, tsLayer1500, tsLayer1500, tsMove120, tsMove120 }) } ,
{"tilt_up_finish_speed", ConfigOptionEnums<TiltSpeeds>({ tsLayer400, tsLayer400, tsLayer400, tsLayer400, tsLayer600, tsLayer600, tsMove120, tsMove120 }) } ,
};
void handle_legacy_sla(DynamicPrintConfig &config)
{
for (std::string corr : {"relative_correction", "material_correction"}) {
@ -4761,6 +5059,66 @@ void handle_legacy_sla(DynamicPrintConfig &config)
}
}
}
// Load default tilt options in config in respect to the print speed, if config is loaded from old PS
if (config.has("material_print_speed") &&
!config.has("tilt_down_offset_delay") // Config from old PS doesn't contain any of tilt options, so check it
) {
int tilt_mode = config.option("material_print_speed")->getInt();
const bool is_sl1_model = config.opt_string("printer_model") == "SL1";
const std::map<std::string, ConfigOptionFloats> floats_defs = is_sl1_model ? tilt_options_floats_sl1_defs : tilt_options_floats_defs;
const std::map<std::string, ConfigOptionInts> ints_defs = is_sl1_model ? tilt_options_ints_sl1_defs : tilt_options_ints_defs;
const std::map<std::string, ConfigOptionBools> bools_defs = is_sl1_model ? tilt_options_bools_sl1_defs : tilt_options_bools_defs;
const std::map<std::string, ConfigOptionEnums<TowerSpeeds>> tower_enums_defs = is_sl1_model ? tower_tilt_options_enums_sl1_defs : tower_tilt_options_enums_defs;
const std::map<std::string, ConfigOptionEnums<TiltSpeeds>> tilt_enums_defs = is_sl1_model ? tilt_options_enums_sl1_defs : tilt_options_enums_defs;
for (const std::string& opt_key : tilt_options()) {
switch (config.def()->get(opt_key)->type) {
case coFloats: {
ConfigOptionFloats values = floats_defs.at(opt_key);
double val1 = values.get_at(2 * tilt_mode);
double val2 = values.get_at(2 * tilt_mode + 1);
config.set_key_value(opt_key, new ConfigOptionFloats({ val1, val2 }));
}
break;
case coInts: {
auto values = ints_defs.at(opt_key);
int val1 = values.get_at(2 * tilt_mode);
int val2 = values.get_at(2 * tilt_mode + 1);
config.set_key_value(opt_key, new ConfigOptionInts({ val1, val2 }));
}
break;
case coBools: {
auto values = bools_defs.at(opt_key);
bool val1 = values.get_at(2 * tilt_mode);
bool val2 = values.get_at(2 * tilt_mode + 1);
config.set_key_value(opt_key, new ConfigOptionBools({ val1, val2 }));
}
break;
case coEnums: {
int val1, val2;
if (opt_key == "tower_speed") {
auto values = tower_enums_defs.at(opt_key);
val1 = values.get_at(2 * tilt_mode);
val2 = values.get_at(2 * tilt_mode + 1);
}
else {
auto values = tilt_enums_defs.at(opt_key);
val1 = values.get_at(2 * tilt_mode);
val2 = values.get_at(2 * tilt_mode + 1);
}
config.set_key_value(opt_key, new ConfigOptionEnumsGeneric({ val1, val2 }));
}
break;
case coNone:
default:
break;
}
}
}
}
void DynamicPrintConfig::set_num_extruders(unsigned int num_extruders)

View File

@ -171,6 +171,37 @@ enum class GCodeThumbnailsFormat {
PNG, JPG, QOI
};
enum TowerSpeeds : int {
tsLayer1,
tsLayer2,
tsLayer3,
tsLayer4,
tsLayer5,
tsLayer8,
tsLayer11,
tsLayer14,
tsLayer18,
tsLayer22,
tsLayer24,
};
enum TiltSpeeds : int {
tsMove120,
tsLayer200,
tsMove300,
tsLayer400,
tsLayer600,
tsLayer800,
tsLayer1000,
tsLayer1250,
tsLayer1500,
tsLayer1750,
tsLayer2000,
tsLayer2250,
tsMove5120,
tsMove8000,
};
#define CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(NAME) \
template<> const t_config_enum_names& ConfigOptionEnum<NAME>::get_enum_names(); \
template<> const t_config_enum_values& ConfigOptionEnum<NAME>::get_enum_values();
@ -226,6 +257,7 @@ private:
void init_fff_params();
void init_extruder_option_keys();
void init_sla_params();
void init_sla_tilt_params();
void init_sla_support_params(const std::string &method_prefix);
std::vector<std::string> m_extruder_option_keys;
@ -305,6 +337,9 @@ public:
{ PrintConfigDef::handle_legacy_composite(*this); }
};
// This vector containes list of parameters for preview of tilt profiles
const std::vector<std::string>& tilt_options();
void handle_legacy_sla(DynamicPrintConfig &config);
class StaticPrintConfig : public StaticConfig
@ -1148,11 +1183,28 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloatNullable, material_ow_support_head_width))
((ConfigOptionFloatNullable, material_ow_branchingsupport_head_width))
((ConfigOptionIntNullable, material_ow_support_points_density_relative))
((ConfigOptionFloatNullable, material_ow_elefant_foot_compensation))
((ConfigOptionFloatNullable, material_ow_relative_correction_x))
((ConfigOptionFloatNullable, material_ow_relative_correction_y))
((ConfigOptionFloatNullable, material_ow_relative_correction_z))
((ConfigOptionFloatNullable, material_ow_absolute_correction))
((ConfigOptionFloat, area_fill))
//tilt params
((ConfigOptionFloats, delay_before_exposure))
((ConfigOptionFloats, delay_after_exposure))
((ConfigOptionInts, tower_hop_height))
((ConfigOptionEnums<TowerSpeeds>, tower_speed))
((ConfigOptionBools, use_tilt))
((ConfigOptionEnums<TiltSpeeds>, tilt_down_initial_speed))
((ConfigOptionInts, tilt_down_offset_steps))
((ConfigOptionFloats, tilt_down_offset_delay))
((ConfigOptionEnums<TiltSpeeds>, tilt_down_finish_speed))
((ConfigOptionInts, tilt_down_cycles))
((ConfigOptionFloats, tilt_down_delay))
((ConfigOptionEnums<TiltSpeeds>, tilt_up_initial_speed))
((ConfigOptionInts, tilt_up_offset_steps))
((ConfigOptionFloats, tilt_up_offset_delay))
((ConfigOptionEnums<TiltSpeeds>, tilt_up_finish_speed))
((ConfigOptionInts, tilt_up_cycles))
((ConfigOptionFloats, tilt_up_delay))
)
PRINT_CONFIG_CLASS_DEFINE(
@ -1179,13 +1231,14 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, fast_tilt_time))
((ConfigOptionFloat, slow_tilt_time))
((ConfigOptionFloat, high_viscosity_tilt_time))
((ConfigOptionFloat, area_fill))
// ((ConfigOptionFloat, area_fill))
((ConfigOptionFloat, min_exposure_time))
((ConfigOptionFloat, max_exposure_time))
((ConfigOptionFloat, min_initial_exposure_time))
((ConfigOptionFloat, max_initial_exposure_time))
((ConfigOptionString, sla_archive_format))
((ConfigOptionFloat, sla_output_precision))
((ConfigOptionString, printer_model))
)
PRINT_CONFIG_CLASS_DERIVED_DEFINE0(

View File

@ -219,10 +219,8 @@ static t_config_option_keys print_config_diffs(const StaticPrintConfig &curr
"branchingsupport_head_width"sv,
"branchingsupport_pillar_diameter"sv,
"support_points_density_relative"sv,
"relative_correction_x"sv,
"relative_correction_y"sv,
"relative_correction_z"sv,
"elefant_foot_compensation"sv,
"absolute_correction"sv,
};
static constexpr auto material_ow_prefix = "material_ow_";
@ -685,6 +683,12 @@ std::string SLAPrint::validate(std::vector<std::string>*) const
}
}
if ((!m_material_config.use_tilt.get_at(0) && m_material_config.tower_hop_height.get_at(0) == 0)
|| (!m_material_config.use_tilt.get_at(1) && m_material_config.tower_hop_height.get_at(1) == 0))
return _u8L("Disabling the 'Use tilt' function causes the object to separate away from the film in the "
"vertical direction only. Therefore, it is necessary to set the 'Tower hop height' parameter "
"to reasonable value. The recommended value is 5 mm.");
return "";
}
@ -858,7 +862,26 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_opt
"display_mirror_y"sv,
"display_orientation"sv,
"sla_archive_format"sv,
"sla_output_precision"sv
"sla_output_precision"sv,
// tilt params
"delay_before_exposure"sv,
"delay_after_exposure"sv,
"tower_hop_height"sv,
"tower_speed"sv,
"use_tilt"sv,
"tilt_down_initial_speed"sv,
"tilt_down_offset_steps"sv,
"tilt_down_offset_delay"sv,
"tilt_down_finish_speed"sv,
"tilt_down_cycles"sv,
"tilt_down_delay"sv,
"tilt_up_initial_speed"sv,
"tilt_up_offset_steps"sv,
"tilt_up_offset_delay"sv,
"tilt_up_finish_speed"sv,
"tilt_up_cycles"sv,
"tilt_up_delay"sv,
"area_fill"sv,
};
static StaticSet steps_ignore = {
@ -869,7 +892,6 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_opt
"fast_tilt_time"sv,
"slow_tilt_time"sv,
"high_viscosity_tilt_time"sv,
"area_fill"sv,
"bottle_cost"sv,
"bottle_volume"sv,
"bottle_weight"sv,
@ -884,9 +906,8 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_opt
"material_ow_branchingsupport_head_width"sv,
"material_ow_elefant_foot_compensation"sv,
"material_ow_support_points_density_relative"sv,
"material_ow_relative_correction_x"sv,
"material_ow_relative_correction_y"sv,
"material_ow_relative_correction_z"sv
"material_ow_absolute_correction"sv,
"printer_model"sv,
};
std::vector<SLAPrintStep> steps;

View File

@ -406,13 +406,15 @@ struct SLAPrintStatistics
{
SLAPrintStatistics() { clear(); }
double estimated_print_time;
double estimated_print_time_tolerance;
double objects_used_material;
double support_used_material;
size_t slow_layers_count;
size_t fast_layers_count;
double total_cost;
double total_weight;
std::vector<double> layers_times;
std::vector<double> layers_times_running_total;
std::vector<double> layers_areas;
// Config with the filled in print statistics.
DynamicConfig config() const;
@ -423,13 +425,15 @@ struct SLAPrintStatistics
void clear() {
estimated_print_time = 0.;
estimated_print_time_tolerance = 0.;
objects_used_material = 0.;
support_used_material = 0.;
slow_layers_count = 0;
fast_layers_count = 0;
total_cost = 0.;
total_weight = 0.;
layers_times.clear();
layers_times_running_total.clear();
layers_areas.clear();
}
};

View File

@ -911,6 +911,188 @@ void SLAPrint::Steps::initialize_printer_input()
}
}
static int Ms(int s)
{
return s;
}
// constant values from FW
int tiltHeight = 4959; //nm
int tower_microstep_size_nm = 250000;
int first_extra_slow_layers = 3;
int refresh_delay_ms = 0;
static int nm_to_tower_microsteps(int nm) {
// add implementation
return nm / tower_microstep_size_nm;
}
static int count_move_time(const std::string& axis_name, double length, int steprate)
{
if (length < 0 || steprate < 0)
return 0;
// sla - fw checks every 0.1 s if axis is still moving.See: Axis._wait_to_stop_delay.Additional 0.021 s is
// measured average delay of the system.Thus, the axis movement time is always quantized by this value.
double delay = 0.121;
// Both axes use linear ramp movements. This factor compensates the tilt acceleration and deceleration time.
double tilt_comp_factor = 0.1;
// Both axes use linear ramp movements.This factor compensates the tower acceleration and deceleration time.
int tower_comp_factor = 20000;
int l = int(length);
return axis_name == "tower" ? Ms((int(l / (steprate * delay) + (steprate + l) / tower_comp_factor) + 1) * (delay * 1000)) :
Ms((int(l / (steprate * delay) + tilt_comp_factor) + 1) * (delay * 1000));
}
struct ExposureProfile {
// map of internal TowerSpeeds to maximum_steprates (usteps/s)
// this values was provided in default_tower_moving_profiles.json by SLA-team
std::map<TowerSpeeds, int> tower_speeds = {
{ tsLayer1 , 800 },
{ tsLayer2 , 1600 },
{ tsLayer3 , 2400 },
{ tsLayer4 , 3200 },
{ tsLayer5 , 4000 },
{ tsLayer8 , 6400 },
{ tsLayer11, 8800 },
{ tsLayer14, 11200 },
{ tsLayer18, 14400 },
{ tsLayer22, 17600 },
{ tsLayer24, 19200 },
};
// map of internal TiltSpeeds to maximum_steprates (usteps/s)
// this values was provided in default_tilt_moving_profiles.json by SLA-team
std::map<TiltSpeeds, int> tilt_speeds = {
{ tsMove120 , 120 },
{ tsLayer200 , 200 },
{ tsMove300 , 300 },
{ tsLayer400 , 400 },
{ tsLayer600 , 600 },
{ tsLayer800 , 800 },
{ tsLayer1000, 1000 },
{ tsLayer1250, 1250 },
{ tsLayer1500, 1500 },
{ tsLayer1750, 1750 },
{ tsLayer2000, 2000 },
{ tsLayer2250, 2250 },
{ tsMove5120 , 5120 },
{ tsMove8000 , 8000 },
};
int delay_before_exposure_ms { 0 };
int delay_after_exposure_ms { 0 };
int tilt_down_offset_delay_ms { 0 };
int tilt_down_delay_ms { 0 };
int tilt_up_offset_delay_ms { 0 };
int tilt_up_delay_ms { 0 };
int tower_hop_height_nm { 0 };
int tilt_down_offset_steps { 0 };
int tilt_down_cycles { 0 };
int tilt_up_offset_steps { 0 };
int tilt_up_cycles { 0 };
bool use_tilt { true };
int tower_speed { 0 };
int tilt_down_initial_speed { 0 };
int tilt_down_finish_speed { 0 };
int tilt_up_initial_speed { 0 };
int tilt_up_finish_speed { 0 };
ExposureProfile() {}
ExposureProfile(const SLAMaterialConfig& config, int opt_id)
{
delay_before_exposure_ms = int(1000 * config.delay_before_exposure.get_at(opt_id));
delay_after_exposure_ms = int(1000 * config.delay_after_exposure.get_at(opt_id));
tilt_down_offset_delay_ms = int(1000 * config.tilt_down_offset_delay.get_at(opt_id));
tilt_down_delay_ms = int(1000 * config.tilt_down_delay.get_at(opt_id));
tilt_up_offset_delay_ms = int(1000 * config.tilt_up_offset_delay.get_at(opt_id));
tilt_up_delay_ms = int(1000 * config.tilt_up_delay.get_at(opt_id));
tower_hop_height_nm = config.tower_hop_height.get_at(opt_id) * 1000000;
tilt_down_offset_steps = config.tilt_down_offset_steps.get_at(opt_id);
tilt_down_cycles = config.tilt_down_cycles.get_at(opt_id);
tilt_up_offset_steps = config.tilt_up_offset_steps.get_at(opt_id);
tilt_up_cycles = config.tilt_up_cycles.get_at(opt_id);
use_tilt = config.use_tilt.get_at(opt_id);
tower_speed = tower_speeds.at(static_cast<TowerSpeeds>(config.tower_speed.getInts()[opt_id]));
tilt_down_initial_speed = tilt_speeds.at(static_cast<TiltSpeeds>(config.tilt_down_initial_speed.getInts()[opt_id]));
tilt_down_finish_speed = tilt_speeds.at(static_cast<TiltSpeeds>(config.tilt_down_finish_speed.getInts()[opt_id]));
tilt_up_initial_speed = tilt_speeds.at(static_cast<TiltSpeeds>(config.tilt_up_initial_speed.getInts()[opt_id]));
tilt_up_finish_speed = tilt_speeds.at(static_cast<TiltSpeeds>(config.tilt_up_finish_speed.getInts()[opt_id]));
}
};
static int layer_peel_move_time(int layer_height_nm, ExposureProfile p)
{
int profile_change_delay = Ms(20); // propagation delay of sending profile change command to MC
int sleep_delay = Ms(2); // average delay of the Linux system sleep function
int tilt = Ms(0);
if (p.use_tilt) {
tilt += profile_change_delay;
// initial down movement
tilt += count_move_time(
"tilt",
p.tilt_down_offset_steps,
p.tilt_down_initial_speed);
// initial down delay
tilt += p.tilt_down_offset_delay_ms + sleep_delay;
// profile change delay if down finish profile is different from down initial
tilt += profile_change_delay;
// cycle down movement
tilt += p.tilt_down_cycles * count_move_time(
"tilt",
int((tiltHeight - p.tilt_down_offset_steps) / p.tilt_down_cycles),
p.tilt_down_finish_speed);
// cycle down delay
tilt += p.tilt_down_cycles * (p.tilt_down_delay_ms + sleep_delay);
// profile change delay if up initial profile is different from down finish
tilt += profile_change_delay;
// initial up movement
tilt += count_move_time(
"tilt",
tiltHeight - p.tilt_up_offset_steps,
p.tilt_up_initial_speed);
// initial up delay
tilt += p.tilt_up_offset_delay_ms + sleep_delay;
// profile change delay if up initial profile is different from down finish
tilt += profile_change_delay;
// finish up movement
tilt += p.tilt_up_cycles * count_move_time(
"tilt",
int(p.tilt_up_offset_steps / p.tilt_up_cycles),
p.tilt_up_finish_speed);
// cycle down delay
tilt += p.tilt_up_cycles * (p.tilt_up_delay_ms + sleep_delay);
}
int tower = Ms(0);
if (p.tower_hop_height_nm > 0) {
tower += count_move_time(
"tower",
nm_to_tower_microsteps(int(p.tower_hop_height_nm) + layer_height_nm),
p.tower_speed);
tower += count_move_time(
"tower",
nm_to_tower_microsteps(int(p.tower_hop_height_nm)),
p.tower_speed);
tower += profile_change_delay;
}
else {
tower += count_move_time(
"tower",
nm_to_tower_microsteps(layer_height_nm),
p.tower_speed);
tower += profile_change_delay;
}
return int(tilt + tower);
}
// Merging the slices from all the print objects into one slice grid and
// calculating print statistics from the merge result.
void SLAPrint::Steps::merge_slices_and_eval_stats() {
@ -924,7 +1106,7 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
print_statistics.clear();
const double area_fill = printer_config.area_fill.getFloat()*0.01;// 0.5 (50%);
const double area_fill = material_config.area_fill.getFloat()*0.01;// 0.5 (50%);
const double fast_tilt = printer_config.fast_tilt_time.getFloat();// 5.0;
const double slow_tilt = printer_config.slow_tilt_time.getFloat();// 8.0;
const double hv_tilt = printer_config.high_viscosity_tilt_time.getFloat();// 10.0;
@ -934,34 +1116,29 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
const int fade_layers_cnt = m_print->m_default_object_config.faded_layers.getInt();// 10 // [3;20]
ExposureProfile below(material_config, 0);
ExposureProfile above(material_config, 1);
const int first_slow_layers = fade_layers_cnt + first_extra_slow_layers;
const std::string printer_model = printer_config.printer_model;
const bool is_prusa_print = printer_model == "SL1" || printer_model == "SL1S" || printer_model == "M1";
const auto width = scaled<double>(printer_config.display_width.getFloat());
const auto height = scaled<double>(printer_config.display_height.getFloat());
const double display_area = width*height;
double supports_volume(0.0);
double models_volume(0.0);
double estim_time(0.0);
std::vector<double> layers_times;
layers_times.reserve(printer_input.size());
size_t slow_layers = 0;
size_t fast_layers = 0;
std::vector<std::tuple<double, double, bool, double, double>> layers_info; // time, area, is_fast, models_volume, supports_volume
layers_info.resize(printer_input.size());
const double delta_fade_time = (init_exp_time - exp_time) / (fade_layers_cnt + 1);
double fade_layer_time = init_exp_time;
execution::SpinningMutex<ExecutionTBB> mutex;
using Lock = std::lock_guard<decltype(mutex)>;
// Going to parallel:
auto printlayerfn = [this,
// functions and read only vars
area_fill, display_area, exp_time, init_exp_time, fast_tilt, slow_tilt, hv_tilt, material_config, delta_fade_time,
area_fill, display_area, exp_time, init_exp_time, fast_tilt, slow_tilt, hv_tilt, material_config, delta_fade_time, is_prusa_print, first_slow_layers, below, above,
// write vars
&mutex, &models_volume, &supports_volume, &estim_time, &slow_layers,
&fast_layers, &fade_layer_time, &layers_times](size_t sliced_layer_cnt)
&layers_info](size_t sliced_layer_cnt)
{
PrintLayer &layer = m_print->m_printer_input[sliced_layer_cnt];
@ -1011,9 +1188,7 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
for (const ExPolygon& polygon : model_polygons)
layer_model_area += area(polygon);
if (layer_model_area < 0 || layer_model_area > 0) {
Lock lck(mutex); models_volume += layer_model_area * l_height;
}
const double models_volume = (layer_model_area < 0 || layer_model_area > 0) ? layer_model_area * l_height : 0.;
if(!supports_polygons.empty()) {
if(model_polygons.empty()) supports_polygons = union_ex(supports_polygons);
@ -1025,9 +1200,8 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
for (const ExPolygon& polygon : supports_polygons)
layer_support_area += area(polygon);
if (layer_support_area < 0 || layer_support_area > 0) {
Lock lck(mutex); supports_volume += layer_support_area * l_height;
}
const double supports_volume = (layer_support_area < 0 || layer_support_area > 0) ? layer_support_area * l_height : 0.;
const double layer_area = layer_model_area + layer_support_area;
// Here we can save the expensively calculated polygons for printing
ExPolygons trslices;
@ -1037,34 +1211,32 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
layer.transformed_slices(union_ex(trslices));
// Calculation of the slow and fast layers to the future controlling those values on FW
// Calculation of the printing time
// + Calculation of the slow and fast layers to the future controlling those values on FW
double layer_times = 0.0;
bool is_fast_layer = false;
const bool is_fast_layer = (layer_model_area + layer_support_area) <= display_area*area_fill;
const double tilt_time = material_config.material_print_speed == slamsSlow ? slow_tilt :
material_config.material_print_speed == slamsHighViscosity ? hv_tilt :
is_fast_layer ? fast_tilt : slow_tilt;
if (is_prusa_print) {
is_fast_layer = int(sliced_layer_cnt) < first_slow_layers || layer_area <= display_area * area_fill;
const int l_height_nm = 1000000 * l_height;
{ Lock lck(mutex);
if (is_fast_layer)
fast_layers++;
else
slow_layers++;
layer_times = layer_peel_move_time(l_height_nm, is_fast_layer ? below : above) +
(is_fast_layer ? below : above).delay_before_exposure_ms +
(is_fast_layer ? below : above).delay_after_exposure_ms +
refresh_delay_ms * 5 + // ~ 5x frame display wait
124; // Magical constant to compensate remaining computation delay in exposure thread
// Calculation of the printing time
layer_times *= 0.001; // All before calculations are made in ms, but we need it in s
}
else {
is_fast_layer = layer_area <= display_area*area_fill;
const double tilt_time = material_config.material_print_speed == slamsSlow ? slow_tilt :
material_config.material_print_speed == slamsHighViscosity ? hv_tilt :
is_fast_layer ? fast_tilt : slow_tilt;
double layer_times = 0.0;
if (sliced_layer_cnt < 3)
layer_times += init_exp_time;
else if (fade_layer_time > exp_time) {
fade_layer_time -= delta_fade_time;
layer_times += fade_layer_time;
}
else
layer_times += exp_time;
layer_times += tilt_time;
//// Per layer times (magical constants cuclulated from FW)
static double exposure_safe_delay_before{ 3.0 };
static double exposure_high_viscosity_delay_before{ 3.5 };
static double exposure_slow_move_delay_before{ 1.0 };
@ -1081,33 +1253,41 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
l_height * 5 // tower move
+ 120 / 1000 // Magical constant to compensate remaining computation delay in exposure thread
);
layers_times.push_back(layer_times);
estim_time += layer_times;
}
// We are done with tilt time, but we haven't added the exposure time yet.
layer_times += std::max(exp_time, init_exp_time - sliced_layer_cnt * delta_fade_time);
// Collect values for this layer.
layers_info[sliced_layer_cnt] = std::make_tuple(layer_times, layer_area * SCALING_FACTOR * SCALING_FACTOR, is_fast_layer, models_volume, supports_volume);
};
// sequential version for debugging:
// for(size_t i = 0; i < m_printer_input.size(); ++i) printlayerfn(i);
// for(size_t i = 0; i < printer_input.size(); ++i) printlayerfn(i);
execution::for_each(ex_tbb, size_t(0), printer_input.size(), printlayerfn,
execution::max_concurrency(ex_tbb));
auto SCALING2 = SCALING_FACTOR * SCALING_FACTOR;
print_statistics.support_used_material = supports_volume * SCALING2;
print_statistics.objects_used_material = models_volume * SCALING2;
print_statistics.clear();
// Estimated printing time
// A layers count o the highest object
if (printer_input.size() == 0)
print_statistics.estimated_print_time = NaNd;
else {
print_statistics.estimated_print_time = estim_time;
print_statistics.layers_times = layers_times;
size_t i=0;
for (const auto& [time, area, is_fast, models_volume, supports_volume] : layers_info) {
print_statistics.fast_layers_count += int(is_fast);
print_statistics.slow_layers_count += int(! is_fast);
print_statistics.layers_areas.emplace_back(area);
print_statistics.estimated_print_time += time;
print_statistics.layers_times_running_total.emplace_back(time + (i==0 ? 0. : print_statistics.layers_times_running_total[i-1]));
print_statistics.objects_used_material += models_volume * SCALING_FACTOR * SCALING_FACTOR;
print_statistics.support_used_material += supports_volume * SCALING_FACTOR * SCALING_FACTOR;
++i;
}
if (is_prusa_print)
// For our SLA printers, we add an error of the estimate:
print_statistics.estimated_print_time_tolerance = 0.03 * print_statistics.estimated_print_time;
}
print_statistics.fast_layers_count = fast_layers;
print_statistics.slow_layers_count = slow_layers;
report_status(-2, "", SlicingStatus::RELOAD_SLA_PREVIEW);
}

View File

@ -117,8 +117,7 @@ void DSForLayers::SetLayersTimes(const std::vector<double>& layers_times)
{
m_ticks.is_wipe_tower = false;
m_layers_times = layers_times;
for (size_t i = 1; i < m_layers_times.size(); i++)
m_layers_times[i] += m_layers_times[i - 1];
std::copy(layers_times.begin(), layers_times.end(), m_layers_times.begin());
}
void DSForLayers::SetDrawMode(bool is_sla_print, bool is_sequential_print)

View File

@ -1156,6 +1156,10 @@ void Choice::set_selection()
field->SetSelection(m_opt.default_value->getInt());
break;
}
case coEnums:{
field->SetSelection(m_opt.default_value->getInts()[m_opt_idx]);
break;
}
case coFloat:
case coPercent: {
double val = m_opt.default_value->getFloat();
@ -1243,7 +1247,8 @@ void Choice::set_value(const boost::any& value, bool change_event)
break;
}
case coEnum: {
case coEnum:
case coEnums: {
auto val = m_opt.enum_def->enum_to_index(boost::any_cast<int>(value));
assert(val.has_value());
field->SetSelection(val.has_value() ? *val : 0);
@ -1308,7 +1313,7 @@ boost::any& Choice::get_value()
if (m_opt_id == rp_option)
return m_value = boost::any(ret_str);
if (m_opt.type == coEnum)
if (m_opt.type == coEnum || m_opt.type == coEnums)
// Closed enum: The combo box item index returned by the field must be convertible to an enum value.
m_value = m_opt.enum_def->index_to_enum(field->GetSelection());
else if (m_opt.gui_type == ConfigOptionDef::GUIType::f_enum_open || m_opt.gui_type == ConfigOptionDef::GUIType::i_enum_open) {

View File

@ -6250,6 +6250,40 @@ void GLCanvas3D::_render_camera_target()
}
#endif // ENABLE_SHOW_CAMERA_TARGET
static void render_sla_layer_legend(const SLAPrint& print, int layer_idx, int cnv_width)
{
const std::vector<double>& areas = print.print_statistics().layers_areas;
const std::vector<double>& times = print.print_statistics().layers_times_running_total;
const double display_area = print.printer_config().display_height * print.printer_config().display_width;
if (layer_idx >= 0 && layer_idx < int(areas.size())) {
const double area = areas[layer_idx];
const double time = times[layer_idx] - (layer_idx == 0 ? 0. : times[layer_idx-1]);
const double time_until_layer = times[layer_idx];
ImGuiWrapper& imgui = *wxGetApp().imgui();
ImGuiPureWrap::set_next_window_pos(float(cnv_width) - imgui.get_style_scaling() * 5.f, 5.f, ImGuiCond_Always, 1.0f, 0.0f);
ImGui::SetNextWindowBgAlpha(0.6f);
ImGuiPureWrap::begin(_u8L("Layer statistics"), ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoFocusOnAppearing);
ImGui::Text("%s", GUI::format(_u8L("Layer area: %1% mm²"), int(0.1 + std::round(area))).c_str());
int area_percent_int = int(std::round(100. * area/display_area));
ImGui::Text("%s", GUI::format(_u8L("Area fill: %1% %%"), area_percent_int == 0 ? "<1" : std::to_string(area_percent_int)).c_str());
ImGui::Separator();
ImGui::Text("%s", GUI::format(_u8L("Layer time: %1%"), get_time_dhms(time)).c_str());
std::string buffer_str = _u8L("Time since start: %1%");
ImGui::Text("%s", GUI::format(buffer_str, get_time_dhms(time_until_layer)).c_str());
// The dummy control below uses the assumption that the total time string will be the longest
// and forces the width of the window large enough so it does not resize depending on the current value.
ImGui::Dummy(ImVec2(ImGui::CalcTextSize(GUI::format(buffer_str, get_time_dhms(82799)).c_str()).x, 0.));
ImGuiPureWrap::end();
}
}
void GLCanvas3D::_render_sla_slices()
{
if (!m_use_clipping_planes || current_printer_technology() != ptSLA)
@ -6261,6 +6295,13 @@ void GLCanvas3D::_render_sla_slices()
// nothing to render, return
return;
if (print->finished()) {
double slider_width = 0.;
if (const Preview* preview = dynamic_cast<Preview*>(m_canvas->GetParent()))
slider_width = preview->get_layers_slider_width();
render_sla_layer_legend(*print, m_layer_slider_index, get_canvas_size().get_width() - slider_width);
}
double clip_min_z = -m_clipping_planes[0].get_data()[3];
double clip_max_z = m_clipping_planes[1].get_data()[3];
for (unsigned int i = 0; i < (unsigned int)print_objects.size(); ++i) {

View File

@ -501,6 +501,7 @@ private:
ClippingPlane m_camera_clipping_plane;
bool m_use_clipping_planes;
std::array<SlaCap, 2> m_sla_caps;
int m_layer_slider_index = -1;
std::string m_sidebar_field;
// when true renders an extra frame by not resetting m_dirty to false
// see request_extra_frame()
@ -763,6 +764,8 @@ public:
void bed_shape_changed();
void set_layer_slider_index(int i) { m_layer_slider_index = i; }
void set_clipping_plane(unsigned int id, const ClippingPlane& plane) {
if (id < 2) {
m_clipping_planes[id] = plane;

View File

@ -1383,7 +1383,7 @@ bool GUI_App::on_init_inner()
mainframe->select_tab(size_t(0));
sidebar().obj_list()->init_objects(); // propagate model objects to object list
// update_mode(); // !!! do that later
update_mode(); // mode sizer doesn't exist anymore, so we came update mode here, before load_current_presets
SetTopWindow(mainframe);
plater_->init_notification_manager();

View File

@ -328,14 +328,14 @@ void Preview::render_sliders(GLCanvas3D& canvas)
m_moves_slider->Render(canvas_width, canvas_height, extra_scale);
}
float Preview::get_moves_slider_height()
float Preview::get_moves_slider_height() const
{
if (m_moves_slider && m_moves_slider->IsShown())
return m_moves_slider->GetHeight();
return 0.0f;
}
float Preview::get_layers_slider_width()
float Preview::get_layers_slider_width() const
{
if (m_layers_slider && m_layers_slider->IsShown())
return m_layers_slider->GetWidth();
@ -629,7 +629,7 @@ void Preview::update_layers_slider(const std::vector<double>& layers_z, bool kee
bool sequential_print = wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_bool("complete_objects");
m_layers_slider->SetDrawMode(sla_print_technology, sequential_print);
if (sla_print_technology)
m_layers_slider->SetLayersTimes(plater->sla_print().print_statistics().layers_times);
m_layers_slider->SetLayersTimes(plater->sla_print().print_statistics().layers_times_running_total);
else
m_layers_slider->SetLayersTimes(m_canvas->get_gcode_layers_times_cache(), m_gcode_result->print_statistics.modes.front().time);
@ -1037,6 +1037,7 @@ void Preview::on_layers_slider_scroll_changed()
else if (tech == ptSLA) {
m_canvas->set_clipping_plane(0, ClippingPlane(Vec3d::UnitZ(), -m_layers_slider->GetLowerValue()));
m_canvas->set_clipping_plane(1, ClippingPlane(-Vec3d::UnitZ(), m_layers_slider->GetHigherValue()));
m_canvas->set_layer_slider_index(m_layers_slider->GetHigherPos());
m_canvas->render();
}
}

View File

@ -136,8 +136,8 @@ public:
void msw_rescale();
void render_sliders(GLCanvas3D& canvas);
float get_layers_slider_width();
float get_moves_slider_height();
float get_layers_slider_width() const;
float get_moves_slider_height() const;
bool is_loaded() const { return m_loaded; }

View File

@ -80,7 +80,8 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
m_fields.emplace(id, SpinCtrl::Create<SpinCtrl>(this->ctrl_parent(), opt, id));
break;
case coEnum:
m_fields.emplace(id, Choice::Create<Choice>(this->ctrl_parent(), opt, id));
case coEnums:
m_fields.emplace(id, Choice::Create<Choice>(this->ctrl_parent(), opt, id));
break;
case coPoints:
m_fields.emplace(id, PointCtrl::Create<PointCtrl>(this->ctrl_parent(), opt, id));
@ -239,6 +240,10 @@ void OptionsGroup::change_opt_value(DynamicPrintConfig& config, const t_config_o
config.set_key_value(opt_key, opt);
}
break;
case coEnums: {
ConfigOptionEnumsGeneric* vec_new = new ConfigOptionEnumsGeneric(1, boost::any_cast<int>(value));;
config.option<ConfigOptionEnumsGeneric>(opt_key)->set_at(vec_new, opt_index, 0);
break; }
case coPoints: {
if (opt_key == "bed_shape") {
config.option<ConfigOptionPoints>(opt_key)->values = boost::any_cast<std::vector<Vec2d>>(value);
@ -816,7 +821,7 @@ void ConfigOptionsGroup::Hide()
void ConfigOptionsGroup::Show(const bool show)
{
sizer->ShowItems(show);
if (sizer) sizer->ShowItems(show);
#if 0//#ifdef __WXGTK__
m_panel->Show(show);
m_grid_sizer->Show(show);
@ -1101,6 +1106,9 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config
case coEnum:
ret = config.option(opt_key)->getInt();
break;
case coEnums:
ret = config.option(opt_key)->getInts()[idx];
break;
case coPoints:
if (opt_key == "bed_shape")
ret = config.option<ConfigOptionPoints>(opt_key)->values;

View File

@ -99,8 +99,11 @@ void OptionsSearcher::append_options(DynamicPrintConfig* config, Preset::Type ty
wxString suffix;
wxString suffix_local;
if (gc.category == "Machine limits") {
suffix = id == 1 ? L("Stealth") : L("Normal");
if (gc.category == "Machine limits" || gc.category == "Material printing profile") {
if (gc.category == "Machine limits")
suffix = id == 1 ? L("Stealth") : L("Normal");
else
suffix = id == 1 ? L("Above") : L("Below");
suffix_local = " " + _(suffix);
suffix = " " + suffix;
}
@ -124,7 +127,7 @@ void OptionsSearcher::append_options(DynamicPrintConfig* config, Preset::Type ty
int cnt = 0;
if ( type != Preset::TYPE_FILAMENT && type != Preset::TYPE_SLA_MATERIAL && !PresetCollection::is_independent_from_extruder_number_option(opt_key) )
if ( type != Preset::TYPE_FILAMENT && !PresetCollection::is_independent_from_extruder_number_option(opt_key))
switch (config->option(opt_key)->type())
{
case coInts: change_opt_key<ConfigOptionInts >(opt_key, config, cnt); break;
@ -134,6 +137,8 @@ void OptionsSearcher::append_options(DynamicPrintConfig* config, Preset::Type ty
case coPercents:change_opt_key<ConfigOptionPercents >(opt_key, config, cnt); break;
case coPoints: change_opt_key<ConfigOptionPoints >(opt_key, config, cnt); break;
case coFloatsOrPercents: change_opt_key<ConfigOptionFloatsOrPercents >(opt_key, config, cnt); break;
case coEnums: change_opt_key<ConfigOptionEnumsGeneric>(opt_key, config, cnt); break;
default: break;
}

View File

@ -937,7 +937,13 @@ void Sidebar::update_sliced_info_sizer()
}
m_sliced_info->SetTextAndShow(siCost, str_total_cost, "Cost");
wxString t_est = std::isnan(ps.estimated_print_time) ? "N/A" : from_u8(short_time_ui(get_time_dhms(float(ps.estimated_print_time))));
wxString t_est = "N/A";
if (! std::isnan(ps.estimated_print_time)) {
t_est = from_u8(short_time_ui(get_time_dhms(float(ps.estimated_print_time))));
if (ps.estimated_print_time_tolerance > 0.)
t_est += from_u8(" \u00B1 ") + from_u8(short_time_ui(get_time_dhms(float(ps.estimated_print_time_tolerance))));
}
m_sliced_info->SetTextAndShow(siEstimatedTime, t_est, _L("Estimated printing time") + ":");
m_plater->get_notification_manager()->set_slicing_complete_print_time(_u8L("Estimated printing time") + ": " + into_u8(t_est), m_plater->is_sidebar_collapsed());

View File

@ -669,7 +669,7 @@ void Tab::init_options_list()
m_options_list.clear();
for (const std::string& opt_key : m_config->keys())
emplace_option(opt_key, m_type != Preset::TYPE_FILAMENT && m_type != Preset::TYPE_SLA_MATERIAL && !PresetCollection::is_independent_from_extruder_number_option(opt_key));
emplace_option(opt_key, m_type != Preset::TYPE_FILAMENT && !PresetCollection::is_independent_from_extruder_number_option(opt_key));
}
template<class T>
@ -692,6 +692,7 @@ void Tab::emplace_option(const std::string& opt_key, bool respect_vec_values/* =
case coPercents:add_correct_opts_to_options_list<ConfigOptionPercents >(opt_key, m_options_list, this, m_opt_status_value); break;
case coPoints: add_correct_opts_to_options_list<ConfigOptionPoints >(opt_key, m_options_list, this, m_opt_status_value); break;
case coFloatsOrPercents: add_correct_opts_to_options_list<ConfigOptionFloatsOrPercents >(opt_key, m_options_list, this, m_opt_status_value); break;
case coEnums: add_correct_opts_to_options_list<ConfigOptionEnumsGeneric>(opt_key, m_options_list, this, m_opt_status_value); break;
default: m_options_list.emplace(opt_key, m_opt_status_value); break;
}
}
@ -906,6 +907,7 @@ void Tab::update_mode()
m_mode = wxGetApp().get_mode();
update_visibility();
update_sla_prusa_specific_visibility();
update_changed_tree_ui();
}
@ -2937,7 +2939,7 @@ void TabPrinter::build_sla()
line.append_option(optgroup->get_option("slow_tilt_time"));
line.append_option(optgroup->get_option("high_viscosity_tilt_time"));
optgroup->append_line(line);
optgroup->append_single_option_line("area_fill");
// optgroup->append_single_option_line("area_fill");
optgroup = page->new_optgroup(L("Corrections"));
line = Line{ m_config->def()->get("relative_correction")->full_label, "" };
@ -3022,6 +3024,29 @@ void TabPrinter::append_option_line(ConfigOptionsGroupShp optgroup, const std::s
optgroup->append_line(line);
}
// Legend for OptionsGroups column's name tooltip
static void create_legend(Slic3r::GUI::PageShp page, const std::vector<std::pair<std::string, std::string>>& columns, ConfigOptionMode mode, bool is_wider = false)
{
auto optgroup = page->new_optgroup("");
auto line = Line{ "", "" };
ConfigOptionDef def;
def.type = coString;
def.width = is_wider ? Field::def_width_wider() : Field::def_width();
def.gui_type = ConfigOptionDef::GUIType::legend;
def.mode = mode;
for (auto& [name, tooltip] : columns) {
def.tooltip = tooltip;
def.set_default_value(new ConfigOptionString{ into_u8(_(name)) });
auto option = Option(def, name + "_legend");
line.append_option(option);
}
optgroup->append_line(line);
}
PageShp TabPrinter::build_kinematics_page()
{
auto page = add_options_page(L("Machine limits"), "cog", true);
@ -3059,27 +3084,12 @@ PageShp TabPrinter::build_kinematics_page()
};
if (m_use_silent_mode) {
// Legend for OptionsGroups
auto optgroup = page->new_optgroup("");
auto line = Line{ "", "" };
std::vector<std::pair<std::string, std::string>> legend_columns = {
{L("Normal"), L("Values in this column are for Normal mode")},
{L("Stealth"), L("Values in this column are for Stealth mode")}
};
ConfigOptionDef def;
def.type = coString;
def.width = Field::def_width();
def.gui_type = ConfigOptionDef::GUIType::legend;
def.mode = comAdvanced;
def.tooltip = L("Values in this column are for Normal mode");
def.set_default_value(new ConfigOptionString{ _(L("Normal")).ToUTF8().data() });
auto option = Option(def, "full_power_legend");
line.append_option(option);
def.tooltip = L("Values in this column are for Stealth mode");
def.set_default_value(new ConfigOptionString{ _(L("Stealth")).ToUTF8().data() });
option = Option(def, "silent_legend");
line.append_option(option);
optgroup->append_line(line);
create_legend(page, legend_columns, comAdvanced);
}
const std::vector<std::string> axes{ "x", "y", "z", "e" };
@ -3606,8 +3616,15 @@ void TabPrinter::update_fff()
toggle_options();
}
bool Tab::is_prusa_printer() const
{
std::string printer_model = m_preset_bundle->printers.get_edited_preset().config.opt_string("printer_model");
return printer_model == "SL1" || printer_model == "SL1S" || printer_model == "M1";
}
void TabPrinter::update_sla()
{ ; }
{
}
void Tab::update_ui_items_related_on_parent_preset(const Preset* selected_preset_parent)
{
@ -3695,6 +3712,7 @@ void Tab::load_current_preset()
m_opt_status_value = (m_presets->get_selected_preset_parent() ? osSystemValue : 0) | osInitValue;
init_options_list();
update_visibility();
update_sla_prusa_specific_visibility();
update_changed_ui();
}
#if 0
@ -4049,6 +4067,7 @@ void Tab::activate_selected_page(std::function<void()> throw_if_canceled)
this->compatible_widget_reload(m_compatible_prints);
}
update_sla_prusa_specific_visibility();
update_changed_ui();
update_description_lines();
toggle_options();
@ -4965,6 +4984,17 @@ bool TabPrinter::apply_extruder_cnt_from_cache()
return false;
}
void TabPrinter::update_sla_prusa_specific_visibility()
{
if (m_active_page && m_active_page->title() == "General") {
auto og_it = std::find_if(m_active_page->m_optgroups.begin(), m_active_page->m_optgroups.end(), [](const ConfigOptionsGroupShp og) { return og->title == "Tilt"; });
if (og_it != m_active_page->m_optgroups.end()) {
og_it->get()->Show(m_mode == comExpert && !is_prusa_printer());
Layout();
}
}
}
bool Tab::validate_custom_gcodes()
{
if (m_type != Preset::TYPE_FILAMENT &&
@ -5346,17 +5376,101 @@ void TabSLAMaterial::build()
build_preset_description_line(optgroup.get());
page = add_options_page(L("Material printing profile"), "note");
#if 1
optgroup = page->new_optgroup(L("Material printing profile"));
optgroup->append_single_option_line("material_print_speed");
optgroup = page->new_optgroup(L("Tilt"));
optgroup->append_single_option_line("area_fill");
#else
optgroup = page->new_optgroup(L("Material printing profile"));
option = optgroup->get_option("material_print_speed");
optgroup->append_single_option_line(option);
optgroup->append_single_option_line("area_fill");
#endif
build_tilt_group(page);
}
static void append_tilt_options_line(ConfigOptionsGroupShp optgroup, const std::string opt_key)
{
auto option = optgroup->get_option(opt_key, 0);
auto line = Line{ option.opt.full_label, "" };
option.opt.width = Field::def_width/*_wider*/();
line.append_option(option);
option = optgroup->get_option(opt_key, 1);
option.opt.width = Field::def_width/*_wider*/();
line.append_option(option);
optgroup->append_line(line);
}
void TabSLAMaterial::build_tilt_group(Slic3r::GUI::PageShp page)
{
// Legend
std::vector<std::pair<std::string, std::string>> legend_columns = {
// TRN: This is a label of a column of parameters in settings to be used when the area is below certain threshold.
{L("Below"),
L("Values in this column are applied when layer area is smaller than area_fill.")},
// TRN: This is a label of a column of parameters in settings to be used when the area is above certain threshold.
{L("Above"),
L("Values in this column are applied when layer area is larger than area_fill.")},
};
create_legend(page, legend_columns, comExpert/*, true*/);
// TRN: 'Profile' in this context denotes a group of parameters used to configure
// layer separation procedure for SLA printers.
auto optgroup = page->new_optgroup(L("Profile settings"));
optgroup->on_change = [this, optgroup](const t_config_option_key& key, boost::any value)
{
if (key.find_first_of("use_tilt") == 0)
toggle_tilt_options(key == "use_tilt#0");
update_dirty();
update();
};
for (const std::string& opt_key : tilt_options())
append_tilt_options_line(optgroup, opt_key);
}
std::vector<std::string> disable_tilt_options = {
"tilt_down_initial_speed"
,"tilt_down_offset_steps"
,"tilt_down_offset_delay"
,"tilt_down_finish_speed"
,"tilt_down_cycles"
,"tilt_down_delay"
,"tilt_up_initial_speed"
,"tilt_up_offset_steps"
,"tilt_up_offset_delay"
,"tilt_up_finish_speed"
,"tilt_up_cycles"
,"tilt_up_delay"
};
void TabSLAMaterial::toggle_tilt_options(bool is_above)
{
if (m_active_page && m_active_page->title() == "Material printing profile")
{
int column_id = is_above ? 0 : 1;
auto optgroup = m_active_page->get_optgroup("Profile settings");
bool use_tilt = boost::any_cast<bool>(optgroup->get_config_value(*m_config, "use_tilt", column_id));
for (const std::string& opt_key : disable_tilt_options) {
auto field = optgroup->get_fieldc(opt_key, column_id);
if (field != nullptr)
field->toggle(use_tilt);
}
}
}
void TabSLAMaterial::toggle_options()
{
const Preset &current_printer = wxGetApp().preset_bundle->printers.get_edited_preset();
std::string model = current_printer.config.opt_string("printer_model");
m_config_manipulation.toggle_field("material_print_speed", model != "SL1");
if (m_active_page->title() == "Material Overrides")
update_material_overrides_page();
}
@ -5380,6 +5494,33 @@ void TabSLAMaterial::update()
wxGetApp().mainframe->on_config_changed(m_config);
}
void TabSLAMaterial::update_sla_prusa_specific_visibility()
{
if (m_active_page && m_active_page->title() == "Material printing profile") {
for (auto& title : { "", "Profile settings" }) {
auto og_it = std::find_if(m_active_page->m_optgroups.begin(), m_active_page->m_optgroups.end(),
[title](const ConfigOptionsGroupShp og) { return og->title == title; });
if (og_it != m_active_page->m_optgroups.end())
og_it->get()->Show(m_mode >= comAdvanced && is_prusa_printer());
}
auto og_it = std::find_if(m_active_page->m_optgroups.begin(), m_active_page->m_optgroups.end(),
[](const ConfigOptionsGroupShp og) { return og->title == "Material printing profile"; });
if (og_it != m_active_page->m_optgroups.end())
og_it->get()->Show(m_mode >= comAdvanced && !is_prusa_printer());
Layout();
}
}
void TabSLAMaterial::clear_pages()
{
Tab::clear_pages();
for (auto& over_opt : m_overrides_options)
over_opt.second = nullptr;
}
void TabSLAMaterial::msw_rescale()
{
for (const auto& over_opt : m_overrides_options)
@ -5465,10 +5606,6 @@ static std::vector<std::string> get_override_opt_kyes_for_line(const std::string
for (auto& prefix : { "", "branching" })
opt_keys.push_back(preprefix + prefix + key);
}
else if (key == "relative_correction") {
for (auto& axis : { "x", "y", "z" })
opt_keys.push_back(preprefix + key + "_" + char(axis[0]));
}
else
opt_keys.push_back(preprefix + key);
@ -5481,17 +5618,7 @@ void TabSLAMaterial::create_line_with_near_label_widget(ConfigOptionsGroupShp op
add_options_into_line(optgroup, { {"", L("Default")}, {"branching", L("Branching")} }, key, "material_ow_");
else {
const std::string opt_key = std::string("material_ow_") + key;
if (key == "relative_correction") {
Line line = Line{ m_preset_bundle->printers.get_edited_preset().config.def()->get("relative_correction")->full_label, "" };
for (auto& axis : { "X", "Y", "Z" }) {
auto opt = optgroup->get_option(opt_key + "_" + char(std::tolower(axis[0])));
opt.opt.label = axis;
line.append_option(opt);
}
optgroup->append_line(line);
}
else
optgroup->append_single_option_line(opt_key);
optgroup->append_single_option_line(opt_key);
}
Line* line = optgroup->get_last_line();
@ -5537,7 +5664,7 @@ std::vector<std::pair<std::string, std::vector<std::string>>> material_overrides
"support_points_density_relative"
}},
{"Corrections", {
"relative_correction",
"absolute_correction",
"elefant_foot_compensation"
}}
};

View File

@ -377,6 +377,7 @@ public:
void update_mode();
void update_mode_markers();
void update_visibility();
virtual void update_sla_prusa_specific_visibility() {}
virtual void msw_rescale();
virtual void sys_color_changed();
Field* get_field(const t_config_option_key& opt_key, int opt_index = -1) const;
@ -406,11 +407,11 @@ public:
static bool validate_custom_gcode(const wxString& title, const std::string& gcode);
bool validate_custom_gcodes();
bool validate_custom_gcodes_was_shown{ false };
bool is_prusa_printer() const;
void edit_custom_gcode(const t_config_option_key& opt_key);
virtual const std::string& get_custom_gcode(const t_config_option_key& opt_key);
virtual void set_custom_gcode(const t_config_option_key& opt_key, const std::string& value);
protected:
void create_line_with_widget(ConfigOptionsGroup* optgroup, const std::string& opt_key, const std::string& path, widget_t widget);
wxSizer* compatible_widget_create(wxWindow* parent, PresetDependencies &deps);
@ -559,6 +560,7 @@ public:
wxSizer* create_bed_shape_widget(wxWindow* parent);
void cache_extruder_cnt(const DynamicPrintConfig* config = nullptr);
bool apply_extruder_cnt_from_cache();
void update_sla_prusa_specific_visibility() override;
};
class TabSLAMaterial : public Tab
@ -575,11 +577,15 @@ public:
~TabSLAMaterial() {}
void build() override;
void build_tilt_group(Slic3r::GUI::PageShp page);
void toggle_tilt_options(bool is_above);
void toggle_options() override;
void update() override;
void clear_pages() override;
void msw_rescale() override;
void sys_color_changed() override;
bool supports_printer_technology(const PrinterTechnology tech) const override { return tech == ptSLA; }
void update_sla_prusa_specific_visibility() override;
};
class TabSLAPrint : public Tab

View File

@ -1223,6 +1223,14 @@ static wxString get_string_value(std::string opt_key, const DynamicPrintConfig&
auto opt = config.option_def(opt_key)->enum_def->enum_to_label(config.option(opt_key)->getInt());
return opt.has_value() ? _(from_u8(*opt)) : _L("Undef");
}
case coEnums: {
auto values = config.option(opt_key)->getInts();
if (opt_idx < values.size()) {
auto opt = config.option_def(opt_key)->enum_def->enum_to_label(values[opt_idx]);
return opt.has_value() ? _(from_u8(*opt)) : _L("Undef");
}
return _L("Undef");
}
case coPoints: {
if (opt_key == "bed_shape") {
BedShape shape(*config.option<ConfigOptionPoints>(opt_key));
@ -1313,7 +1321,7 @@ void UnsavedChangesDialog::update_tree(Preset::Type type, PresetCollection* pres
m_tree->model->AddPreset(type, from_u8(presets->get_edited_preset().name), old_pt, from_u8(new_selected_preset));
// Collect dirty options.
const bool deep_compare = type != Preset::TYPE_FILAMENT && type != Preset::TYPE_SLA_MATERIAL;
const bool deep_compare = type != Preset::TYPE_FILAMENT;
auto dirty_options = presets->current_dirty_options(deep_compare);
// process changes of extruders count