From f8218eb9036a40846682f6beb7947d64b920253e Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 25 Jul 2019 14:39:19 +0200 Subject: [PATCH] Reworked the FFF Print::update() to process the filament retract override values and to store them into the output G-code. --- src/libslic3r/Config.hpp | 71 +++++++++++++++++- src/libslic3r/GCode.cpp | 23 ++---- src/libslic3r/PlaceholderParser.cpp | 18 ++--- src/libslic3r/PlaceholderParser.hpp | 1 + src/libslic3r/Print.cpp | 110 +++++++++++++++++++++------- src/libslic3r/Print.hpp | 9 ++- src/libslic3r/PrintBase.hpp | 9 ++- src/libslic3r/PrintConfig.cpp | 19 +++++ src/libslic3r/PrintConfig.hpp | 8 ++ src/libslic3r/SLAPrint.cpp | 6 +- src/libslic3r/SLAPrint.hpp | 2 +- 11 files changed, 210 insertions(+), 66 deletions(-) diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 64fc69dd5..f1fab91fd 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -129,6 +129,19 @@ public: virtual bool nullable() const { return false; } // A scalar is nil, or all values of a vector are nil. virtual bool is_nil() const { return false; } + // Is this option overridden by another option? + // An option overrides another option if it is not nil and not equal. + virtual bool overriden_by(const ConfigOption *rhs) const { + assert(! this->nullable() && ! rhs->nullable()); + return *this != *rhs; + } + // Apply an override option, possibly a nullable one. + virtual bool apply_override(const ConfigOption *rhs) { + if (*this == *rhs) + return false; + *this = *rhs; + return true; + } }; typedef ConfigOption* ConfigOptionPtr; @@ -309,6 +322,62 @@ public: bool operator==(const std::vector &rhs) const { return this->values == rhs; } bool operator!=(const std::vector &rhs) const { return this->values != rhs; } + // Is this option overridden by another option? + // An option overrides another option if it is not nil and not equal. + bool overriden_by(const ConfigOption *rhs) const override { + if (this->nullable()) + throw std::runtime_error("Cannot override a nullable ConfigOption."); + if (rhs->type() != this->type()) + throw std::runtime_error("ConfigOptionVector.overriden_by() applied to different types."); + auto rhs_vec = static_cast*>(rhs); + if (! rhs->nullable()) + // Overridding a non-nullable object with another non-nullable object. + return this->values != rhs_vec->values; + size_t i = 0; + size_t cnt = std::min(this->size(), rhs_vec->size()); + for (; i < cnt; ++ i) + if (! rhs_vec->is_nil(i) && this->values[i] != rhs_vec->values[i]) + return true; + for (; i < rhs_vec->size(); ++ i) + if (! rhs_vec->is_nil(i)) + return true; + return false; + } + // Apply an override option, possibly a nullable one. + bool apply_override(const ConfigOption *rhs) override { + if (this->nullable()) + throw std::runtime_error("Cannot override a nullable ConfigOption."); + if (rhs->type() != this->type()) + throw std::runtime_error("ConfigOptionVector.apply_override() applied to different types."); + auto rhs_vec = static_cast*>(rhs); + if (! rhs->nullable()) { + // Overridding a non-nullable object with another non-nullable object. + if (this->values != rhs_vec->values) { + this->values = rhs_vec->values; + return true; + } + return false; + } + size_t i = 0; + size_t cnt = std::min(this->size(), rhs_vec->size()); + bool modified = false; + for (; i < cnt; ++ i) + if (! rhs_vec->is_nil(i) && this->values[i] != rhs_vec->values[i]) { + this->values[i] = rhs_vec->values[i]; + modified = true; + } + for (; i < rhs_vec->size(); ++ i) + if (! rhs_vec->is_nil(i)) { + if (this->values.empty()) + this->values.resize(i + 1); + else + this->values.resize(i + 1, this->values.front()); + this->values[i] = rhs_vec->values[i]; + modified = true; + } + return false; + } + private: friend class cereal::access; template void serialize(Archive & ar) { ar(this->values); } @@ -1595,7 +1664,7 @@ public: // Allow DynamicConfig to be instantiated on ints own without a definition. // If the definition is not defined, the method requiring the definition will throw NoDefinitionException. - const ConfigDef* def() const override { return nullptr; }; + const ConfigDef* def() const override { return nullptr; } template T* opt(const t_config_option_key &opt_key, bool create = false) { return dynamic_cast(this->option(opt_key, create)); } template const T* opt(const t_config_option_key &opt_key) const diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 81880831f..bc3730026 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1829,25 +1829,12 @@ void GCode::apply_print_config(const PrintConfig &print_config) m_config.apply(print_config); } -void GCode::append_full_config(const Print& print, std::string& str) +void GCode::append_full_config(const Print &print, std::string &str) { - const StaticPrintConfig *configs[] = { static_cast(&print.config()), &print.default_object_config(), &print.default_region_config() }; - for (size_t i = 0; i < sizeof(configs) / sizeof(configs[0]); ++i) { - const StaticPrintConfig *cfg = configs[i]; - for (const std::string &key : cfg->keys()) - if (key != "compatible_printers") - str += "; " + key + " = " + cfg->opt_serialize(key) + "\n"; - } - const DynamicConfig &full_config = print.placeholder_parser().config(); - for (const char *key : { - "print_settings_id", "filament_settings_id", "sla_print_settings_id", "sla_material_settings_id", "printer_settings_id", - "printer_model", "printer_variant", - "default_print_profile", "default_filament_profile", "default_sla_print_profile", "default_sla_material_profile", - "compatible_prints_condition_cummulative", "compatible_printers_condition_cummulative", "inherits_cummulative" }) { - const ConfigOption *opt = full_config.option(key); - if (opt != nullptr) - str += std::string("; ") + key + " = " + opt->serialize() + "\n"; - } + const DynamicPrintConfig &cfg = print.full_print_config(); + for (const std::string &key : cfg.keys()) + if (key != "compatible_prints" && key != "compatible_printers" && ! cfg.option(key)->is_nil()) + str += "; " + key + " = " + cfg.opt_serialize(key) + "\n"; } void GCode::set_extruders(const std::vector &extruder_ids) diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index 604afad20..c3ac22e96 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -94,14 +94,6 @@ void PlaceholderParser::update_timestamp(DynamicConfig &config) config.set_key_value("second", new ConfigOptionInt(timeinfo->tm_sec)); } -// Ignore this key by the placeholder parser. -static inline bool placeholder_parser_ignore(const ConfigDef *def, const std::string &opt_key) -{ - const ConfigOptionDef *opt_def = def->get(opt_key); - assert(opt_def != nullptr); - return (opt_def->multiline && boost::ends_with(opt_key, "_gcode")) || opt_key == "post_process"; -} - static inline bool opts_equal(const DynamicConfig &config_old, const DynamicConfig &config_new, const std::string &opt_key) { const ConfigOption *opt_old = config_old.option(opt_key); @@ -119,7 +111,7 @@ std::vector PlaceholderParser::config_diff(const DynamicPrintConfig const ConfigDef *def = rhs.def(); std::vector diff_keys; for (const t_config_option_key &opt_key : rhs.keys()) - if (! placeholder_parser_ignore(def, opt_key) && ! opts_equal(m_config, rhs, opt_key)) + if (! opts_equal(m_config, rhs, opt_key)) diff_keys.emplace_back(opt_key); return diff_keys; } @@ -135,8 +127,6 @@ bool PlaceholderParser::apply_config(const DynamicPrintConfig &rhs) const ConfigDef *def = rhs.def(); bool modified = false; for (const t_config_option_key &opt_key : rhs.keys()) { - if (placeholder_parser_ignore(def, opt_key)) - continue; if (! opts_equal(m_config, rhs, opt_key)) { // Store a copy of the config option. // Convert FloatOrPercent values to floats first. @@ -155,7 +145,6 @@ bool PlaceholderParser::apply_config(const DynamicPrintConfig &rhs) void PlaceholderParser::apply_only(const DynamicPrintConfig &rhs, const std::vector &keys) { for (const t_config_option_key &opt_key : keys) { - assert(! placeholder_parser_ignore(rhs.def(), opt_key)); // Store a copy of the config option. // Convert FloatOrPercent values to floats first. //FIXME there are some ratio_over chains, which end with empty ratio_with. @@ -167,6 +156,11 @@ void PlaceholderParser::apply_only(const DynamicPrintConfig &rhs, const std::vec } } +void PlaceholderParser::apply_config(DynamicPrintConfig &&rhs) +{ + m_config += std::move(rhs); +} + void PlaceholderParser::apply_env_variables() { for (char** env = environ; *env; ++ env) { diff --git a/src/libslic3r/PlaceholderParser.hpp b/src/libslic3r/PlaceholderParser.hpp index f682c3252..14fdc5c28 100644 --- a/src/libslic3r/PlaceholderParser.hpp +++ b/src/libslic3r/PlaceholderParser.hpp @@ -19,6 +19,7 @@ public: std::vector config_diff(const DynamicPrintConfig &rhs); // Return true if modified. bool apply_config(const DynamicPrintConfig &config); + void apply_config(DynamicPrintConfig &&config); // To be called on the values returned by PlaceholderParser::config_diff(). // The keys should already be valid. void apply_only(const DynamicPrintConfig &config, const std::vector &keys); diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index ac2e4f151..2cb48353d 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -485,25 +485,79 @@ bool layer_height_ranges_equal(const t_layer_config_ranges &lr1, const t_layer_c return true; } -Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &config_in) +// Collect diffs of configuration values at various containers, +// resolve the filament rectract overrides of extruder retract values. +void Print::config_diffs( + const DynamicPrintConfig &new_full_config, + t_config_option_keys &print_diff, t_config_option_keys &object_diff, t_config_option_keys ®ion_diff, + t_config_option_keys &full_config_diff, + DynamicPrintConfig &placeholder_parser_overrides, + DynamicPrintConfig &filament_overrides) const +{ + // Collect changes to print config, account for overrides of extruder retract values by filament presets. + { + const std::vector &extruder_retract_keys = print_config_def.extruder_retract_keys(); + const std::string filament_prefix = "filament_"; + for (const t_config_option_key &opt_key : m_config.keys()) { + const ConfigOption *opt_old = m_config.option(opt_key); + assert(opt_old != nullptr); + const ConfigOption *opt_new = new_full_config.option(opt_key); + assert(opt_new != nullptr); + const ConfigOption *opt_new_filament = std::binary_search(extruder_retract_keys.begin(), extruder_retract_keys.end(), opt_key) ? new_full_config.option(filament_prefix + opt_key) : nullptr; + if (opt_new_filament != nullptr && ! opt_new_filament->is_nil()) { + // An extruder retract override is available at some of the filament presets. + if (*opt_old != *opt_new || opt_new->overriden_by(opt_new_filament)) { + auto opt_copy = opt_new->clone(); + opt_copy->apply_override(opt_new_filament); + if (*opt_old == *opt_copy) + delete opt_copy; + else { + filament_overrides.set_key_value(opt_key, opt_copy); + print_diff.emplace_back(opt_key); + } + } + } else if (*opt_new != *opt_old) + print_diff.emplace_back(opt_key); + } + } + // Collect changes to object and region configs. + object_diff = m_default_object_config.diff(new_full_config); + region_diff = m_default_region_config.diff(new_full_config); + // Prepare for storing of the full print config into new_full_config to be exported into the G-code and to be used by the PlaceholderParser. + // As the PlaceholderParser does not interpret the FloatOrPercent values itself, these values are stored into the PlaceholderParser converted to floats. + for (const t_config_option_key &opt_key : new_full_config.keys()) { + const ConfigOption *opt_old = m_full_print_config.option(opt_key); + const ConfigOption *opt_new = new_full_config.option(opt_key); + if (opt_old == nullptr || *opt_new != *opt_old) + full_config_diff.emplace_back(opt_key); + if (opt_new->type() == coFloatOrPercent) { + // The m_placeholder_parser is never modified by the background processing, GCode.cpp/hpp makes a copy. + const ConfigOption *opt_old_pp = this->placeholder_parser().config().option(opt_key); + double new_value = new_full_config.get_abs_value(opt_key); + if (opt_old_pp == nullptr || static_cast(opt_old_pp)->value != new_value) + placeholder_parser_overrides.set_key_value(opt_key, new ConfigOptionFloat(new_value)); + } + } +} + +Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_config) { #ifdef _DEBUG check_model_ids_validity(model); #endif /* _DEBUG */ - // Make a copy of the config, normalize it. - DynamicPrintConfig config(config_in); - config.option("print_settings_id", true); - config.option("filament_settings_id", true); - config.option("printer_settings_id", true); - config.normalize(); - // Collect changes to print config. - t_config_option_keys print_diff = m_config.diff(config); - t_config_option_keys object_diff = m_default_object_config.diff(config); - t_config_option_keys region_diff = m_default_region_config.diff(config); - t_config_option_keys placeholder_parser_diff = this->placeholder_parser().config_diff(config); + // Normalize the config. + new_full_config.option("print_settings_id", true); + new_full_config.option("filament_settings_id", true); + new_full_config.option("printer_settings_id", true); + new_full_config.normalize(); - // Do not use the ApplyStatus as we will use the max function when updating apply_status. + // Find modified keys of the various configs. Resolve overrides extruder retract values by filament profiles. + t_config_option_keys print_diff, object_diff, region_diff, full_config_diff; + DynamicPrintConfig placeholder_parser_overrides, filament_overrides; + this->config_diffs(new_full_config, print_diff, object_diff, region_diff, full_config_diff, placeholder_parser_overrides, filament_overrides); + + // 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) { apply_status = std::max(apply_status, invalidated ? APPLY_STATUS_INVALIDATED : APPLY_STATUS_CHANGED); }; @@ -516,24 +570,26 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co // The following call may stop the background processing. if (! print_diff.empty()) update_apply_status(this->invalidate_state_by_config_options(print_diff)); + // Apply variables to placeholder parser. The placeholder parser is used by G-code export, // which should be stopped if print_diff is not empty. - if (! placeholder_parser_diff.empty()) { + if (! full_config_diff.empty() || ! placeholder_parser_overrides.empty()) { update_apply_status(this->invalidate_step(psGCodeExport)); PlaceholderParser &pp = this->placeholder_parser(); - pp.apply_only(config, placeholder_parser_diff); + pp.apply_config(std::move(placeholder_parser_overrides)); // Set the profile aliases for the PrintBase::output_filename() - pp.set("print_preset", config.option("print_settings_id")->clone()); - pp.set("filament_preset", config.option("filament_settings_id")->clone()); - pp.set("printer_preset", config.option("printer_settings_id")->clone()); + pp.set("print_preset", new_full_config.option("print_settings_id")->clone()); + pp.set("filament_preset", new_full_config.option("filament_settings_id")->clone()); + pp.set("printer_preset", new_full_config.option("printer_settings_id")->clone()); + // It is also safe to change m_config now after this->invalidate_state_by_config_options() call. + m_config.apply_only(new_full_config, print_diff, true); + m_config.apply(filament_overrides); + // Handle changes to object config defaults + m_default_object_config.apply_only(new_full_config, object_diff, true); + // Handle changes to regions config defaults + m_default_region_config.apply_only(new_full_config, region_diff, true); + m_full_print_config = std::move(new_full_config); } - - // It is also safe to change m_config now after this->invalidate_state_by_config_options() call. - m_config.apply_only(config, print_diff, true); - // Handle changes to object config defaults - m_default_object_config.apply_only(config, object_diff, true); - // Handle changes to regions config defaults - m_default_region_config.apply_only(config, region_diff, true); class LayerRanges { @@ -1698,8 +1754,8 @@ void Print::_make_wipe_tower() (float)m_config.filament_cooling_initial_speed.get_at(i), (float)m_config.filament_cooling_final_speed.get_at(i), m_config.filament_ramming_parameters.get_at(i), - m_config.filament_max_volumetric_speed.get_at(i), - m_config.nozzle_diameter.get_at(i)); + (float)m_config.filament_max_volumetric_speed.get_at(i), + (float)m_config.nozzle_diameter.get_at(i)); m_wipe_tower_data.priming = Slic3r::make_unique>( wipe_tower.prime((float)this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false)); diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 368bf4ee8..b6d7b678d 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -296,7 +296,7 @@ public: void clear() override; bool empty() const override { return m_objects.empty(); } - ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) override; + ApplyStatus apply(const Model &model, DynamicPrintConfig config) override; void process() override; // Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file. @@ -368,6 +368,13 @@ protected: bool invalidate_step(PrintStep step); private: + void config_diffs( + const DynamicPrintConfig &new_full_config, + t_config_option_keys &print_diff, t_config_option_keys &object_diff, t_config_option_keys ®ion_diff, + t_config_option_keys &full_config_diff, + DynamicPrintConfig &placeholder_parser_overrides, + DynamicPrintConfig &filament_overrides) const; + bool invalidate_state_by_config_options(const std::vector &opt_keys); void _make_skirt(); diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index d84d492a0..b0258fc64 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -217,7 +217,7 @@ protected: class PrintBase { public: - PrintBase() { this->restart(); } + PrintBase() : m_placeholder_parser(&m_full_print_config) { this->restart(); } inline virtual ~PrintBase() {} virtual PrinterTechnology technology() const noexcept = 0; @@ -240,7 +240,7 @@ public: // Some data was changed, which in turn invalidated already calculated steps. APPLY_STATUS_INVALIDATED, }; - virtual ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) = 0; + virtual ApplyStatus apply(const Model &model, DynamicPrintConfig config) = 0; const Model& model() const { return m_model; } struct TaskParams { @@ -316,7 +316,7 @@ public: virtual bool finished() const = 0; const PlaceholderParser& placeholder_parser() const { return m_placeholder_parser; } - PlaceholderParser& placeholder_parser() { return m_placeholder_parser; } + const DynamicPrintConfig& full_print_config() const { return m_full_print_config; } virtual std::string output_filename(const std::string &filename_base = std::string()) const = 0; // If the filename_base is set, it is used as the input for the template processing. In that case the path is expected to be the directory (may be empty). @@ -327,6 +327,8 @@ protected: friend class PrintObjectBase; friend class BackgroundSlicingProcess; + PlaceholderParser& placeholder_parser() { return m_placeholder_parser; } + tbb::mutex& state_mutex() const { return m_state_mutex; } std::function cancel_callback() { return m_cancel_callback; } void call_cancel_callback() { m_cancel_callback(); } @@ -341,6 +343,7 @@ protected: void update_object_placeholders(DynamicConfig &config, const std::string &default_ext) const; Model m_model; + DynamicPrintConfig m_full_print_config; private: tbb::atomic m_cancel_status; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index e147e1087..8ec74b83a 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -29,6 +29,7 @@ PrintConfigDef::PrintConfigDef() this->init_common_params(); assign_printer_technology_to_unknown(this->options, ptAny); this->init_fff_params(); + this->init_extruder_retract_keys(); assign_printer_technology_to_unknown(this->options, ptFFF); this->init_sla_params(); assign_printer_technology_to_unknown(this->options, ptSLA); @@ -2254,6 +2255,24 @@ void PrintConfigDef::init_fff_params() } } +void PrintConfigDef::init_extruder_retract_keys() +{ + m_extruder_retract_keys = { + "deretract_speed", + "retract_before_travel", + "retract_before_wipe", + "retract_layer_change", + "retract_length", + "retract_lift", + "retract_lift_above", + "retract_lift_below", + "retract_restart_extra", + "retract_speed", + "wipe" + }; + assert(std::is_sorted(m_extruder_retract_keys.begin(), m_extruder_retract_keys.end())); +} + void PrintConfigDef::init_sla_params() { ConfigOptionDef* def; diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 5731bef00..f2d0775fa 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -185,10 +185,18 @@ public: static void handle_legacy(t_config_option_key &opt_key, std::string &value); + // Options defining the extruder retract properties. These keys are sorted lexicographically. + // The extruder retract keys could be overidden by the same values defined at the Filament level + // (then the key is further prefixed with the "filament_" prefix). + const std::vector& extruder_retract_keys() const { return m_extruder_retract_keys; } + private: void init_common_params(); void init_fff_params(); + void init_extruder_retract_keys(); void init_sla_params(); + + std::vector m_extruder_retract_keys; }; // The one and only global definition of SLic3r configuration options. diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index fb2a5d7df..706053645 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -145,14 +145,13 @@ static std::vector sla_instances(const ModelObject &mo return instances; } -SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConfig &config_in) +SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig config) { #ifdef _DEBUG check_model_ids_validity(model); #endif /* _DEBUG */ - // Make a copy of the config, normalize it. - DynamicPrintConfig config(config_in); + // Normalize the config. config.option("sla_print_settings_id", true); config.option("sla_material_settings_id", true); config.option("printer_settings_id", true); @@ -459,6 +458,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf check_model_ids_equal(m_model, model); #endif /* _DEBUG */ + m_full_print_config = std::move(config); return static_cast(apply_status); } diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 9620e9b68..f6d0781a8 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -349,7 +349,7 @@ public: void clear() override; bool empty() const override { return m_objects.empty(); } - ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) override; + ApplyStatus apply(const Model &model, DynamicPrintConfig config) override; void set_task(const TaskParams ¶ms) override; void process() override; void finalize() override;