diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index 09b48f69ba..346665a135 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -653,22 +653,52 @@ 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 need " << 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; + 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, "_line_width")) { + return this->get_abs_value("line_width"); + } + if (!cofop->percent) + return cofop->value; + cast_opt = cofop; } + + 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()"); } diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp index 692b5cec77..bc1b24a81d 100644 --- a/src/libslic3r/Fill/FillAdaptive.cpp +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -301,7 +301,7 @@ std::pair adaptive_fill_line_spacing(const PrintObject &print_ob bool nonempty = config.sparse_infill_density > 0; bool has_adaptive_infill = nonempty && config.sparse_infill_pattern == ipAdaptiveCubic; bool has_support_infill = nonempty && config.sparse_infill_pattern == ipSupportCubic; - double sparse_infill_line_width = config.sparse_infill_line_width; + double sparse_infill_line_width = config.sparse_infill_line_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 fb00cbe6e2..6b453ca8ef 100644 --- a/src/libslic3r/Fill/Lightning/Generator.cpp +++ b/src/libslic3r/Fill/Lightning/Generator.cpp @@ -75,9 +75,7 @@ Generator::Generator(const PrintObject &print_object, const std::function(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); - //m_supporting_radius = coord_t(m_infill_extrusion_width) * 100 / coord_t(region_config.fill_density.value); - m_infill_extrusion_width = scaled(region_config.sparse_infill_line_width.value); + m_infill_extrusion_width = scaled(region_config.sparse_infill_line_width.get_abs_value(max_nozzle_diameter)); m_supporting_radius = coord_t(m_infill_extrusion_width) * 100 / region_config.sparse_infill_density; const double lightning_infill_overhang_angle = M_PI / 4; // 45 degrees @@ -103,7 +101,7 @@ Generator::Generator(PrintObject* m_object, std::vector& contours, std // 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.sparse_infill_line_width.value); + m_infill_extrusion_width = scaled(region_config.sparse_infill_line_width.get_abs_value(max_nozzle_diameter)); //m_supporting_radius: against to the density of lightning, failures may happen if set to high density //higher density lightning makes support harder, more time-consuming on computing and printing, but more reliable on supporting overhangs //lower density lightning performs opposite diff --git a/src/libslic3r/Flow.cpp b/src/libslic3r/Flow.cpp index 0fbefb7240..24a324fd5e 100644 --- a/src/libslic3r/Flow.cpp +++ b/src/libslic3r/Flow.cpp @@ -67,8 +67,6 @@ double Flow::extrusion_width(const std::string& opt_key, const ConfigOptionFloat { assert(opt != nullptr); - bool first_layer = boost::starts_with(opt_key, "initial_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) { @@ -84,24 +82,18 @@ double Flow::extrusion_width(const std::string& opt_key, const ConfigOptionFloat opt = config.option("line_width"); if (opt == nullptr) throw_on_missing_variable(opt_key, "line_width"); - // Use the "layer_height" instead of "initial_layer_print_height". - first_layer = false; } - if (opt->percent) { - auto opt_key_layer_height = first_layer ? "initial_layer_print_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()); + auto opt_nozzle_diameters = config.option("nozzle_diameter"); + if (opt_nozzle_diameters == nullptr) + throw_on_missing_variable(opt_key, "nozzle_diameter"); + + if (opt->percent) { + 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))); } @@ -116,18 +108,18 @@ double Flow::extrusion_width(const std::string& opt_key, const ConfigOptionResol // 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 ConfigOptionFloat &width, float nozzle_diameter, float height) +Flow Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height) { if (height <= 0) throw Slic3r::InvalidArgument("Invalid flow height supplied to new_from_config_width()"); float w; - if (width.value == 0.) { + if (!width.percent && width.value <= 0.) { // If user left option to 0, calculate a sane default width. w = auto_extrusion_width(role, nozzle_diameter); } else { // If user set a manual value, use it. - w = float(width.value); + 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/Flow.hpp b/src/libslic3r/Flow.hpp index 7ead899a19..c7954158f5 100644 --- a/src/libslic3r/Flow.hpp +++ b/src/libslic3r/Flow.hpp @@ -98,7 +98,7 @@ public: static Flow bridging_flow(float dmr, float nozzle_diameter) { return Flow { dmr, dmr, bridge_extrusion_spacing(dmr), nozzle_diameter, true }; } - static Flow new_from_config_width(FlowRole role, const ConfigOptionFloat &width, float nozzle_diameter, float height); + static Flow new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height); // Spacing of extrusions with rounded extrusion model. static float rounded_rectangle_extrusion_spacing(float width, float height); diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 3b856f6a5a..eea1dd9ccc 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1783,11 +1783,13 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato //BBS: calculate the volumetric speed of outer wall. Ignore pre-object setting and multi-filament, and just use the default setting { + float filament_max_volumetric_speed = m_config.option("filament_max_volumetric_speed")->get_at(initial_non_support_extruder_id); - float outer_wall_line_width = print.default_region_config().outer_wall_line_width.value; + const double nozzle_diameter = m_config.nozzle_diameter.get_at(initial_non_support_extruder_id); + float outer_wall_line_width = this->config().get_abs_value("outer_wall_line_width", nozzle_diameter); if (outer_wall_line_width == 0.0) { - float default_line_width = print.default_object_config().line_width.value; - outer_wall_line_width = default_line_width == 0.0 ? m_config.nozzle_diameter.get_at(initial_non_support_extruder_id) : default_line_width; + float default_line_width = this->config().get_abs_value("line_width", nozzle_diameter); + outer_wall_line_width = default_line_width == 0.0 ? nozzle_diameter : default_line_width; } Flow outer_wall_flow = Flow(outer_wall_line_width, m_config.layer_height, m_config.nozzle_diameter.get_at(initial_non_support_extruder_id)); float outer_wall_speed = print.default_region_config().outer_wall_speed.value; diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 4d474d7133..77e5db3365 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -239,7 +239,10 @@ std::vector ToolOrdering::generate_first_layer_tool_order(const Pr int extruder_id = layerm->region().config().option("wall_filament")->getInt(); for (auto expoly : layerm->raw_slices) { - if (offset_ex(expoly, -0.2 * scale_(print.config().initial_layer_line_width)).empty()) + const double nozzle_diameter = print.config().nozzle_diameter.get_at(0); + const coordf_t initial_layer_line_width = print.config().get_abs_value("initial_layer_line_width", nozzle_diameter); + + if (offset_ex(expoly, -0.2 * scale_(initial_layer_line_width)).empty()) continue; double contour_area = expoly.contour.area(); @@ -279,7 +282,10 @@ std::vector ToolOrdering::generate_first_layer_tool_order(const Pr for (auto layerm : first_layer->regions()) { int extruder_id = layerm->region().config().option("wall_filament")->getInt(); for (auto expoly : layerm->raw_slices) { - if (offset_ex(expoly, -0.2 * scale_(object.config().line_width)).empty()) + const double nozzle_diameter = object.print()->config().nozzle_diameter.get_at(0); + const coordf_t line_width = object.config().get_abs_value("line_width", nozzle_diameter); + + if (offset_ex(expoly, -0.2 * scale_(line_width)).empty()) continue; double contour_area = expoly.contour.area(); diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 5191c22939..6a0cf9cfbf 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -175,6 +175,7 @@ void Layer::make_perimeters() && config.filter_out_gap_fill.value == other_config.filter_out_gap_fill.value && config.detect_overhang_wall == other_config.detect_overhang_wall && config.opt_serialize("inner_wall_line_width") == other_config.opt_serialize("inner_wall_line_width") + && config.opt_serialize("outer_wall_line_width") == other_config.opt_serialize("outer_wall_line_width") && config.detect_thin_wall == other_config.detect_thin_wall //&& config.wall_infill_order == other_config.wall_infill_order && config.infill_wall_overlap == other_config.infill_wall_overlap diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index 06efb5fdd5..4efedc1ccb 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -1545,7 +1545,7 @@ static inline std::vector> mmu_segmentation_top_and_bott //BBS: spacing according to width and layer height float extrusion_spacing{ 0.f }; }; - 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()) @@ -1554,16 +1554,18 @@ static inline std::vector> mmu_segmentation_top_and_bott // As this region may split existing regions, we collect statistics over all regions for color_idx == 0. color_idx == 0 || config.wall_filament == int(color_idx)) { //BBS: the extrusion line width is outer wall rather than inner wall - out.extrusion_width = std::max(out.extrusion_width, float(config.outer_wall_line_width)); + const double nozzle_diameter = print_object.print()->config().nozzle_diameter.get_at(0); + double outer_wall_line_width = config.get_abs_value("outer_wall_line_width", nozzle_diameter); + out.extrusion_width = std::max(out.extrusion_width, outer_wall_line_width); out.top_shell_layers = std::max(out.top_shell_layers, config.top_shell_layers); out.bottom_shell_layers = std::max(out.bottom_shell_layers, config.bottom_shell_layers); out.small_region_threshold = config.gap_infill_speed.value > 0 ? // Gap fill enabled. Enable a single line of 1/2 extrusion width. - 0.5f * float(config.outer_wall_line_width) : + 0.5f * outer_wall_line_width : // Gap fill disabled. Enable two lines slightly overlapping. - float(config.outer_wall_line_width) + 0.7f * Flow::rounded_rectangle_extrusion_spacing(float(config.outer_wall_line_width), float(layer.height)); + outer_wall_line_width + 0.7f * Flow::rounded_rectangle_extrusion_spacing(outer_wall_line_width, float(layer.height)); out.small_region_threshold = scaled(out.small_region_threshold * 0.5f); - out.extrusion_spacing = Flow::rounded_rectangle_extrusion_spacing(float(config.outer_wall_line_width), float(layer.height)); + out.extrusion_spacing = Flow::rounded_rectangle_extrusion_spacing(float(outer_wall_line_width), float(layer.height)); ++ out.num_regions; } assert(out.num_regions > 0); diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index bf04e29c39..0c4ed1aef4 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -1019,15 +1019,13 @@ void PerimeterGenerator::process_classic() // get the real top surface ExPolygons grown_lower_slices; ExPolygons bridge_checker; - // BBS: check whether surface be bridge or not + auto nozzle_diameter = this->print_config->nozzle_diameter.get_at(this->config->wall_filament - 1); + // Check whether surface be bridge or not if (this->lower_slices != NULL) { // BBS: get the Polygons below the polygon this layer Polygons lower_polygons_series_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(*this->lower_slices, last_box); - double bridge_offset = std::max(double(ext_perimeter_spacing), (double(perimeter_width))); // SoftFever: improve bridging - auto nozzle_diameter = - this->print_config->nozzle_diameter.get_at(this->config->wall_filament - 1); const float bridge_margin = std::min(float(scale_(BRIDGE_INFILL_MARGIN)), float(scale_(nozzle_diameter * BRIDGE_INFILL_MARGIN / 0.4))); @@ -1047,7 +1045,8 @@ void PerimeterGenerator::process_classic() // increase by half peri the inner space to fill the frontier between last and stored. top_fills = union_ex(top_fills, top_polygons); //set the clip to the external wall but go back inside by infill_extrusion_width/2 to be sure the extrusion won't go outside even with a 100% overlap. - double infill_spacing_unscaled = this->config->sparse_infill_line_width.value; + double infill_spacing_unscaled = this->config->sparse_infill_line_width.get_abs_value(nozzle_diameter); + if (infill_spacing_unscaled == 0) infill_spacing_unscaled = Flow::auto_extrusion_width(frInfill, nozzle_diameter); fill_clip = offset_ex(last, double(ext_perimeter_spacing / 2) - scale_(infill_spacing_unscaled / 2)); //ExPolygons oldLast = last; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 4cd8484994..05b42ec7cc 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1099,13 +1099,9 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons* return ("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); - double extrusion_width_max = config.get_abs_value(opt_key); + 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) { @@ -1297,10 +1293,10 @@ double Print::skirt_first_layer_height() const Flow Print::brim_flow() const { - ConfigOptionFloat width = m_config.initial_layer_line_width; - if (width.value == 0) + ConfigOptionFloatOrPercent width = m_config.initial_layer_line_width; + if (width.value <= 0) width = m_print_regions.front()->config().inner_wall_line_width; - if (width.value == 0) + if (width.value <= 0) width = m_objects.front()->config().line_width; /* We currently use a random region's perimeter extruder. @@ -1310,6 +1306,7 @@ Flow Print::brim_flow() const generation as well. */ return Flow::new_from_config_width( frPerimeter, + // Flow::new_from_config_width takes care of the percent to value substitution width, (float)m_config.nozzle_diameter.get_at(m_print_regions.front()->config().wall_filament-1), (float)this->skirt_first_layer_height()); @@ -1317,8 +1314,8 @@ Flow Print::brim_flow() const Flow Print::skirt_flow() const { - ConfigOptionFloat width = m_config.initial_layer_line_width; - if (width.value == 0) + ConfigOptionFloatOrPercent width = m_config.initial_layer_line_width; + if (width.value <= 0) width = m_objects.front()->config().line_width; /* We currently use a random object's support material extruder. @@ -1328,6 +1325,7 @@ Flow Print::skirt_flow() const generation as well. */ return Flow::new_from_config_width( frPerimeter, + // Flow::new_from_config_width takes care of the percent to value substitution width, (float)m_config.nozzle_diameter.get_at(m_objects.front()->config().support_filament-1), (float)this->skirt_first_layer_height()); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 6e4332a5e9..60cd78e1ce 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1057,14 +1057,17 @@ void PrintConfigDef::init_fff_params() def->enum_labels = def_top_fill_pattern->enum_labels; def->set_default_value(new ConfigOptionEnum(ipRectilinear)); - def = this->add("outer_wall_line_width", coFloat); + def = this->add("outer_wall_line_width", coFloatOrPercent); def->label = L("Outer wall"); def->category = L("Quality"); - def->tooltip = L("Line width of outer wall"); - def->sidetext = L("mm"); + def->tooltip = L("Line width of outer wall. If expressed as a %, 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 = 10; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(0)); + def->set_default_value(new ConfigOptionFloatOrPercent(0., false)); def = this->add("outer_wall_speed", coFloat); def->label = L("Outer wall"); @@ -1208,15 +1211,17 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloats { 0.02 }); - def = this->add("line_width", coFloat); + def = this->add("line_width", coFloatOrPercent); def->label = L("Default"); def->category = L("Quality"); - def->tooltip = L("Default line width if some line width is set to be zero"); - def->sidetext = L("mm"); + def->tooltip = L("Default line width if other line widths are set to 0. If expressed as a %, it will be computed over the nozzle diameter."); + def->sidetext = L("mm or %"); + def->ratio_over = "nozzle_diameter"; def->min = 0; - def->max = 10; + def->max = 1000; + def->max_literal = 10; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(0.4)); + def->set_default_value(new ConfigOptionFloatOrPercent(0, false)); def = this->add("reduce_fan_stop_start_freq", coBools); def->label = L("Keep fan always on"); @@ -1637,14 +1642,18 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(12)); - def = this->add("initial_layer_line_width", coFloat); + def = this->add("initial_layer_line_width", coFloatOrPercent); def->label = L("Initial layer"); def->category = L("Quality"); - def->tooltip = L("Line width of initial layer"); - def->sidetext = L("mm"); + def->tooltip = L("Line width of initial layer. If expressed as a %, 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 = 10; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(0.4)); + def->set_default_value(new ConfigOptionFloatOrPercent(0., false)); + def = this->add("initial_layer_print_height", coFloat); def->label = L("Initial layer height"); @@ -1942,14 +1951,17 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionInt(1)); - def = this->add("sparse_infill_line_width", coFloat); + def = this->add("sparse_infill_line_width", coFloatOrPercent); def->label = L("Sparse infill"); def->category = L("Quality"); - def->tooltip = L("Line width of internal sparse infill"); - def->sidetext = L("mm"); + def->tooltip = L("Line width of internal sparse infill. If expressed as a %, 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 = 10; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(0.4)); + def->set_default_value(new ConfigOptionFloatOrPercent(0., false)); def = this->add("infill_wall_overlap", coPercent); def->label = L("Infill/Wall overlap"); @@ -2374,14 +2386,17 @@ void PrintConfigDef::init_fff_params() def->mode = comDevelop; def->set_default_value(new ConfigOptionInt(1)); - def = this->add("inner_wall_line_width", coFloat); + def = this->add("inner_wall_line_width", coFloatOrPercent); def->label = L("Inner wall"); def->category = L("Quality"); - def->tooltip = L("Line width of inner wall"); - def->sidetext = L("mm"); + def->tooltip = L("Line width of inner wall. If expressed as a %, 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 = 10; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(0.4)); + def->set_default_value(new ConfigOptionFloatOrPercent(0., false)); def = this->add("inner_wall_speed", coFloat); def->label = L("Inner wall"); @@ -2773,14 +2788,17 @@ void PrintConfigDef::init_fff_params() def->mode = comDevelop; def->set_default_value(new ConfigOptionInt(1)); - def = this->add("internal_solid_infill_line_width", coFloat); + def = this->add("internal_solid_infill_line_width", coFloatOrPercent); def->label = L("Internal solid infill"); def->category = L("Quality"); - def->tooltip = L("Line width of internal solid infill"); - def->sidetext = L("mm"); + def->tooltip = L("Line width of internal solid infill. If expressed as a %, 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 = 10; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(0.4)); + def->set_default_value(new ConfigOptionFloatOrPercent(0., false)); def = this->add("internal_solid_infill_speed", coFloat); def->label = L("Internal solid infill"); @@ -2995,14 +3013,17 @@ void PrintConfigDef::init_fff_params() def->mode = comSimple; def->set_default_value(new ConfigOptionInt(1)); - def = this->add("support_line_width", coFloat); + def = this->add("support_line_width", coFloatOrPercent); def->label = L("Support"); def->category = L("Quality"); - def->tooltip = L("Line width of support"); - def->sidetext = L("mm"); + def->tooltip = L("Line width of support. If expressed as a %, 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 = 10; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(0.4)); + def->set_default_value(new ConfigOptionFloatOrPercent(0., false)); def = this->add("support_interface_loop_pattern", coBool); def->label = L("Interface use loop pattern"); @@ -3318,14 +3339,17 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionString("")); - def = this->add("top_surface_line_width", coFloat); + def = this->add("top_surface_line_width", coFloatOrPercent); def->label = L("Top surface"); def->category = L("Quality"); - def->tooltip = L("Line width for top surfaces"); - def->sidetext = L("mm"); + def->tooltip = L("Line width for top surfaces. If expressed as a %, 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 = 10; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(0.4)); + def->set_default_value(new ConfigOptionFloatOrPercent(0., false)); def = this->add("top_surface_speed", coFloat); def->label = L("Top surface"); @@ -4993,7 +5017,7 @@ std::map validate(const FullPrintConfig &cfg, bool und "initial_layer_line_width" }; for (size_t i = 0; i < sizeof(widths) / sizeof(widths[i]); ++ i) { std::string key(widths[i]); - if (cfg.get_abs_value(key) > 2.5 * max_nozzle_diameter) { + if (cfg.get_abs_value(key, max_nozzle_diameter) > 2.5 * max_nozzle_diameter) { error_message.emplace(key, L("too large line width ") + std::to_string(cfg.get_abs_value(key))); //return std::string("Too Large line width: ") + key; } diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 1360b9c94f..6de2b12b6e 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -643,7 +643,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBool, bridge_no_support)) ((ConfigOptionFloat, elefant_foot_compensation)) ((ConfigOptionFloat, max_bridge_length)) - ((ConfigOptionFloat, line_width)) + ((ConfigOptionFloatOrPercent, line_width)) // Force the generation of solid shells between adjacent materials/volumes. ((ConfigOptionBool, interface_shells)) ((ConfigOptionFloat, layer_height)) @@ -667,7 +667,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloat, support_bottom_z_distance)) ((ConfigOptionInt, enforce_support_layers)) ((ConfigOptionInt, support_filament)) - ((ConfigOptionFloat, support_line_width)) + ((ConfigOptionFloatOrPercent, support_line_width)) ((ConfigOptionBool, support_interface_loop_pattern)) ((ConfigOptionInt, support_interface_filament)) ((ConfigOptionInt, support_interface_top_layers)) @@ -727,7 +727,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBool, ensure_vertical_shell_thickness)) ((ConfigOptionEnum, top_surface_pattern)) ((ConfigOptionEnum, bottom_surface_pattern)) - ((ConfigOptionFloat, outer_wall_line_width)) + ((ConfigOptionFloatOrPercent, outer_wall_line_width)) ((ConfigOptionFloat, outer_wall_speed)) ((ConfigOptionFloat, infill_direction)) ((ConfigOptionPercent, sparse_infill_density)) @@ -737,7 +737,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloat, fuzzy_skin_point_distance)) ((ConfigOptionFloat, gap_infill_speed)) ((ConfigOptionInt, sparse_infill_filament)) - ((ConfigOptionFloat, sparse_infill_line_width)) + ((ConfigOptionFloatOrPercent, sparse_infill_line_width)) ((ConfigOptionPercent, infill_wall_overlap)) ((ConfigOptionFloat, sparse_infill_speed)) //BBS @@ -750,17 +750,17 @@ PRINT_CONFIG_CLASS_DEFINE( // Detect bridging perimeters ((ConfigOptionBool, detect_overhang_wall)) ((ConfigOptionInt, wall_filament)) - ((ConfigOptionFloat, inner_wall_line_width)) + ((ConfigOptionFloatOrPercent, inner_wall_line_width)) ((ConfigOptionFloat, inner_wall_speed)) // Total number of perimeters. ((ConfigOptionInt, wall_loops)) ((ConfigOptionFloat, minimum_sparse_infill_area)) ((ConfigOptionInt, solid_infill_filament)) - ((ConfigOptionFloat, internal_solid_infill_line_width)) + ((ConfigOptionFloatOrPercent, internal_solid_infill_line_width)) ((ConfigOptionFloat, internal_solid_infill_speed)) // Detect thin walls. ((ConfigOptionBool, detect_thin_wall)) - ((ConfigOptionFloat, top_surface_line_width)) + ((ConfigOptionFloatOrPercent, top_surface_line_width)) ((ConfigOptionInt, top_shell_layers)) ((ConfigOptionFloat, top_shell_thickness)) ((ConfigOptionFloat, top_surface_speed)) @@ -946,7 +946,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionFloat, travel_acceleration)) ((ConfigOptionFloatOrPercent, sparse_infill_acceleration)) ((ConfigOptionFloatOrPercent, internal_solid_infill_acceleration)) - ((ConfigOptionFloat, initial_layer_line_width)) + ((ConfigOptionFloatOrPercent, initial_layer_line_width)) ((ConfigOptionFloat, initial_layer_print_height)) ((ConfigOptionFloat, initial_layer_speed)) ((ConfigOptionFloat, default_jerk)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 890d7aab8a..f4e89957f7 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -423,7 +423,10 @@ static const float g_min_overhang_percent_for_lift = 0.3f; void PrintObject::detect_overhangs_for_lift() { if (this->set_started(posDetectOverhangsForLift)) { - const float min_overlap = m_config.line_width * g_min_overhang_percent_for_lift; + const double nozzle_diameter = m_print->config().nozzle_diameter.get_at(0); + const coordf_t line_width = this->config().get_abs_value("line_width", nozzle_diameter); + + const float min_overlap = line_width * g_min_overhang_percent_for_lift; size_t num_layers = this->layer_count(); size_t num_raft_layers = m_slicing_params.raft_layers(); @@ -433,14 +436,14 @@ void PrintObject::detect_overhangs_for_lift() tbb::spin_mutex layer_storage_mutex; tbb::parallel_for(tbb::blocked_range(num_raft_layers + 1, num_layers), - [this, min_overlap](const tbb::blocked_range& range) + [this, min_overlap, line_width](const tbb::blocked_range& range) { for (size_t layer_id = range.begin(); layer_id < range.end(); ++layer_id) { Layer& layer = *m_layers[layer_id]; Layer& lower_layer = *layer.lower_layer; ExPolygons overhangs = diff_ex(layer.lslices, offset_ex(lower_layer.lslices, scale_(min_overlap))); - layer.loverhangs = std::move(offset2_ex(overhangs, -0.1f * scale_(m_config.line_width), 0.1f * scale_(m_config.line_width))); + layer.loverhangs = std::move(offset2_ex(overhangs, -0.1f * scale_(line_width), 0.1f * scale_(line_width))); } }); @@ -2591,6 +2594,7 @@ SupportNecessaryType PrintObject::is_support_necessary() #if 0 double threshold_rad = (m_config.support_threshold_angle.value < EPSILON ? 30 : m_config.support_threshold_angle.value + 1) * M_PI / 180.; int enforce_support_layers = m_config.enforce_support_layers; + // not fixing in extrusion width % PR b/c never called const coordf_t extrusion_width = m_config.line_width.value; const coordf_t extrusion_width_scaled = scale_(extrusion_width); float max_bridge_length = scale_(m_config.max_bridge_length.value); diff --git a/src/libslic3r/PrintRegion.cpp b/src/libslic3r/PrintRegion.cpp index 0f9f92e488..f3d5359f4c 100644 --- a/src/libslic3r/PrintRegion.cpp +++ b/src/libslic3r/PrintRegion.cpp @@ -21,7 +21,7 @@ unsigned int PrintRegion::extruder(FlowRole role) const Flow PrintRegion::flow(const PrintObject &object, FlowRole role, double layer_height, bool first_layer) const { const PrintConfig &print_config = object.print()->config(); - ConfigOptionFloat config_width; + ConfigOptionFloatOrPercent config_width; // Get extrusion width from configuration. // (might be an absolute value, or a percent value, or zero for auto) if (first_layer && print_config.initial_layer_line_width.value > 0) { diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 38b3a9d514..ecd48b46b4 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -2252,7 +2252,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ // check if the sharp tails should be extended higher bool detect_first_sharp_tail_only = false; - const coordf_t extrusion_width = m_object_config->line_width.value; + const coordf_t extrusion_width = m_object_config->line_width.get_abs_value(object.print()->config().nozzle_diameter.get_at(object.config().support_interface_filament-1)); const coordf_t extrusion_width_scaled = scale_(extrusion_width); if (is_auto(m_object_config->support_type.value) && g_config_support_sharp_tails && !detect_first_sharp_tail_only) { for (size_t layer_nr = 0; layer_nr < object.layer_count(); layer_nr++) { @@ -2345,7 +2345,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ // BBS group overhang clusters if (g_config_remove_small_overhangs) { std::vector clusters; - double fw_scaled = scale_(m_object_config->line_width); + double fw_scaled = scale_(extrusion_width); std::set removed_overhang; for (size_t layer_id = layer_id_start; layer_id < num_layers; layer_id++) { diff --git a/src/libslic3r/TreeSupport.cpp b/src/libslic3r/TreeSupport.cpp index f2309a930b..d2ebe11500 100644 --- a/src/libslic3r/TreeSupport.cpp +++ b/src/libslic3r/TreeSupport.cpp @@ -689,7 +689,12 @@ TreeSupport::TreeSupport(PrintObject& object, const SlicingParameters &slicing_p m_object_config->support_interface_pattern == smipConcentric ? ipConcentric : (m_support_params.interface_density > 0.95 ? ipRectilinear : ipSupportBase); - m_support_params.support_extrusion_width = m_object_config->support_line_width.value > 0 ? m_object_config->support_line_width : m_object_config->line_width; + + const auto nozzle_diameter = object.print()->config().nozzle_diameter.get_at(object.config().support_interface_filament-1); + const coordf_t extrusion_width = m_object_config->line_width.get_abs_value(nozzle_diameter); + const coordf_t support_extrusion_width = m_object_config->support_line_width.get_abs_value(nozzle_diameter); + + m_support_params.support_extrusion_width = support_extrusion_width > 0 ? support_extrusion_width : extrusion_width; is_slim = is_tree_slim(support_type, support_style); is_strong = is_tree(support_type) && support_style == smsTreeStrong; MAX_BRANCH_RADIUS = 10.0; @@ -723,7 +728,8 @@ void TreeSupport::detect_overhangs(bool detect_first_sharp_tail_only) const PrintObjectConfig& config = m_object->config(); SupportType stype = support_type; const coordf_t radius_sample_resolution = g_config_tree_support_collision_resolution; - const coordf_t extrusion_width = config.line_width.value; + const double nozzle_diameter = m_object->print()->config().nozzle_diameter.get_at(0); + const coordf_t extrusion_width = config.get_abs_value("line_width", nozzle_diameter); const coordf_t extrusion_width_scaled = scale_(extrusion_width); const coordf_t max_bridge_length = scale_(config.max_bridge_length.value); const bool bridge_no_support = max_bridge_length > 0; @@ -2011,7 +2017,8 @@ void TreeSupport::draw_circles(const std::vector>& contact_no const size_t top_interface_layers = config.support_interface_top_layers.value; const size_t bottom_interface_layers = config.support_interface_bottom_layers.value; const double diameter_angle_scale_factor = tan(tree_support_branch_diameter_angle * M_PI / 180.);// * layer_height / branch_radius; //Scale factor per layer to produce the desired angle. - const coordf_t line_width = config.support_line_width; + const double nozzle_diameter = m_object->print()->config().nozzle_diameter.get_at(0); + const coordf_t line_width = config.get_abs_value("support_line_width", nozzle_diameter); const coordf_t line_width_scaled = scale_(line_width); const bool with_lightning_infill = m_support_params.base_fill_pattern == ipLightning; @@ -2472,12 +2479,14 @@ void TreeSupport::drop_nodes(std::vector>& contact_nodes) const size_t bottom_interface_layers = config.support_interface_bottom_layers.value; const size_t top_interface_layers = config.support_interface_top_layers.value; float DO_NOT_MOVER_UNDER_MM = is_slim ? 0 : 5; // do not move contact points under 5mm + const auto nozzle_diameter = m_object->print()->config().nozzle_diameter.get_at(m_object->config().support_interface_filament-1); + const auto support_line_width = config.support_line_width.get_abs_value(nozzle_diameter); auto get_branch_angle = [this,&config](coordf_t radius) { if (config.tree_support_branch_angle.value < 30.0) return config.tree_support_branch_angle.value; return (radius - MIN_BRANCH_RADIUS) / (MAX_BRANCH_RADIUS - MIN_BRANCH_RADIUS) * (config.tree_support_branch_angle.value - 30.0) + 30.0; }; - auto get_max_move_dist = [this, &config, branch_radius, tip_layers, diameter_angle_scale_factor, wall_count, support_extrusion_width](const Node *node, int power = 1) { + auto get_max_move_dist = [this, &config, branch_radius, tip_layers, diameter_angle_scale_factor, wall_count, support_extrusion_width, support_line_width](const Node *node, int power = 1) { double move_dist = node->max_move_dist; if (node->max_move_dist == 0) { if (node->radius == 0) node->radius = calc_branch_radius(branch_radius, node->dist_mm_to_top, diameter_angle_scale_factor); @@ -2485,7 +2494,7 @@ void TreeSupport::drop_nodes(std::vector>& contact_nodes) if (angle > 30.0 && node->radius > MIN_BRANCH_RADIUS) angle = (node->radius - MIN_BRANCH_RADIUS) / (MAX_BRANCH_RADIUS - MIN_BRANCH_RADIUS) * (config.tree_support_branch_angle.value - 30.0) + 30.0; double tan_angle = tan(angle * M_PI / 180); - int wall_count_ = node->radius > 2 * config.support_line_width ? wall_count : 1; + int wall_count_ = node->radius > 2 * support_line_width ? wall_count : 1; node->max_move_dist = (angle < 90) ? (coordf_t) (tan_angle * node->height) * wall_count_ : std::numeric_limits::max(); node->max_move_dist = std::min(node->max_move_dist, support_extrusion_width); move_dist = node->max_move_dist; diff --git a/src/libslic3r/calib.hpp b/src/libslic3r/calib.hpp index 986442c0fe..9f31e002c6 100644 --- a/src/libslic3r/calib.hpp +++ b/src/libslic3r/calib.hpp @@ -166,8 +166,8 @@ public: protected: double speed_first_layer() const { return m_config.option("initial_layer_speed")->value; }; double speed_perimeter() const { return m_config.option("outer_wall_speed")->value; }; - double line_width_first_layer() const { return m_config.option("initial_layer_line_width")->value; }; - double line_width() const { return m_config.option("line_width")->value; }; + double line_width_first_layer() const { return m_config.get_abs_value("initial_layer_line_width"); }; + double line_width() const { return m_config.get_abs_value("line_width"); }; int wall_count() const { return m_config.option("wall_loops")->value; }; private: diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 4a6eecbaad..24bf3a06ed 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -1390,7 +1390,7 @@ void PageDiameters::apply_custom_config(DynamicPrintConfig &config) auto set_extrusion_width = [&config, opt_nozzle](const char *key, double dmr) { char buf[64]; // locales don't matter here (sprintf/atof) sprintf(buf, "%.2lf", dmr * opt_nozzle->values.front() / 0.4); - config.set_key_value(key, new ConfigOptionFloat(atof(buf))); + config.set_key_value(key, new ConfigOptionFloatOrPercent(atof(buf),false)); }; set_extrusion_width("support_line_width", 0.35); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 93ae0802c2..e6f05a0f4c 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1,4 +1,5 @@ #include "Plater.hpp" +#include "libslic3r/Config.hpp" #include #include @@ -8155,7 +8156,7 @@ void Plater::_calib_pa_pattern(const Calib_Params& params) double nozzle_diameter = printer_config.option("nozzle_diameter")->get_at(0); print_config.set_key_value( opt.first, - new ConfigOptionFloat(nozzle_diameter * opt.second / 100) + new ConfigOptionFloatOrPercent(nozzle_diameter * opt.second / 100, false) ); } @@ -8333,8 +8334,8 @@ void Plater::calib_flowrate(int pass) { _obj->config.set_key_value("detect_thin_wall", new ConfigOptionBool(true)); _obj->config.set_key_value("filter_out_gap_fill", new ConfigOptionFloat(0)); _obj->config.set_key_value("sparse_infill_pattern", new ConfigOptionEnum(ipRectilinear)); - _obj->config.set_key_value("top_surface_line_width", new ConfigOptionFloat(nozzle_diameter * 1.2f)); - _obj->config.set_key_value("internal_solid_infill_line_width", new ConfigOptionFloat(nozzle_diameter * 1.2f)); + _obj->config.set_key_value("top_surface_line_width", new ConfigOptionFloatOrPercent(nozzle_diameter * 1.2f, false)); + _obj->config.set_key_value("internal_solid_infill_line_width", new ConfigOptionFloatOrPercent(nozzle_diameter * 1.2f, false)); _obj->config.set_key_value("top_surface_pattern", new ConfigOptionEnum(ipMonotonic)); _obj->config.set_key_value("top_solid_infill_flow_ratio", new ConfigOptionFloat(1.0f)); _obj->config.set_key_value("top_surface_pattern", new ConfigOptionEnum(ipMonotonic)); @@ -8455,7 +8456,7 @@ void Plater::calib_max_vol_speed(const Calib_Params& params) print_config->set_key_value("bottom_shell_layers", new ConfigOptionInt(1)); print_config->set_key_value("sparse_infill_density", new ConfigOptionPercent(0)); print_config->set_key_value("spiral_mode", new ConfigOptionBool(true)); - print_config->set_key_value("outer_wall_line_width", new ConfigOptionFloat(line_width)); + print_config->set_key_value("outer_wall_line_width", new ConfigOptionFloatOrPercent(line_width, false)); print_config->set_key_value("initial_layer_print_height", new ConfigOptionFloat(layer_height)); print_config->set_key_value("layer_height", new ConfigOptionFloat(layer_height)); obj->config.set_key_value("brim_type", new ConfigOptionEnum(btOuterAndInner));