diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index ce588151c2..b34b6af932 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -61,9 +61,9 @@ namespace Slic3r { template void serialize(Archive& ar) { ar(this->value); ar(this->percent); } }; - inline bool operator==(const FloatOrPercent& l, const FloatOrPercent& r) throw() { return l.value == r.value && l.percent == r.percent; } - inline bool operator!=(const FloatOrPercent& l, const FloatOrPercent& r) throw() { return !(l == r); } - inline bool operator< (const FloatOrPercent& l, const FloatOrPercent& r) throw() { return l.value < r.value || (l.value == r.value && int(l.percent) < int(r.percent)); } + inline bool operator==(const FloatOrPercent& l, const FloatOrPercent& r) noexcept { return l.value == r.value && l.percent == r.percent; } + inline bool operator!=(const FloatOrPercent& l, const FloatOrPercent& r) noexcept { return !(l == r); } + inline bool operator< (const FloatOrPercent& l, const FloatOrPercent& r) noexcept { return l.value < r.value || (l.value == r.value && int(l.percent) < int(r.percent)); } } namespace std { @@ -320,6 +320,54 @@ public: typedef ConfigOption* ConfigOptionPtr; typedef const ConfigOption* ConfigOptionConstPtr; +// Nill value will be defined in specializations +template struct NilValueTempl +{ + using NilType = T; + static_assert(always_false::value, "Type has no well defined nil value"); +}; + +template struct NilValueTempl, void>> { + using NilType = T; + static constexpr auto value = std::numeric_limits::max(); +}; + +template<> struct NilValueTempl : public NilValueTempl{}; + +// For enums the nil is the max value of the underlying type. +template +struct NilValueTempl, void>> +{ + using NilType = T; + static constexpr auto value = static_cast(std::numeric_limits>::max()); +}; + +template struct NilValueTempl, void>> { + using NilType = T; + static constexpr auto value = std::numeric_limits::quiet_NaN(); +}; + +template<> +struct NilValueTempl : public NilValueTempl {}; + +template<> struct NilValueTempl { + using NilType = const char *; + + static constexpr const char* value = ""; +}; + +template struct NilValueTempl> { + using NilType = Vec; + // No constexpr for Vec + static inline const Vec value = Vec::Ones() * NilValueTempl>::value; +}; + +template using NilType = typename NilValueTempl>::NilType; + +// Define shortcut as a function instead of a static const var so that it can be constexpr +// even if the NilValueTempl::value is not constexpr. +template static constexpr NilType NilValue() noexcept { return NilValueTempl>::value; } + // Value of a single valued option (bool, int, float, string, point, enum) template class ConfigOptionSingle : public ConfigOption { @@ -357,12 +405,12 @@ public: throw ConfigurationError("Cannot override a nullable ConfigOption."); if (rhs->type() != this->type()) throw ConfigurationError("ConfigOptionVector.overriden_by() applied to different types."); - auto rhs_vec = static_cast(rhs); + auto rhs_co = static_cast(rhs); if (! rhs->nullable()) // Overridding a non-nullable object with another non-nullable object. - return this->value != rhs_vec->value; + return this->value != rhs_co->value; - return false; + return !rhs_co->is_nil() && rhs_co->value != this->value; } // Apply an override option, possibly a nullable one. bool apply_override(const ConfigOption *rhs) override { @@ -370,27 +418,37 @@ public: throw ConfigurationError("Cannot override a nullable ConfigOption."); if (rhs->type() != this->type()) throw ConfigurationError("ConfigOptionVector.apply_override() applied to different types."); - auto rhs_vec = static_cast(rhs); + auto rhs_co = static_cast(rhs); if (! rhs->nullable()) { // Overridding a non-nullable object with another non-nullable object. - if (this->value != rhs_vec->value) { - this->value = rhs_vec->value; + if (this->value != rhs_co->value) { + this->value = rhs_co->value; return true; } return false; } + if (!rhs_co->is_nil() && rhs_co->value != this->value) { + this->value = rhs_co->value; + return true; + } + return false; } bool nullable() const override { return NULLABLE; } - static T nil_value() { return std::numeric_limits::min(); } + static constexpr NilType nil_value() { return NilValue(); } // A scalar is nil, or all values of a vector are nil. bool is_nil() const override { - return this->value == nil_value(); + bool ret = false; + + if constexpr (NULLABLE) + ret = this->value == nil_value(); + + return ret; } private: @@ -636,7 +694,18 @@ public: std::string serialize() const override { std::ostringstream ss; - ss << this->value; + double v = this->value; + + if (std::isfinite(v)) + ss << v; + else if (std::isnan(v)) { + if (NULLABLE) + ss << "nil"; + else + throw ConfigurationError("Serializing NaN"); + } else + throw ConfigurationError("Serializing invalid number"); + return ss.str(); } @@ -644,7 +713,16 @@ public: { UNUSED(append); std::istringstream iss(str); - iss >> this->value; + + if (str == "nil") { + if (NULLABLE) + this->value = this->nil_value(); + else + throw ConfigurationError("Deserializing nil into a non-nullable object"); + } else { + iss >> this->value; + } + return !iss.fail(); } @@ -654,6 +732,11 @@ public: return *this; } + bool is_nil() const override + { + return std::isnan(this->value); + } + private: friend class cereal::access; template void serialize(Archive &ar) { ar(cereal::base_class>(this)); } @@ -805,7 +888,14 @@ public: std::string serialize() const override { std::ostringstream ss; - ss << this->value; + if (this->value == this->nil_value()) { + if (NULLABLE) + ss << "nil"; + else + throw ConfigurationError("Serializing NaN"); + } else + ss << this->value; + return ss.str(); } @@ -813,7 +903,16 @@ public: { UNUSED(append); std::istringstream iss(str); - iss >> this->value; + + if (str == "nil") { + if (NULLABLE) + this->value = this->nil_value(); + else + throw ConfigurationError("Deserializing nil into a non-nullable object"); + } else { + iss >> this->value; + } + return !iss.fail(); } diff --git a/src/libslic3r/Format/SL1.cpp b/src/libslic3r/Format/SL1.cpp index 2ed898441b..f298cdf395 100644 --- a/src/libslic3r/Format/SL1.cpp +++ b/src/libslic3r/Format/SL1.cpp @@ -45,8 +45,9 @@ namespace { std::string to_ini(const ConfMap &m) { std::string ret; - for (auto ¶m : m) ret += param.first + " = " + param.second + "\n"; - + for (auto ¶m : m) + ret += param.first + " = " + param.second + "\n"; + return ret; } diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 5c9bd4ee3c..90e0f1fbb4 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1117,6 +1117,14 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloat, material_correction_y)) ((ConfigOptionFloat, material_correction_z)) ((ConfigOptionEnum, material_print_speed)) + ((ConfigOptionFloatNullable, material_ow_support_pillar_diameter)) + ((ConfigOptionFloatNullable, material_ow_branchingsupport_pillar_diameter)) + ((ConfigOptionFloatNullable, material_ow_support_head_front_diameter)) + ((ConfigOptionFloatNullable, material_ow_branchingsupport_head_front_diameter)) + ((ConfigOptionFloatNullable, material_ow_support_head_penetration)) + ((ConfigOptionFloatNullable, material_ow_branchingsupport_head_penetration)) + ((ConfigOptionFloatNullable, material_ow_support_head_width)) + ((ConfigOptionFloatNullable, material_ow_branchingsupport_head_width)) ) PRINT_CONFIG_CLASS_DEFINE( diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 7dd402ecaf..fa1d2a3c6c 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -203,14 +203,24 @@ std::vector SLAPrint::print_object_ids() const return out; } -static t_config_option_keys print_config_diffs(const SLAPrintObjectConfig ¤t_config, +static t_config_option_keys print_config_diffs(const StaticPrintConfig ¤t_config, const DynamicPrintConfig &new_full_config, DynamicPrintConfig &material_overrides) { using namespace std::string_view_literals; static const constexpr StaticSet overriden_keys = { - "support_pillar_diameter"sv + "support_head_front_diameter"sv, + "support_head_penetration"sv, + "support_head_width"sv, + "support_pillar_diameter"sv, + "branchingsupport_head_front_diameter"sv, + "branchingsupport_head_penetration"sv, + "branchingsupport_head_width"sv, + "branchingsupport_pillar_diameter"sv, + "support_points_density_relative"sv, + "relative_correction"sv, + "elefant_foot_compensation"sv, }; static constexpr auto material_ow_prefix = "material_ow_"; @@ -260,12 +270,15 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con config.option("printer_settings_id", true); config.option("physical_printer_settings_id", true); // Collect changes to print config. + DynamicPrintConfig mat_overrides; t_config_option_keys print_diff = m_print_config.diff(config); - t_config_option_keys printer_diff = m_printer_config.diff(config); + t_config_option_keys printer_diff = print_config_diffs(m_printer_config, config, mat_overrides); t_config_option_keys material_diff = m_material_config.diff(config); - t_config_option_keys object_diff = m_default_object_config.diff(config); + t_config_option_keys object_diff = print_config_diffs(m_default_object_config, config, mat_overrides); t_config_option_keys placeholder_parser_diff = m_placeholder_parser.config_diff(config); + config.apply(mat_overrides, true); + // Do not use the ApplyStatus as we will use the max function when updating apply_status. unsigned int apply_status = APPLY_STATUS_UNCHANGED; auto update_apply_status = [&apply_status](bool invalidated) @@ -838,17 +851,17 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector steps; diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 4a8e21e4be..eb5860b451 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -868,7 +868,11 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config switch (opt->type) { case coFloat: - ret = double_to_string(config.option(opt_key)->value); + if (config.option(opt_key)->is_nil()) + ret = _L("N/A"); + else + ret = double_to_string(config.option(opt_key)->value); + break; case coInt: ret = config.option(opt_key)->value; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index b3c1f5b50c..1a3c9171b3 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -5581,24 +5581,24 @@ void TabSLAMaterial::update_line_with_near_label_widget(ConfigOptionsGroupShp op if (optgroup->title == "Support head" || optgroup->title == "Support pillar") { for (auto& prefix : { "", "branching" }) { std::string opt_key = preprefix + prefix + key; - is_checked &= !m_config->option(opt_key)->is_nil(); + is_checked = !m_config->option(opt_key)->is_nil(); opt_keys.push_back(opt_key); } } else if (key == "relative_correction") { for (auto& axis : { "x", "y", "z" }) { std::string opt_key = preprefix + key + "_" + char(axis[0]); - is_checked &= !m_config->option(opt_key)->is_nil(); + is_checked = !m_config->option(opt_key)->is_nil(); opt_keys.push_back(opt_key); } } else { std::string opt_key = preprefix + key; - is_checked &= !m_config->option(opt_key)->is_nil(); + is_checked = !m_config->option(opt_key)->is_nil(); opt_keys.push_back(opt_key); } -// m_overrides_options[key]->Enable(is_checked); + // m_overrides_options[key]->Enable(is_checked); CheckBox::SetValue(m_overrides_options[key], is_checked); @@ -5622,22 +5622,25 @@ void TabSLAMaterial::update_material_overrides_page() } for (const std::string& key : keys) { - update_line_with_near_label_widget(*optgroup, key, false); - continue; + update_line_with_near_label_widget(*optgroup, key); + // // update_line_with_near_label_widget(*optgroup, key, false); - bool is_checked{ true }; + // const static std::string preprefix = "material_ow_"; - const static std::string preprefix = "material_ow_"; - if (title == "Support head" || title == "Support pillar") { - for (auto& prefix : { "", "branching" }) - update_line_with_near_label_widget(*optgroup, preprefix + prefix + key, is_checked); - } - else if (key == "relative_correction") { - for (auto& axis : { "x", "y", "z" }) - update_line_with_near_label_widget(*optgroup, preprefix + key + "_" + char(axis[0]), is_checked); - } - else - update_line_with_near_label_widget(*optgroup, preprefix + key, is_checked); + // if (title == "Support head" || title == "Support pillar") { + + // for (auto& prefix : { "", "branching" }) { + // update_line_with_near_label_widget(*optgroup, preprefix + prefix + key); + // } + // } + // else if (key == "relative_correction") { + // for (auto& axis : { "x", "y", "z" }) { + // update_line_with_near_label_widget(*optgroup, preprefix + key + "_" + char(axis[0])); + // } + // } + // else { + // update_line_with_near_label_widget(*optgroup, preprefix + key); + // } } } }