mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer
This commit is contained in:
		
						commit
						c2598cf8d6
					
				
					 11 changed files with 236 additions and 89 deletions
				
			
		|  | @ -591,7 +591,7 @@ bool CLI::setup(int argc, char **argv) | |||
|     // Initialize with defaults.
 | ||||
|     for (const t_optiondef_map *options : { &cli_actions_config_def.options, &cli_transform_config_def.options, &cli_misc_config_def.options }) | ||||
|         for (const std::pair<t_config_option_key, ConfigOptionDef> &optdef : *options) | ||||
|             m_config.optptr(optdef.first, true); | ||||
|             m_config.option(optdef.first, true); | ||||
| 
 | ||||
|     set_data_dir(m_config.opt_string("datadir")); | ||||
| 
 | ||||
|  |  | |||
|  | @ -757,6 +757,12 @@ ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool cre | |||
|     return opt; | ||||
| } | ||||
| 
 | ||||
| const ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key) const | ||||
| { | ||||
|     auto it = options.find(opt_key); | ||||
|     return (it == options.end()) ? nullptr : it->second.get(); | ||||
| } | ||||
| 
 | ||||
| void DynamicConfig::read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra, t_config_option_keys* keys) | ||||
| { | ||||
|     std::vector<const char*> args;     | ||||
|  |  | |||
|  | @ -1494,8 +1494,49 @@ protected: | |||
|     ConfigOptionDef*        add_nullable(const t_config_option_key &opt_key, ConfigOptionType type); | ||||
| }; | ||||
| 
 | ||||
| // A pure interface to resolving ConfigOptions.
 | ||||
| // This pure interface is useful as a base of ConfigBase, also it may be overriden to combine 
 | ||||
| // various config sources.
 | ||||
