diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index 454906ec3f6..d7901d0c9a9 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -692,23 +692,57 @@ double ConfigBase::get_abs_value(const t_config_option_key &opt_key) const { // Get stored option value. const ConfigOption *raw_opt = this->option(opt_key); + if (raw_opt == nullptr) { + std::stringstream ss; + ss << "You can't define an option that needs " << opt_key << " without defining it!"; + throw std::runtime_error(ss.str()); + } assert(raw_opt != nullptr); + if (raw_opt->type() == coFloat) - return static_cast(raw_opt)->value; + return static_cast(raw_opt)->value; + if (raw_opt->type() == coInt) + return static_cast(raw_opt)->value; + if (raw_opt->type() == coBool) + return static_cast(raw_opt)->value ? 1 : 0; + + const ConfigOptionPercent *cast_opt = nullptr; if (raw_opt->type() == coFloatOrPercent) { - // Get option definition. - const ConfigDef *def = this->def(); - if (def == nullptr) - throw NoDefinitionException(opt_key); - const ConfigOptionDef *opt_def = def->get(opt_key); - assert(opt_def != nullptr); - // Compute absolute value over the absolute value of the base option. - //FIXME there are some ratio_over chains, which end with empty ratio_with. - // For example, XXX_extrusion_width parameters are not handled by get_abs_value correctly. - return opt_def->ratio_over.empty() ? 0. : - static_cast(raw_opt)->get_abs_value(this->get_abs_value(opt_def->ratio_over)); + auto cofop = static_cast(raw_opt); + if (cofop->value == 0 && boost::ends_with(opt_key, "_extrusion_width")) { + return this->get_abs_value("extrusion_width"); + } + if (!cofop->percent) + return cofop->value; + cast_opt = cofop; } - throw ConfigurationError("ConfigBase::get_abs_value(): Not a valid option type for get_abs_value()"); + + if (raw_opt->type() == coPercent) { + cast_opt = static_cast(raw_opt); + } + + // Get option definition. + const ConfigDef *def = this->def(); + if (def == nullptr) + throw NoDefinitionException(opt_key); + const ConfigOptionDef *opt_def = def->get(opt_key); + + assert(opt_def != nullptr); + if (opt_def->ratio_over == "") + return cast_opt->get_abs_value(1); + + // Compute absolute value over the absolute value of the base option. + // FIXME there are some ratio_over chains, which end with empty ratio_with. + // For example, XXX_extrusion_width parameters are not handled by get_abs_value correctly. + return opt_def->ratio_over.empty() ? + 0. : + static_cast(raw_opt)->get_abs_value( + this->get_abs_value(opt_def->ratio_over) + ); + + throw ConfigurationError( + "ConfigBase::get_abs_value(): Not a valid option type for get_abs_value()" + ); } // Return an absolute value of a possibly relative config variable. diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp index 4b216d5b447..6f7377b4827 100644 --- a/src/libslic3r/Fill/FillAdaptive.cpp +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -305,7 +305,7 @@ std::pair adaptive_fill_line_spacing(const PrintObject &print_ob bool nonempty = config.fill_density > 0; bool has_adaptive_infill = nonempty && config.fill_pattern == ipAdaptiveCubic; bool has_support_infill = nonempty && config.fill_pattern == ipSupportCubic; - double infill_extrusion_width = config.infill_extrusion_width.percent ? default_infill_extrusion_width * 0.01 * config.infill_extrusion_width : config.infill_extrusion_width; + double infill_extrusion_width = config.infill_extrusion_width.get_abs_value(max_nozzle_diameter); region_fill_data.push_back(RegionFillData({ has_adaptive_infill ? Tristate::Maybe : Tristate::No, has_support_infill ? Tristate::Maybe : Tristate::No, diff --git a/src/libslic3r/Fill/Lightning/Generator.cpp b/src/libslic3r/Fill/Lightning/Generator.cpp index 185cb60af40..34d3424738f 100644 --- a/src/libslic3r/Fill/Lightning/Generator.cpp +++ b/src/libslic3r/Fill/Lightning/Generator.cpp @@ -36,9 +36,7 @@ Generator::Generator(const PrintObject &print_object, const coordf_t fill_densit // Note: There's not going to be a layer below the first one, so the 'initial layer height' doesn't have to be taken into account. const double layer_thickness = scaled(object_config.layer_height.value); - m_infill_extrusion_width = scaled(region_config.infill_extrusion_width.percent ? default_infill_extrusion_width * 0.01 * region_config.infill_extrusion_width : - region_config.infill_extrusion_width != 0. ? region_config.infill_extrusion_width : - default_infill_extrusion_width); + m_infill_extrusion_width = m_infill_extrusion_width = scaled(region_config.infill_extrusion_width.get_abs_value(max_nozzle_diameter)); m_supporting_radius = coord_t(m_infill_extrusion_width * 100. / fill_density); const double lightning_infill_overhang_angle = M_PI / 4; // 45 degrees diff --git a/src/libslic3r/Flow.cpp b/src/libslic3r/Flow.cpp index e6290cdff02..b775bcfc314 100644 --- a/src/libslic3r/Flow.cpp +++ b/src/libslic3r/Flow.cpp @@ -73,8 +73,6 @@ double Flow::extrusion_width(const std::string& opt_key, const ConfigOptionFloat { 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) { @@ -90,24 +88,18 @@ double Flow::extrusion_width(const std::string& opt_key, const ConfigOptionFloat opt = config.option("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; } + auto opt_nozzle_diameters = config.option("nozzle_diameter"); + if (opt_nozzle_diameters == nullptr) + throw_on_missing_variable(opt_key, "nozzle_diameter"); + 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); - assert(! first_layer || ! static_cast(opt_layer_height)->percent); - return opt->get_abs_value(opt_layer_height->getFloat()); + return opt->get_abs_value(float(opt_nozzle_diameters->get_at(first_printing_extruder))); } if (opt->value == 0.) { // If user left option to 0, calculate a sane default width. - auto opt_nozzle_diameters = config.option("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))); } @@ -133,7 +125,7 @@ Flow Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent w = auto_extrusion_width(role, nozzle_diameter); } else { // If user set a manual value, use it. - w = float(width.get_abs_value(height)); + w = float(width.get_abs_value(nozzle_diameter)); } return Flow(w, height, rounded_rectangle_extrusion_spacing(w, height), nozzle_diameter, false); diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index e4b4d6539a9..3d5f7045bc7 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -686,6 +686,7 @@ void Layer::make_perimeters() (other_config.gap_fill_enabled ? other_config.gap_fill_speed.value : 0.) && config.overhangs == other_config.overhangs && config.opt_serialize("perimeter_extrusion_width") == other_config.opt_serialize("perimeter_extrusion_width") + && config.opt_serialize("external_perimeter_extrusion_width") == other_config.opt_serialize("external_perimeter_extrusion_width") && config.thin_walls == other_config.thin_walls && config.external_perimeters_first == other_config.external_perimeters_first && config.infill_overlap == other_config.infill_overlap diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index 708bdcf5ee6..b49ef49be02 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -996,7 +996,7 @@ static inline std::vector> mm_segmentation_top_and_botto // Maximum number of bottom layers for a queried color. int bottom_solid_layers { 0 }; }; - auto layer_color_stat = [&layers = std::as_const(layers)](const size_t layer_idx, const size_t color_idx) -> LayerColorStat { + auto layer_color_stat = [&layers = std::as_const(layers), &print_object](const size_t layer_idx, const size_t color_idx) -> LayerColorStat { LayerColorStat out; const Layer &layer = *layers[layer_idx]; for (const LayerRegion *region : layer.regions()) @@ -1004,14 +1004,16 @@ static inline std::vector> mm_segmentation_top_and_botto // color_idx == 0 means "don't know" extruder aka the underlying extruder. // As this region may split existing regions, we collect statistics over all regions for color_idx == 0. color_idx == 0 || config.perimeter_extruder == int(color_idx)) { - out.extrusion_width = std::max(out.extrusion_width, float(config.perimeter_extrusion_width)); + const double nozzle_diameter = print_object.print()->config().nozzle_diameter.get_at(0); + double perimeter_extrusion_width = config.get_abs_value("perimeter_extrusion_width", nozzle_diameter); + out.extrusion_width = std::max(out.extrusion_width, perimeter_extrusion_width); out.top_solid_layers = std::max(out.top_solid_layers, config.top_solid_layers); out.bottom_solid_layers = std::max(out.bottom_solid_layers, config.bottom_solid_layers); out.small_region_threshold = config.gap_fill_enabled.value && config.gap_fill_speed.value > 0 ? // Gap fill enabled. Enable a single line of 1/2 extrusion width. - 0.5f * float(config.perimeter_extrusion_width) : + 0.5f * perimeter_extrusion_width : // Gap fill disabled. Enable two lines slightly overlapping. - float(config.perimeter_extrusion_width) + 0.7f * Flow::rounded_rectangle_extrusion_spacing(float(config.perimeter_extrusion_width), float(layer.height)); + perimeter_extrusion_width + 0.7f * Flow::rounded_rectangle_extrusion_spacing(perimeter_extrusion_width, float(layer.height)); out.small_region_threshold = scaled(out.small_region_threshold * 0.5f); ++ out.num_regions; } diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 7e5795823cc..c0d7eab964a 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -724,13 +724,9 @@ std::string Print::validate(std::vector* warnings) const return _u8L("One or more object were assigned an extruder that the printer does not have."); #endif - auto validate_extrusion_width = [/*min_nozzle_diameter,*/ max_nozzle_diameter](const ConfigBase &config, const char *opt_key, double layer_height, std::string &err_msg) -> bool { - // This may change in the future, if we switch to "extrusion width wrt. nozzle diameter" - // instead of currently used logic "extrusion width wrt. layer height", see GH issues #1923 #2829. -// double extrusion_width_min = config.get_abs_value(opt_key, min_nozzle_diameter); -// double extrusion_width_max = config.get_abs_value(opt_key, max_nozzle_diameter); - double extrusion_width_min = config.get_abs_value(opt_key, layer_height); - double extrusion_width_max = extrusion_width_min; + auto validate_extrusion_width = [min_nozzle_diameter, max_nozzle_diameter](const ConfigBase &config, const char *opt_key, double layer_height, std::string &err_msg) -> bool { + double extrusion_width_min = config.get_abs_value(opt_key, min_nozzle_diameter); + double extrusion_width_max = config.get_abs_value(opt_key, max_nozzle_diameter); if (extrusion_width_min == 0) { // Default "auto-generated" extrusion width is always valid. } else if (extrusion_width_min <= layer_height) { diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 98cc1675a2d..1314e10b15e 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -980,12 +980,14 @@ void PrintConfigDef::init_fff_params() def->category = L("Extrusion Width"); def->tooltip = L("Set this to a non-zero value to set a manual extrusion width for external perimeters. " "If left zero, default extrusion width will be used if set, otherwise 1.125 x nozzle diameter will be used. " - "If expressed as percentage (for example 200%), it will be computed over layer height."); + "If expressed as percentage (for example 200%), it will be computed over the nozzle diameter."); def->sidetext = L("mm or %"); + def->ratio_over = "nozzle_diameter"; def->min = 0; - def->max_literal = 50; + def->max = 1000; + def->max_literal = 10; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloatOrPercent(0, false)); + def->set_default_value(new ConfigOptionFloatOrPercent(105, true)); def = this->add("external_perimeter_speed", coFloatOrPercent); def->label = L("External perimeters"); @@ -1104,11 +1106,12 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Set this to a non-zero value to allow a manual extrusion width. " "If left to zero, Slic3r derives extrusion widths from the nozzle diameter " "(see the tooltips for perimeter extrusion width, infill extrusion width etc). " - "If expressed as percentage (for example: 230%), it will be computed over layer height."); + "If expressed as percentage (for example: 230%), it will be computed over the nozzle diameter."); def->sidetext = L("mm or %"); + def->ratio_over = "nozzle_diameter"; def->min = 0; def->max = 1000; - def->max_literal = 50; + def->max_literal = 10; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloatOrPercent(0, false)); @@ -1527,14 +1530,15 @@ void PrintConfigDef::init_fff_params() def->category = L("Extrusion Width"); def->tooltip = L("Set this to a non-zero value to set a manual extrusion width for first layer. " "You can use this to force fatter extrudates for better adhesion. If expressed " - "as percentage (for example 120%) it will be computed over first layer height. " + "as percentage (for example 120%) it will be computed over the nozzle diameter " "If set to zero, it will use the default extrusion width."); def->sidetext = L("mm or %"); - def->ratio_over = "first_layer_height"; + def->ratio_over = "nozzle_diameter"; def->min = 0; - def->max_literal = 50; + def->max = 1000; + def->max_literal = 10; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloatOrPercent(200, true)); + def->set_default_value(new ConfigOptionFloatOrPercent(140, true)); def = this->add("first_layer_height", coFloatOrPercent); def->label = L("First layer height"); @@ -1903,10 +1907,12 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Set this to a non-zero value to set a manual extrusion width for infill. " "If left zero, default extrusion width will be used if set, otherwise 1.125 x nozzle diameter will be used. " "You may want to use fatter extrudates to speed up the infill and make your parts stronger. " - "If expressed as percentage (for example 90%) it will be computed over layer height."); + "If expressed as percentage (for example 90%) it will be computed over the nozzle diameter."); def->sidetext = L("mm or %"); + def->ratio_over = "nozzle_diameter"; def->min = 0; - def->max_literal = 50; + def->max = 1000; + def->max_literal = 10; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloatOrPercent(0, false)); @@ -2637,11 +2643,13 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Set this to a non-zero value to set a manual extrusion width for perimeters. " "You may want to use thinner extrudates to get more accurate surfaces. " "If left zero, default extrusion width will be used if set, otherwise 1.125 x nozzle diameter will be used. " - "If expressed as percentage (for example 200%) it will be computed over layer height."); + "If expressed as percentage (for example 200%) it will be computed over the nozzle diameter."); def->sidetext = L("mm or %"); def->aliases = { "perimeters_extrusion_width" }; + def->ratio_over = "nozzle_diameter"; def->min = 0; - def->max_literal = 50; + def->max = 1000; + def->max_literal = 10; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloatOrPercent(0, false)); @@ -3060,10 +3068,12 @@ void PrintConfigDef::init_fff_params() def->category = L("Extrusion Width"); def->tooltip = L("Set this to a non-zero value to set a manual extrusion width for infill for solid surfaces. " "If left zero, default extrusion width will be used if set, otherwise 1.125 x nozzle diameter will be used. " - "If expressed as percentage (for example 90%) it will be computed over layer height."); + "If expressed as percentage (for example 90%) it will be computed over the nozzle diameter."); def->sidetext = L("mm or %"); + def->ratio_over = "nozzle_diameter"; def->min = 0; - def->max_literal = 50; + def->max = 1000; + def->max_literal = 10; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloatOrPercent(0, false)); @@ -3329,10 +3339,12 @@ void PrintConfigDef::init_fff_params() def->category = L("Extrusion Width"); def->tooltip = L("Set this to a non-zero value to set a manual extrusion width for support material. " "If left zero, default extrusion width will be used if set, otherwise nozzle diameter will be used. " - "If expressed as percentage (for example 90%) it will be computed over layer height."); + "If expressed as percentage (for example 90%) it will be computed over the nozzle diameter."); def->sidetext = L("mm or %"); + def->ratio_over = "nozzle_diameter"; def->min = 0; - def->max_literal = 50; + def->max = 1000; + def->max_literal = 10; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloatOrPercent(0, false)); @@ -3650,12 +3662,14 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Set this to a non-zero value to set a manual extrusion width for infill for top surfaces. " "You may want to use thinner extrudates to fill all narrow regions and get a smoother finish. " "If left zero, default extrusion width will be used if set, otherwise nozzle diameter will be used. " - "If expressed as percentage (for example 90%) it will be computed over layer height."); + "If expressed as percentage (for example 90%) it will be computed over the nozzle diameter."); def->sidetext = L("mm or %"); + def->ratio_over = "nozzle_diameter"; def->min = 0; - def->max_literal = 50; + def->max = 1000; + def->max_literal = 10; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloatOrPercent(0, false)); + def->set_default_value(new ConfigOptionFloatOrPercent(105, true)); def = this->add("top_solid_infill_speed", coFloatOrPercent); def->label = L("Top solid infill"); diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 545fc5fadf4..da7cd44bc3a 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -340,6 +340,16 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) for (auto el : { "raft_expansion", "first_layer_speed_over_raft" }) toggle_field(el, have_raft); + //for default_extrusion_width/spacing, you need to ahve at least an extrusion_width with 0 + bool have_default_width = config->option("first_layer_extrusion_width")->getFloat() == 0 || + (config->option("perimeter_extrusion_width")->getFloat() == 0 && (have_perimeters || have_brim)) || + (config->option("external_perimeter_extrusion_width")->getFloat() == 0 && have_perimeters) || + (config->option("infill_extrusion_width")->getFloat() == 0 && (have_infill || has_solid_infill)) || + (config->option("solid_infill_extrusion_width")->getFloat() == 0 && has_solid_infill) || + (config->option("top_infill_extrusion_width")->getFloat() == 0 && has_top_solid_infill) || + (config->option("support_material_extrusion_width")->getFloat() == 0 && have_support_material); + toggle_field("extrusion_width", have_default_width); + bool has_ironing = config->opt_bool("ironing"); for (auto el : { "ironing_type", "ironing_flowrate", "ironing_spacing", "ironing_speed" }) toggle_field(el, has_ironing);