From 0fa884d9caa0b44790027e13799675b4542ddb44 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 29 Nov 2023 21:28:23 +0800 Subject: [PATCH] Various infill improvements (#2716) * Fix issue that sparse infill threshold no longer working * Turn all internal sparse infill into solid infill if infill density is 100% * Allow combining solid infill when sparse infill density is 100% --- src/libslic3r/LayerRegion.cpp | 26 +++++++++++++++---- src/libslic3r/PrintConfig.cpp | 8 +----- src/libslic3r/PrintObject.cpp | 29 +++++++++++++-------- src/slic3r/GUI/ConfigManipulation.cpp | 37 --------------------------- src/slic3r/GUI/Tab.cpp | 2 +- 5 files changed, 41 insertions(+), 61 deletions(-) diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index ff0c1736ab..a89dd3cfa7 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -446,6 +446,24 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly RegionExpansionParameters::build(expansion_top, expansion_step, max_nr_expansion_steps), sparse, expansion_params_into_sparse_infill, closing_radius); + // turn too small internal regions into solid regions according to the user setting + if (!this->layer()->object()->print()->config().spiral_mode && this->region().config().sparse_infill_density.value > 0) { + // scaling an area requires two calls! + double min_area = scale_(scale_(this->region().config().minimum_sparse_infill_area.value)); + ExPolygons small_regions{}; + sparse.erase(std::remove_if(sparse.begin(), sparse.end(), [min_area, &small_regions](ExPolygon& ex_polygon) { + if (ex_polygon.area() <= min_area) { + small_regions.push_back(ex_polygon); + return true; + } + return false; + }), sparse.end()); + + if (!small_regions.empty()) { + shells = union_ex(shells, small_regions); + } + } + // m_fill_surfaces.remove_types({ stBottomBridge, stBottom, stTop, stInternal, stInternalSolid }); this->fill_surfaces.clear(); reserve_more(this->fill_surfaces.surfaces, shells.size() + sparse.size() + bridges.size() + bottoms.size() + tops.size()); @@ -792,12 +810,10 @@ void LayerRegion::prepare_fill_surfaces() surface.surface_type = stInternal; } - // turn too small internal regions into solid regions according to the user setting - if (! spiral_mode && this->region().config().sparse_infill_density.value > 0) { - // scaling an area requires two calls! - double min_area = scale_(scale_(this->region().config().minimum_sparse_infill_area.value)); + if (!spiral_mode && fabs(this->region().config().sparse_infill_density.value - 100.) < EPSILON) { + // Turn all internal sparse infill into solid infill, if sparse_infill_density is 100% for (Surface &surface : this->fill_surfaces.surfaces) - if (surface.surface_type == stInternal && surface.area() <= min_area) + if (surface.surface_type == stInternal) surface.surface_type = stInternalSolid; } diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index e8f9219940..cecda027f8 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1726,7 +1726,7 @@ def = this->add("filament_loading_speed", coFloats); def = this->add("sparse_infill_density", coPercent); def->label = L("Sparse infill density"); def->category = L("Strength"); - def->tooltip = L("Density of internal sparse infill, 100% means solid throughout"); + def->tooltip = L("Density of internal sparse infill, 100% turns all sparse infill into solid infill and internal solid infill pattern will be used"); def->sidetext = L("%"); def->min = 0; def->max = 100; @@ -5711,12 +5711,6 @@ std::map validate(const FullPrintConfig &cfg, bool und error_message.emplace("internal_solid_infill_pattern", L("invalid value ") + cfg.internal_solid_infill_pattern.serialize()); } - // --fill-density - if (fabs(cfg.sparse_infill_density.value - 100.) < EPSILON && - ! print_config_def.get("top_surface_pattern")->has_enum_value(cfg.sparse_infill_pattern.serialize())) { - error_message.emplace("sparse_infill_pattern", cfg.sparse_infill_pattern.serialize() + L(" doesn't work at 100%% density ")); - } - // --skirt-height if (cfg.skirt_height < 0) { error_message.emplace("skirt_height", L("invalid value ") + std::to_string(cfg.skirt_height)); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index d3ccbfbb34..092427fd04 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -3315,6 +3315,13 @@ void PrintObject::combine_infill() const bool enable_combine_infill = region.config().infill_combination.value; if (enable_combine_infill == false || region.config().sparse_infill_density == 0.) continue; + + // Support internal solid infill when sparse_infill_density is 100% + const bool use_solid_infill = fabs(region.config().sparse_infill_density.value - 100.) < EPSILON; + const SurfaceType surface_type = use_solid_infill ? stInternalSolid : stInternal; + const InfillPattern infill_pattern = use_solid_infill ? region.config().internal_solid_infill_pattern : + region.config().sparse_infill_pattern; + // Limit the number of combined layers to the maximum height allowed by this regions' nozzle. //FIXME limit the layer height to max_layer_height double nozzle_diameter = std::min( @@ -3361,10 +3368,10 @@ void PrintObject::combine_infill() layerms.emplace_back(m_layers[i]->regions()[region_id]); // We need to perform a multi-layer intersection, so let's split it in pairs. // Initialize the intersection with the candidates of the lowest layer. - ExPolygons intersection = to_expolygons(layerms.front()->fill_surfaces.filter_by_type(stInternal)); + ExPolygons intersection = to_expolygons(layerms.front()->fill_surfaces.filter_by_type(surface_type)); // Start looping from the second layer and intersect the current intersection with it. for (size_t i = 1; i < layerms.size(); ++ i) - intersection = intersection_ex(layerms[i]->fill_surfaces.filter_by_type(stInternal), intersection); + intersection = intersection_ex(layerms[i]->fill_surfaces.filter_by_type(surface_type), intersection); double area_threshold = layerms.front()->infill_area_threshold(); if (! intersection.empty() && area_threshold > 0.) intersection.erase(std::remove_if(intersection.begin(), intersection.end(), @@ -3384,21 +3391,21 @@ void PrintObject::combine_infill() 0.5f * layerms.back()->flow(frPerimeter).scaled_width() + // Because fill areas for rectilinear and honeycomb are grown // later to overlap perimeters, we need to counteract that too. - ((region.config().sparse_infill_pattern == ipRectilinear || - region.config().sparse_infill_pattern == ipMonotonic || - region.config().sparse_infill_pattern == ipGrid || - region.config().sparse_infill_pattern == ipLine || - region.config().sparse_infill_pattern == ipHoneycomb) ? 1.5f : 0.5f) * + ((infill_pattern == ipRectilinear || + infill_pattern == ipMonotonic || + infill_pattern == ipGrid || + infill_pattern == ipLine || + infill_pattern == ipHoneycomb) ? 1.5f : 0.5f) * layerms.back()->flow(frSolidInfill).scaled_width(); for (ExPolygon &expoly : intersection) polygons_append(intersection_with_clearance, offset(expoly, clearance_offset)); for (LayerRegion *layerm : layerms) { - Polygons internal = to_polygons(std::move(layerm->fill_surfaces.filter_by_type(stInternal))); - layerm->fill_surfaces.remove_type(stInternal); - layerm->fill_surfaces.append(diff_ex(internal, intersection_with_clearance), stInternal); + Polygons internal = to_polygons(std::move(layerm->fill_surfaces.filter_by_type(surface_type))); + layerm->fill_surfaces.remove_type(surface_type); + layerm->fill_surfaces.append(diff_ex(internal, intersection_with_clearance), surface_type); if (layerm == layerms.back()) { // Apply surfaces back with adjusted depth to the uppermost layer. - Surface templ(stInternal, ExPolygon()); + Surface templ(surface_type, ExPolygon()); templ.thickness = 0.; for (LayerRegion *layerm2 : layerms) templ.thickness += layerm2->layer()->height; diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 64a0ac84ef..069eb4fb36 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -419,43 +419,6 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con } } - if (config->option("sparse_infill_density")->value == 100) { - std::string sparse_infill_pattern = config->option>("sparse_infill_pattern")->serialize(); - const auto &top_fill_pattern_values = config->def()->get("top_surface_pattern")->enum_values; - bool correct_100p_fill = std::find(top_fill_pattern_values.begin(), top_fill_pattern_values.end(), sparse_infill_pattern) != top_fill_pattern_values.end(); - if (!correct_100p_fill) { - // get sparse_infill_pattern name from enum_labels for using this one at dialog_msg - const ConfigOptionDef *fill_pattern_def = config->def()->get("sparse_infill_pattern"); - assert(fill_pattern_def != nullptr); - auto it_pattern = std::find(fill_pattern_def->enum_values.begin(), fill_pattern_def->enum_values.end(), sparse_infill_pattern); - assert(it_pattern != fill_pattern_def->enum_values.end()); - if (it_pattern != fill_pattern_def->enum_values.end()) { - wxString msg_text = GUI::format_wxstr(_L("%1% infill pattern doesn't support 100%% density."), - _(fill_pattern_def->enum_labels[it_pattern - fill_pattern_def->enum_values.begin()])); - if (is_global_config) - msg_text += "\n" + _L("Switch to rectilinear pattern?\n" - "Yes - switch to rectilinear pattern automaticlly\n" - "No - reset density to default non 100% value automaticlly") + "\n"; - MessageDialog dialog(m_msg_dlg_parent, msg_text, "", - wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK) ); - DynamicPrintConfig new_conf = *config; - is_msg_dlg_already_exist = true; - auto answer = dialog.ShowModal(); - if (!is_global_config || answer == wxID_YES) { - new_conf.set_key_value("sparse_infill_pattern", new ConfigOptionEnum(ipRectilinear)); - sparse_infill_density = 100; - } - else - sparse_infill_density = wxGetApp().preset_bundle->prints.get_selected_preset().config.option("sparse_infill_density")->value; - new_conf.set_key_value("sparse_infill_density", new ConfigOptionPercent(sparse_infill_density)); - apply(config, &new_conf); - if (cb_value_change) - cb_value_change("sparse_infill_density", sparse_infill_density); - is_msg_dlg_already_exist = false; - } - } - } - // BBS static const char* keys[] = { "support_filament", "support_interface_filament"}; for (int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) { diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 3bf9d55237..94eb6e4579 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1927,13 +1927,13 @@ void TabPrint::build() optgroup->append_single_option_line("bottom_surface_pattern", "fill-patterns#Infill of the top surface and bottom surface"); optgroup->append_single_option_line("bottom_shell_layers"); optgroup->append_single_option_line("bottom_shell_thickness"); - optgroup->append_single_option_line("internal_solid_infill_pattern"); optgroup = page->new_optgroup(L("Infill"), L"param_infill"); optgroup->append_single_option_line("sparse_infill_density"); optgroup->append_single_option_line("sparse_infill_pattern", "fill-patterns#infill types and their properties of sparse"); optgroup->append_single_option_line("infill_anchor"); optgroup->append_single_option_line("infill_anchor_max"); + optgroup->append_single_option_line("internal_solid_infill_pattern"); optgroup->append_single_option_line("filter_out_gap_fill");