| class ConfigOptionResolver | ||||
| { | ||||
| public: | ||||
|     ConfigOptionResolver() {} | ||||
|     virtual ~ConfigOptionResolver() {} | ||||
| 
 | ||||
|     // Find a ConfigOption instance for a given name.
 | ||||
|     virtual const ConfigOption* optptr(const t_config_option_key &opt_key) const = 0; | ||||
| 
 | ||||
|     bool 						has(const t_config_option_key &opt_key) const { return this->optptr(opt_key) != nullptr; } | ||||
|      | ||||
|     const ConfigOption* 		option(const t_config_option_key &opt_key) const { return this->optptr(opt_key); } | ||||
| 
 | ||||
|     template<typename TYPE> | ||||
|     const TYPE* 				option(const t_config_option_key& opt_key) const | ||||
|     { | ||||
|         const ConfigOption* opt = this->optptr(opt_key); | ||||
|         return (opt == nullptr || opt->type() != TYPE::static_type()) ? nullptr : static_cast<const TYPE*>(opt); | ||||
|     } | ||||
| 
 | ||||
|     const ConfigOption* 		option_throw(const t_config_option_key& opt_key) const | ||||
|     { | ||||
|         const ConfigOption* opt = this->optptr(opt_key); | ||||
|         if (opt == nullptr) | ||||
|             throw UnknownOptionException(opt_key); | ||||
|         return opt; | ||||
|     } | ||||
| 
 | ||||
|     template<typename TYPE> | ||||
|     const TYPE* 				option_throw(const t_config_option_key& opt_key) const | ||||
|     { | ||||
|         const ConfigOption* opt = this->option_throw(opt_key); | ||||
|         if (opt->type() != TYPE::static_type()) | ||||
|             throw BadOptionTypeException("Conversion to a wrong type"); | ||||
|         return static_cast<TYPE*>(opt); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| // An abstract configuration store.
 | ||||
| class ConfigBase | ||||
| class ConfigBase : public ConfigOptionResolver | ||||
| { | ||||
| public: | ||||
|     // Definition of configuration values for the purpose of GUI presentation, editing, value mapping and config file handling.
 | ||||
|  | @ -1503,7 +1544,7 @@ public: | |||
|     // but it carries the defaults of the configuration values.
 | ||||
|      | ||||
|     ConfigBase() {} | ||||
|     virtual ~ConfigBase() {} | ||||
|     ~ConfigBase() override {} | ||||
| 
 | ||||
|     // Virtual overridables:
 | ||||
| public: | ||||
|  | @ -1513,6 +1554,7 @@ public: | |||
|     virtual ConfigOption*           optptr(const t_config_option_key &opt_key, bool create = false) = 0; | ||||
|     // Collect names of all configuration values maintained by this configuration store.
 | ||||
|     virtual t_config_option_keys    keys() const = 0; | ||||
| 
 | ||||
| protected: | ||||
|     // Verify whether the opt_key has not been obsoleted or renamed.
 | ||||
|     // Both opt_key and value may be modified by handle_legacy().
 | ||||
|  | @ -1521,12 +1563,10 @@ protected: | |||
|     virtual void                    handle_legacy(t_config_option_key &/*opt_key*/, std::string &/*value*/) const {} | ||||
| 
 | ||||
| public: | ||||
| 	using ConfigOptionResolver::option; | ||||
| 	using ConfigOptionResolver::option_throw; | ||||
| 
 | ||||
|     // Non-virtual methods:
 | ||||
|     bool has(const t_config_option_key &opt_key) const { return this->option(opt_key) != nullptr; } | ||||
|      | ||||
|     const ConfigOption* option(const t_config_option_key &opt_key) const | ||||
|         { return const_cast<ConfigBase*>(this)->option(opt_key, false); } | ||||
|      | ||||
|     ConfigOption* option(const t_config_option_key &opt_key, bool create = false) | ||||
|         { return this->optptr(opt_key, create); } | ||||
|      | ||||
|  | @ -1537,10 +1577,6 @@ public: | |||
|         return (opt == nullptr || opt->type() != TYPE::static_type()) ? nullptr : static_cast<TYPE*>(opt); | ||||
|     } | ||||
| 
 | ||||
|     template<typename TYPE> | ||||
|     const TYPE* option(const t_config_option_key &opt_key) const | ||||
|         { return const_cast<ConfigBase*>(this)->option<TYPE>(opt_key, false); } | ||||
| 
 | ||||
|     ConfigOption* option_throw(const t_config_option_key &opt_key, bool create = false) | ||||
|     {  | ||||
|         ConfigOption *opt = this->optptr(opt_key, create); | ||||
|  | @ -1549,9 +1585,6 @@ public: | |||
|         return opt; | ||||
|     } | ||||
|      | ||||
|     const ConfigOption* option_throw(const t_config_option_key &opt_key) const | ||||
|         { return const_cast<ConfigBase*>(this)->option_throw(opt_key, false); } | ||||
|      | ||||
|     template<typename TYPE> | ||||
|     TYPE* option_throw(const t_config_option_key &opt_key, bool create = false) | ||||
|     {  | ||||
|  | @ -1561,10 +1594,6 @@ public: | |||
|         return static_cast<TYPE*>(opt); | ||||
|     } | ||||
|      | ||||
|     template<typename TYPE> | ||||
|     const TYPE* option_throw(const t_config_option_key &opt_key) const | ||||
|         { return const_cast<ConfigBase*>(this)->option_throw<TYPE>(opt_key, false); } | ||||
|      | ||||
|     // Apply all keys of other ConfigBase defined by this->def() to this ConfigBase.
 | ||||
|     // An UnknownOptionException is thrown in case some option keys of other are not defined by this->def(),
 | ||||
|     // or this ConfigBase is of a StaticConfig type and it does not support some of the keys, and ignore_nonexistent is not set.
 | ||||
|  | @ -1735,6 +1764,8 @@ public: | |||
|         { return dynamic_cast<T*>(this->option(opt_key, create)); } | ||||
|     template<class T> const T* opt(const t_config_option_key &opt_key) const | ||||
|         { return dynamic_cast<const T*>(this->option(opt_key)); } | ||||
|     // Overrides ConfigResolver::optptr().
 | ||||
|     const ConfigOption*     optptr(const t_config_option_key &opt_key) const override; | ||||
|     // Overrides ConfigBase::optptr(). Find ando/or create a ConfigOption instance for a given name.
 | ||||
|     ConfigOption*           optptr(const t_config_option_key &opt_key, bool create = false) override; | ||||
|     // Overrides ConfigBase::keys(). Collect names of all configuration values maintained by this configuration store.
 | ||||
|  |  | |||
|  | @ -1,12 +1,17 @@ | |||
| #include "Flow.hpp" | ||||
| #include "I18N.hpp" | ||||
| #include "Print.hpp" | ||||
| #include <cmath> | ||||
| #include <assert.h> | ||||
| 
 | ||||
| 
 | ||||
| // Mark string for localization and translate.
 | ||||
| #define L(s) Slic3r::I18N::translate(s) | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| // This static method returns a sane extrusion width default.
 | ||||
| static inline float auto_extrusion_width(FlowRole role, float nozzle_diameter, float height) | ||||
| float Flow::auto_extrusion_width(FlowRole role, float nozzle_diameter) | ||||
| { | ||||
|     switch (role) { | ||||
|     case frSupportMaterial: | ||||
|  | @ -22,6 +27,92 @@ static inline float auto_extrusion_width(FlowRole role, float nozzle_diameter, f | |||
|     } | ||||
| } | ||||
| 
 | ||||
| // Used by the Flow::extrusion_width() funtion to provide hints to the user on default extrusion width values,
 | ||||
| // and to provide reasonable values to the PlaceholderParser.
 | ||||
| static inline FlowRole opt_key_to_flow_role(const std::string &opt_key) | ||||
| { | ||||
|  	if (opt_key == "perimeter_extrusion_width" ||  | ||||
|  		// or all the defaults:
 | ||||
|  		opt_key == "extrusion_width" || opt_key == "first_layer_extrusion_width") | ||||
|         return frPerimeter; | ||||
|     else if (opt_key == "external_perimeter_extrusion_width") | ||||
|         return frExternalPerimeter; | ||||
|     else if (opt_key == "infill_extrusion_width") | ||||
|         return frInfill; | ||||
|     else if (opt_key == "solid_infill_extrusion_width") | ||||
|         return frSolidInfill; | ||||
| 	else if (opt_key == "top_infill_extrusion_width") | ||||
| 		return frTopSolidInfill; | ||||
| 	else if (opt_key == "support_material_extrusion_width") | ||||
|     	return frSupportMaterial; | ||||
|     else  | ||||
|     	throw std::runtime_error("opt_key_to_flow_role: invalid argument"); | ||||
| }; | ||||
| 
 | ||||
| static inline void throw_on_missing_variable(const std::string &opt_key, const char *dependent_opt_key)  | ||||
| { | ||||
| 	throw std::runtime_error((boost::format(L("Cannot calculate extrusion width for %1%: Variable \"%2%\" not accessible.")) % opt_key % dependent_opt_key).str()); | ||||
| } | ||||
| 
 | ||||
| // Used to provide hints to the user on default extrusion width values, and to provide reasonable values to the PlaceholderParser.
 | ||||
| double Flow::extrusion_width(const std::string& opt_key, const ConfigOptionFloatOrPercent* opt, const ConfigOptionResolver& config, const unsigned int first_printing_extruder) | ||||
| { | ||||
| 	assert(opt != nullptr); | ||||
| 
 | ||||
| 	bool first_layer = boost::starts_with(opt_key, "first_layer_"); | ||||
| 
 | ||||
| #if 0 | ||||
| // This is the logic used for skit / brim, but not for the rest of the 1st layer.
 | ||||
| 	if (opt->value == 0. && first_layer) { | ||||
| 		// The "first_layer_extrusion_width" was set to zero, try a substitute.
 | ||||
| 		opt = config.option<ConfigOptionFloatOrPercent>("perimeter_extrusion_width"); | ||||
| 		if (opt == nullptr) | ||||
|     		throw_on_missing_variable(opt_key, "perimeter_extrusion_width"); | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| 	if (opt->value == 0.) { | ||||
| 		// The role specific extrusion width value was set to zero, try the role non-specific extrusion width.
 | ||||
| 		opt = config.option<ConfigOptionFloatOrPercent>("extrusion_width"); | ||||
| 		if (opt == nullptr) | ||||
|     		throw_on_missing_variable(opt_key, "extrusion_width"); | ||||
|     	// Use the "layer_height" instead of "first_layer_height".
 | ||||
|     	first_layer = false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (opt->percent) { | ||||
| 		auto opt_key_layer_height = first_layer ? "first_layer_height" : "layer_height"; | ||||
|     	auto opt_layer_height = config.option(opt_key_layer_height); | ||||
|     	if (opt_layer_height == nullptr) | ||||
|     		throw_on_missing_variable(opt_key, opt_key_layer_height); | ||||
|     	double layer_height = opt_layer_height->getFloat(); | ||||
|     	if (first_layer && static_cast<const ConfigOptionFloatOrPercent*>(opt_layer_height)->percent) { | ||||
|     		// first_layer_height depends on layer_height.
 | ||||
| 	    	opt_layer_height = config.option("layer_height"); | ||||
| 	    	if (opt_layer_height == nullptr) | ||||
| 	    		throw_on_missing_variable(opt_key, "layer_height"); | ||||
| 	    	layer_height *= 0.01 * opt_layer_height->getFloat(); | ||||
|     	} | ||||
| 		return opt->get_abs_value(layer_height); | ||||
| 	} | ||||
| 
 | ||||
| 	if (opt->value == 0.) { | ||||
|         // If user left option to 0, calculate a sane default width.
 | ||||
|     	auto opt_nozzle_diameters = config.option<ConfigOptionFloats>("nozzle_diameter"); | ||||
|     	if (opt_nozzle_diameters == nullptr) | ||||
|     		throw_on_missing_variable(opt_key, "nozzle_diameter"); | ||||
|         return auto_extrusion_width(opt_key_to_flow_role(opt_key), float(opt_nozzle_diameters->get_at(first_printing_extruder))); | ||||
|     } | ||||
| 
 | ||||
| 	return opt->value; | ||||
| } | ||||
| 
 | ||||
| // Used to provide hints to the user on default extrusion width values, and to provide reasonable values to the PlaceholderParser.
 | ||||
| double Flow::extrusion_width(const std::string& opt_key, const ConfigOptionResolver &config, const unsigned int first_printing_extruder) | ||||
| { | ||||
|     return extrusion_width(opt_key, config.option<ConfigOptionFloatOrPercent>(opt_key), config, first_printing_extruder); | ||||
| } | ||||
| 
 | ||||
| // This constructor builds a Flow object from an extrusion width config setting
 | ||||
| // and other context properties.
 | ||||
| Flow Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height, float bridge_flow_ratio) | ||||
|  | @ -39,7 +130,7 @@ Flow Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent | |||
|             sqrt(bridge_flow_ratio) * nozzle_diameter; | ||||
|     } else if (! width.percent && width.value == 0.) { | ||||
|         // If user left option to 0, calculate a sane default width.
 | ||||
|         w = auto_extrusion_width(role, nozzle_diameter, height); | ||||
|         w = auto_extrusion_width(role, nozzle_diameter); | ||||
|     } else { | ||||
|         // If user set a manual value, use it.
 | ||||
|         w = float(width.get_abs_value(height)); | ||||
|  |  | |||
|  | @ -64,6 +64,16 @@ public: | |||
|     // This method is used exclusively to calculate new flow of 100% infill, where the extrusion width was allowed to scale
 | ||||
|     // to fit a region with integer number of lines.
 | ||||
|     static Flow new_from_spacing(float spacing, float nozzle_diameter, float height, bool bridge); | ||||
| 
 | ||||
|     // Sane extrusion width defautl based on nozzle diameter.
 | ||||
|     // The defaults were derived from manual Prusa MK3 profiles.
 | ||||
|     static float auto_extrusion_width(FlowRole role, float nozzle_diameter); | ||||
| 
 | ||||
|     // Extrusion width from full config, taking into account the defaults (when set to zero) and ratios (percentages).
 | ||||
|     // Precise value depends on layer index (1st layer vs. other layers vs. variable layer height),
 | ||||
|     // on active extruder etc. Therefore the value calculated by this function shall be used as a hint only.
 | ||||
| 	static double extrusion_width(const std::string &opt_key, const ConfigOptionFloatOrPercent *opt, const ConfigOptionResolver &config, const unsigned int first_printing_extruder = 0); | ||||
| 	static double extrusion_width(const std::string &opt_key, const ConfigOptionResolver &config, const unsigned int first_printing_extruder = 0); | ||||
| }; | ||||
| 
 | ||||
| extern Flow support_material_flow(const PrintObject *object, float layer_height = 0.f); | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| #include "PlaceholderParser.hpp" | ||||
| #include "Flow.hpp" | ||||
| #include <cstring> | ||||
| #include <ctime> | ||||
| #include <iomanip> | ||||
|  | @ -99,11 +100,7 @@ static inline bool opts_equal(const DynamicConfig &config_old, const DynamicConf | |||
| 	const ConfigOption *opt_old = config_old.option(opt_key); | ||||
| 	const ConfigOption *opt_new = config_new.option(opt_key); | ||||
| 	assert(opt_new != nullptr); | ||||
| 	if (opt_old == nullptr) | ||||
|         return false; | ||||
|     return (opt_new->type() == coFloatOrPercent) ? | ||||
| 		dynamic_cast<const ConfigOptionFloat*>(opt_old)->value == config_new.get_abs_value(opt_key) : | ||||
|         *opt_new == *opt_old; | ||||
|     return opt_old != nullptr && *opt_new == *opt_old; | ||||
| } | ||||
| 
 | ||||
| std::vector<std::string> PlaceholderParser::config_diff(const DynamicPrintConfig &rhs) | ||||
|  | @ -126,14 +123,7 @@ bool PlaceholderParser::apply_config(const DynamicPrintConfig &rhs) | |||
|     bool modified = false; | ||||
|     for (const t_config_option_key &opt_key : rhs.keys()) { | ||||
|         if (! opts_equal(m_config, rhs, 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.
 | ||||
|             // For example, XXX_extrusion_width parameters are not handled by get_abs_value correctly.
 | ||||
| 			const ConfigOption *opt_rhs = rhs.option(opt_key); | ||||
| 			this->set(opt_key, (opt_rhs->type() == coFloatOrPercent) ? | ||||
|                 new ConfigOptionFloat(rhs.get_abs_value(opt_key)) : | ||||
|                 opt_rhs->clone()); | ||||
| 			this->set(opt_key, rhs.option(opt_key)->clone()); | ||||
|             modified = true; | ||||
|         } | ||||
|     } | ||||
|  | @ -142,16 +132,8 @@ bool PlaceholderParser::apply_config(const DynamicPrintConfig &rhs) | |||
| 
 | ||||
| void PlaceholderParser::apply_only(const DynamicPrintConfig &rhs, const std::vector<std::string> &keys) | ||||
| { | ||||
|     for (const t_config_option_key &opt_key : keys) { | ||||
|         // 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.
 | ||||
|         // For example, XXX_extrusion_width parameters are not handled by get_abs_value correctly.
 | ||||
|         const ConfigOption *opt_rhs = rhs.option(opt_key); | ||||
|         this->set(opt_key, (opt_rhs->type() == coFloatOrPercent) ? | ||||
|             new ConfigOptionFloat(rhs.get_abs_value(opt_key)) : | ||||
|             opt_rhs->clone()); | ||||
|     } | ||||
|     for (const t_config_option_key &opt_key : keys) | ||||
|         this->set(opt_key, rhs.option(opt_key)->clone()); | ||||
| } | ||||
| 
 | ||||
| void PlaceholderParser::apply_config(DynamicPrintConfig &&rhs) | ||||
|  | @ -635,7 +617,7 @@ namespace client | |||
|         return os; | ||||
|     } | ||||
| 
 | ||||
|     struct MyContext { | ||||
|     struct MyContext : public ConfigOptionResolver { | ||||
|     	const DynamicConfig     *external_config        = nullptr; | ||||
|         const DynamicConfig     *config                 = nullptr; | ||||
|         const DynamicConfig     *config_override        = nullptr; | ||||
|  | @ -650,7 +632,7 @@ namespace client | |||
| 
 | ||||
|         static void             evaluate_full_macro(const MyContext *ctx, bool &result) { result = ! ctx->just_boolean_expression; } | ||||
| 
 | ||||
|         const ConfigOption*     resolve_symbol(const std::string &opt_key) const | ||||
|         const ConfigOption* 	optptr(const t_config_option_key &opt_key) const override | ||||
|         { | ||||
|             const ConfigOption *opt = nullptr; | ||||
|             if (config_override != nullptr) | ||||
|  | @ -662,6 +644,8 @@ namespace client | |||
|             return opt; | ||||
|         } | ||||
| 
 | ||||
|         const ConfigOption*     resolve_symbol(const std::string &opt_key) const { return this->optptr(opt_key); } | ||||
| 
 | ||||
|         template <typename Iterator> | ||||
|         static void legacy_variable_expansion( | ||||
|             const MyContext                 *ctx,  | ||||
|  | @ -758,7 +742,43 @@ namespace client | |||
|             case coPoint:   output.set_s(opt.opt->serialize());  break; | ||||
|             case coBool:    output.set_b(opt.opt->getBool());    break; | ||||
|             case coFloatOrPercent: | ||||
|                 ctx->throw_exception("FloatOrPercent variables are not supported", opt.it_range); | ||||
|             { | ||||
|                 std::string opt_key(opt.it_range.begin(), opt.it_range.end()); | ||||
|                 if (boost::ends_with(opt_key, "extrusion_width")) { | ||||
|                 	// Extrusion width supports defaults and a complex graph of dependencies.
 | ||||
|                     output.set_d(Flow::extrusion_width(opt_key, *ctx, static_cast<unsigned int>(ctx->current_extruder_id))); | ||||
|                 } else if (! static_cast<const ConfigOptionFloatOrPercent*>(opt.opt)->percent) { | ||||
|                 	// Not a percent, just return the value.
 | ||||
|                     output.set_d(opt.opt->getFloat()); | ||||
|                 } else { | ||||
|                 	// Resolve dependencies using the "ratio_over" link to a parent value.
 | ||||
| 			        const ConfigOptionDef  *opt_def = print_config_def.get(opt_key); | ||||
| 			        assert(opt_def != nullptr); | ||||
| 			        double v = opt.opt->getFloat() * 0.01; // percent to ratio
 | ||||
| 			        for (;;) { | ||||
| 			        	const ConfigOption *opt_parent = opt_def->ratio_over.empty() ? nullptr : ctx->resolve_symbol(opt_def->ratio_over); | ||||
| 			        	if (opt_parent == nullptr) | ||||
| 			                ctx->throw_exception("FloatOrPercent variable failed to resolve the \"ratio_over\" dependencies", opt.it_range); | ||||
| 			            if (boost::ends_with(opt_def->ratio_over, "extrusion_width")) { | ||||
|                 			// Extrusion width supports defaults and a complex graph of dependencies.
 | ||||
|                             assert(opt_parent->type() == coFloatOrPercent); | ||||
|                     		v *= Flow::extrusion_width(opt_def->ratio_over, static_cast<const ConfigOptionFloatOrPercent*>(opt_parent), *ctx, static_cast<unsigned int>(ctx->current_extruder_id)); | ||||
|                     		break; | ||||
|                     	} | ||||
|                     	if (opt_parent->type() == coFloat || opt_parent->type() == coFloatOrPercent) { | ||||
| 			        		v *= opt_parent->getFloat(); | ||||
| 			        		if (opt_parent->type() == coFloat || ! static_cast<const ConfigOptionFloatOrPercent*>(opt_parent)->percent) | ||||
| 			        			break; | ||||
| 			        		v *= 0.01; // percent to ratio
 | ||||
| 			        	} | ||||
| 		        		// Continue one level up in the "ratio_over" hierarchy.
 | ||||
| 				        opt_def = print_config_def.get(opt_def->ratio_over); | ||||
| 				        assert(opt_def != nullptr); | ||||
| 			        } | ||||
|                     output.set_d(v); | ||||
| 	            } | ||||
| 		        break; | ||||
| 		    } | ||||
|             default: | ||||
|                 ctx->throw_exception("Unknown scalar variable type", opt.it_range); | ||||
|             } | ||||
|  |  | |||
|  | @ -24,8 +24,7 @@ | |||
| #include <boost/format.hpp> | ||||
| #include <boost/log/trivial.hpp> | ||||
| 
 | ||||
| //! macro used to mark string used at localization,
 | ||||
| //! return same string
 | ||||
| // Mark string for localization and translate.
 | ||||
| #define L(s) Slic3r::I18N::translate(s) | ||||
| 
 | ||||
| namespace Slic3r { | ||||
|  | @ -527,7 +526,6 @@ 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.
 | ||||
|  | @ -563,19 +561,11 @@ void Print::config_diffs( | |||
|     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<const ConfigOptionFloat*>(opt_old_pp)->value != new_value) | ||||
| 	        	placeholder_parser_overrides.set_key_value(opt_key, new ConfigOptionFloat(new_value)); | ||||
| 		} | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -593,8 +583,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ | |||
| 
 | ||||
|     // 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); | ||||
| 	DynamicPrintConfig filament_overrides; | ||||
| 	this->config_diffs(new_full_config, print_diff, object_diff, region_diff, full_config_diff, 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; | ||||
|  | @ -614,9 +604,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ | |||
|     // which should be stopped if print_diff is not empty.
 | ||||
|     size_t num_extruders = m_config.nozzle_diameter.size(); | ||||
|     bool   num_extruders_changed = false; | ||||
|     if (! full_config_diff.empty() || ! placeholder_parser_overrides.empty()) { | ||||
|     if (! full_config_diff.empty()) { | ||||
|         update_apply_status(this->invalidate_step(psGCodeExport)); | ||||
| 		m_placeholder_parser.apply_config(std::move(placeholder_parser_overrides)); | ||||
|         // Set the profile aliases for the PrintBase::output_filename()
 | ||||
| 		m_placeholder_parser.set("print_preset",    new_full_config.option("print_settings_id")->clone()); | ||||
| 		m_placeholder_parser.set("filament_preset", new_full_config.option("filament_settings_id")->clone()); | ||||
|  |  | |||
|  | @ -435,7 +435,6 @@ private: | |||
| 		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<t_config_option_key> &opt_keys); | ||||
|  |  | |||
|  | @ -718,8 +718,9 @@ void PrintConfigDef::init_fff_params() | |||
|     def->gui_type = "f_enum_open"; | ||||
|     def->gui_flags = "show_value"; | ||||
|     def->enum_values.push_back("PLA"); | ||||
|     def->enum_values.push_back("ABS"); | ||||
|     def->enum_values.push_back("PET"); | ||||
|     def->enum_values.push_back("ABS"); | ||||
|     def->enum_values.push_back("ASA"); | ||||
|     def->enum_values.push_back("FLEX"); | ||||
|     def->enum_values.push_back("HIPS"); | ||||
|     def->enum_values.push_back("EDGE"); | ||||
|  |  | |||
|  | @ -46,12 +46,6 @@ enum SeamPosition { | |||
|     spRandom, spNearest, spAligned, spRear | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
| enum FilamentType { | ||||
|     ftPLA, ftABS, ftPET, ftHIPS, ftFLEX, ftSCAFF, ftEDGE, ftNGEN, ftPVA | ||||
| }; | ||||
| */ | ||||
| 
 | ||||
| enum SLAMaterial { | ||||
|     slamTough, | ||||
|     slamFlex, | ||||
|  | @ -149,24 +143,6 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<SeamPosition>::ge | |||
|     return keys_map; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| template<> inline const t_config_enum_values& ConfigOptionEnum<FilamentType>::get_enum_values() { | ||||
|     static t_config_enum_values keys_map; | ||||
|     if (keys_map.empty()) { | ||||
|         keys_map["PLA"]             = ftPLA; | ||||
|         keys_map["ABS"]             = ftABS; | ||||
|         keys_map["PET"]             = ftPET; | ||||
|         keys_map["HIPS"]            = ftHIPS; | ||||
|         keys_map["FLEX"]            = ftFLEX; | ||||
|         keys_map["SCAFF"]           = ftSCAFF; | ||||
|         keys_map["EDGE"]            = ftEDGE; | ||||
|         keys_map["NGEN"]            = ftNGEN; | ||||
|         keys_map["PVA"]             = ftPVA; | ||||
|     } | ||||
|     return keys_map; | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| template<> inline const t_config_enum_values& ConfigOptionEnum<SLADisplayOrientation>::get_enum_values() { | ||||
|     static const t_config_enum_values keys_map = { | ||||
|         { "landscape", sladoLandscape}, | ||||
|  | @ -354,6 +330,9 @@ protected: | |||
| #define STATIC_PRINT_CONFIG_CACHE_BASE(CLASS_NAME) \ | ||||
| public: \ | ||||
|     /* Overrides ConfigBase::optptr(). Find ando/or create a ConfigOption instance for a given name. */ \ | ||||
|     const ConfigOption*      optptr(const t_config_option_key &opt_key) const override \ | ||||
|         { return s_cache_##CLASS_NAME.optptr(opt_key, this); } \ | ||||
|     /* Overrides ConfigBase::optptr(). Find ando/or create a ConfigOption instance for a given name. */ \ | ||||
|     ConfigOption*            optptr(const t_config_option_key &opt_key, bool create = false) override \ | ||||
|         { return s_cache_##CLASS_NAME.optptr(opt_key, this); } \ | ||||
|     /* Overrides ConfigBase::keys(). Collect names of all configuration values maintained by this configuration store. */ \ | ||||
|  |  | |||
|  | @ -14,7 +14,15 @@ SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") { | |||
| 	    { "nozzle_diameter", "0.6;0.6;0.6;0.6" }, | ||||
| 	    { "temperature", "357;359;363;378" } | ||||
| 	}); | ||||
| 	parser.apply_config(config); | ||||
|     // To test the "first_layer_extrusion_width" over "first_layer_heigth" over "layer_height" chain.
 | ||||
|     config.option<ConfigOptionFloatOrPercent>("first_layer_height")->value = 150.; | ||||
|     config.option<ConfigOptionFloatOrPercent>("first_layer_height")->percent = true; | ||||
|     // To let the PlaceholderParser throw when referencing first_layer_speed if it is set to percent, as the PlaceholderParser does not know
 | ||||
|     // a percent to what.
 | ||||
|     config.option<ConfigOptionFloatOrPercent>("first_layer_speed")->value = 50.; | ||||
|     config.option<ConfigOptionFloatOrPercent>("first_layer_speed")->percent = true; | ||||
| 
 | ||||
|     parser.apply_config(config); | ||||
| 	parser.set("foo", 0); | ||||
| 	parser.set("bar", 2); | ||||
| 	parser.set("num_extruders", 4); | ||||
|  | @ -41,6 +49,19 @@ SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") { | |||
|     SECTION("math: int(13.4)") { REQUIRE(parser.process("{int(13.4)}") == "13"); } | ||||
|     SECTION("math: int(-13.4)") { REQUIRE(parser.process("{int(-13.4)}") == "-13"); } | ||||
| 
 | ||||
|     // Test the "coFloatOrPercent" and "xxx_extrusion_width" substitutions.
 | ||||
|     // first_layer_extrusion_width ratio_over first_layer_heigth ratio_over layer_height
 | ||||
|     SECTION("perimeter_extrusion_width") { REQUIRE(std::stod(parser.process("{perimeter_extrusion_width}")) == Approx(0.67500001192092896)); } | ||||
|     SECTION("first_layer_extrusion_width") { REQUIRE(std::stod(parser.process("{first_layer_extrusion_width}")) == Approx(0.9)); } | ||||
|     SECTION("support_material_xy_spacing") { REQUIRE(std::stod(parser.process("{support_material_xy_spacing}")) == Approx(0.3375)); } | ||||
|     // external_perimeter_speed over perimeter_speed
 | ||||
|     SECTION("external_perimeter_speed") { REQUIRE(std::stod(parser.process("{external_perimeter_speed}")) == Approx(30.)); } | ||||
|     // infill_overlap over perimeter_extrusion_width
 | ||||
|     SECTION("infill_overlap") { REQUIRE(std::stod(parser.process("{infill_overlap}")) == Approx(0.16875)); } | ||||
|     // If first_layer_speed is set to percent, then it is applied over respective extrusion types by overriding their respective speeds.
 | ||||
|     // The PlaceholderParser has no way to know which extrusion type the caller has in mind, therefore it throws.
 | ||||
|     SECTION("first_layer_speed") { REQUIRE_THROWS(parser.process("{first_layer_speed}")); } | ||||
| 
 | ||||
|     // Test the boolean expression parser.
 | ||||
|     auto boolean_expression = [&parser](const std::string& templ) { return parser.evaluate_boolean_expression(templ, parser.config()); }; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 David Kocik
						David Kocik