From 3153d9612e8279404a6d886c12abe2781f4761dd Mon Sep 17 00:00:00 2001 From: supermerill Date: Sun, 8 Aug 2021 19:18:10 +0200 Subject: [PATCH] new setting to remove unwanted bottom/top fill on slopes supermerill/SuperSlicer#253 supermerill/SuperSlicer#426 supermerill/SuperSlicer#1090 --- resources/ui_layout/print.ui | 1 + src/libslic3r/Preset.cpp | 1 + src/libslic3r/PrintConfig.cpp | 14 ++++++++ src/libslic3r/PrintConfig.hpp | 2 ++ src/libslic3r/PrintObject.cpp | 66 ++++++++++++++++++++++++++++++++--- 5 files changed, 80 insertions(+), 4 deletions(-) diff --git a/resources/ui_layout/print.ui b/resources/ui_layout/print.ui index 34c07613d..f5e1bd710 100644 --- a/resources/ui_layout/print.ui +++ b/resources/ui_layout/print.ui @@ -14,6 +14,7 @@ group:Horizontal shells setting:bottom_solid_min_thickness end_line top_bottom_shell_thickness_explanation + setting:solid_over_perimeters setting:enforce_full_fill_volume group:Quality line:Only one perimeter on Top surfaces diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 7befb0d10..be21b8b89 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -446,6 +446,7 @@ const std::vector& Preset::print_options() "top_solid_min_thickness", "bottom_solid_layers", "bottom_solid_min_thickness", + "solid_over_perimeters", "duplicate_distance", "extra_perimeters", "extra_perimeters_odd_layers", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index e90e099b5..73926cec7 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -3640,6 +3640,20 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(false)); + def = this->add("solid_over_perimeters", coInt); + def->label = L("Max perimeters layer for solid infill"); + def->category = OptionCategory::perimeter; + def->tooltip = L("When you have a medium/hight number of top/bottom solid layers, and a low/medium of perimeters," + " then it have to put some solid infill inside the part to have enough solid layers." + "\nBy setting this to somethign higher than 0, you can remove this 'inside filling'." + " This number allow to keep some if there is a low number of perimeter over the void." + "\nIf this setting is equal or higher than the top/bottom solid layer count, it won't evict anything." + "\nIf this setting is set to 1, it will evict all solid fill are are only over perimeters." + "\nSet it to 0 to disable."); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionInt(2)); + def = this->add("support_material", coBool); def->label = L("Generate support material"); def->category = OptionCategory::support; diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index f68dabc30..d6b165be9 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -850,6 +850,7 @@ public: ConfigOptionFloatOrPercent solid_infill_extrusion_width; ConfigOptionInt solid_infill_every_layers; ConfigOptionFloatOrPercent solid_infill_speed; + ConfigOptionInt solid_over_perimeters; ConfigOptionInt print_temperature; ConfigOptionBool thin_perimeters; ConfigOptionBool thin_perimeters_all; @@ -960,6 +961,7 @@ protected: OPT_PTR(solid_infill_extrusion_width); OPT_PTR(solid_infill_every_layers); OPT_PTR(solid_infill_speed); + OPT_PTR(solid_over_perimeters); OPT_PTR(print_temperature); OPT_PTR(thin_perimeters); OPT_PTR(thin_perimeters_all); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 4ddcb9269..f58efd88e 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -778,6 +778,7 @@ namespace Slic3r { || opt_key == "solid_infill_below_area" || opt_key == "solid_infill_extruder" || opt_key == "solid_infill_every_layers" + || opt_key == "solid_over_perimeters" || opt_key == "top_solid_layers" || opt_key == "top_solid_min_thickness") { steps.emplace_back(posPrepareInfill); @@ -1479,7 +1480,11 @@ namespace Slic3r { { // Collected polygons, offsetted Polygons top_surfaces; + Polygons top_fill_surfaces; + Polygons top_perimeter_surfaces; Polygons bottom_surfaces; + Polygons bottom_fill_surfaces; + Polygons bottom_perimeter_surfaces; Polygons holes; }; bool spiral_vase = this->print()->config().spiral_vase.value; @@ -1538,10 +1543,14 @@ namespace Slic3r { // Top surfaces. append(cache.top_surfaces, offset(to_expolygons(layerm.slices().filter_by_type(stPosTop | stDensSolid)), min_perimeter_infill_spacing)); append(cache.top_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_type(stPosTop | stDensSolid)), min_perimeter_infill_spacing)); + append(cache.top_fill_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_type(stPosTop | stDensSolid)), min_perimeter_infill_spacing)); + append(cache.top_perimeter_surfaces, to_polygons(layerm.slices().filter_by_type(stPosTop | stDensSolid))); // Bottom surfaces. const SurfaceType surfaces_bottom[2] = { stPosBottom | stDensSolid, stPosBottom | stDensSolid | stModBridge }; append(cache.bottom_surfaces, offset(to_expolygons(layerm.slices().filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing)); append(cache.bottom_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing)); + append(cache.bottom_fill_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing)); + append(cache.bottom_perimeter_surfaces, to_polygons(layerm.slices().filter_by_type(stPosTop | stDensSolid))); // Calculate the maximum perimeter offset as if the slice was extruded with a single extruder only. // First find the maxium number of perimeters per region slice. unsigned int perimeters = 0; @@ -1596,13 +1605,16 @@ namespace Slic3r { //FIXME Improve the heuristics for a grain size. size_t grain_size = std::max(num_layers / 16, size_t(1)); + //solid_over_perimeters value, to remove solid fill where there's only perimeters on multiple layers + int nb_perimeter_layers_for_solid_fill = region.config().solid_over_perimeters.value; + if (!top_bottom_surfaces_all_regions) { // This is either a single material print, or a multi-material print and interface_shells are enabled, meaning that the vertical shell thickness // is calculated over a single material. BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << idx_region << " in parallel - start : cache top / bottom"; tbb::parallel_for( tbb::blocked_range(0, num_layers, grain_size), - [this, idx_region, &cache_top_botom_regions](const tbb::blocked_range& range) { + [this, idx_region, &cache_top_botom_regions, nb_perimeter_layers_for_solid_fill](const tbb::blocked_range& range) { for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) { m_print->throw_if_canceled(); Layer& layer = *m_layers[idx_layer]; @@ -1612,10 +1624,18 @@ namespace Slic3r { auto& cache = cache_top_botom_regions[idx_layer]; cache.top_surfaces = offset(to_expolygons(layerm.slices().filter_by_type(stPosTop | stDensSolid)), min_perimeter_infill_spacing); append(cache.top_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_type(stPosTop | stDensSolid)), min_perimeter_infill_spacing)); + if (nb_perimeter_layers_for_solid_fill != 0) { + cache.top_fill_surfaces = offset(to_expolygons(layerm.fill_surfaces.filter_by_type(stPosTop | stDensSolid)), min_perimeter_infill_spacing); + cache.top_perimeter_surfaces = to_polygons(layerm.slices().filter_by_type(stPosTop | stDensSolid)); + } // Bottom surfaces. const SurfaceType surfaces_bottom[2] = { stPosBottom | stDensSolid, stPosBottom | stDensSolid | stModBridge }; cache.bottom_surfaces = offset(to_expolygons(layerm.slices().filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing); append(cache.bottom_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing)); + if (nb_perimeter_layers_for_solid_fill != 0) { + cache.bottom_fill_surfaces = offset(to_expolygons(layerm.fill_surfaces.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing); + cache.bottom_perimeter_surfaces = to_polygons(layerm.slices().filter_by_types(surfaces_bottom, 2)); + } // Holes over all regions. Only collect them once, they are valid for all idx_region iterations. if (cache.holes.empty()) { for (size_t idx_region = 0; idx_region < layer.regions().size(); ++idx_region) @@ -1630,7 +1650,7 @@ namespace Slic3r { BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << idx_region << " in parallel - start : ensure vertical wall thickness"; tbb::parallel_for( tbb::blocked_range(0, num_layers, grain_size), - [this, idx_region, &cache_top_botom_regions] + [this, idx_region, &cache_top_botom_regions, nb_perimeter_layers_for_solid_fill] (const tbb::blocked_range& range) { // printf("discover_vertical_shells from %d to %d\n", range.begin(), range.end()); for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) { @@ -1654,6 +1674,8 @@ namespace Slic3r { coord_t infill_line_spacing = solid_infill_flow.scaled_spacing(); // Find a union of perimeters below / above this surface to guarantee a minimum shell thickness. Polygons shell; + Polygons fill_shell; + Polygons max_perimeter_shell; // for nb_perimeter_layers_for_solid_fill Polygons holes; #ifdef SLIC3R_DEBUG_SLICE_PROCESSING ExPolygons shell_ex; @@ -1701,6 +1723,16 @@ namespace Slic3r { // than running the union_ all at once. shell = union_(shell, false); } + if (nb_perimeter_layers_for_solid_fill != 0) { + if (!cache.top_fill_surfaces.empty()) { + polygons_append(fill_shell, cache.top_fill_surfaces); + fill_shell = union_(fill_shell, false); + } + if (nb_perimeter_layers_for_solid_fill > 1 && i - idx_layer < nb_perimeter_layers_for_solid_fill) { + polygons_append(max_perimeter_shell, cache.top_perimeter_surfaces); + max_perimeter_shell = union_(max_perimeter_shell, false); + } + } } } if (int n_bottom_layers = region_config.bottom_solid_layers.value; n_bottom_layers > 0) { @@ -1720,6 +1752,16 @@ namespace Slic3r { // than running the union_ all at once. shell = union_(shell, false); } + if (nb_perimeter_layers_for_solid_fill != 0) { + if (!cache.bottom_fill_surfaces.empty()) { + polygons_append(fill_shell, cache.bottom_fill_surfaces); + fill_shell = union_(fill_shell, false); + } + if (nb_perimeter_layers_for_solid_fill > 1 && idx_layer - i < nb_perimeter_layers_for_solid_fill) { + polygons_append(max_perimeter_shell, cache.bottom_perimeter_surfaces); + max_perimeter_shell = union_(max_perimeter_shell, false); + } + } } } #ifdef SLIC3R_DEBUG_SLICE_PROCESSING @@ -1780,11 +1822,27 @@ namespace Slic3r { svg.Close(); } #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ - // Trim the shells region by the internal & internal void surfaces. const SurfaceType surfaceTypesInternal[] = { stPosInternal | stDensSparse, stPosInternal | stDensVoid, stPosInternal | stDensSolid }; const Polygons polygonsInternal = to_polygons(layerm->fill_surfaces.filter_by_types(surfaceTypesInternal, 3)); - shell = intersection(shell, polygonsInternal, true); + { + Polygons shell_internal = intersection(shell, polygonsInternal, true); + //check if a polygon is only over perimeter, in this case evict it (depends from nb_perimeter_layers_for_solid_fill value) + if (nb_perimeter_layers_for_solid_fill != 0) { + for (int i = 0; i < shell_internal.size(); i++) { + if (intersection({ shell_internal[i] }, fill_shell, false).empty()) { + if (nb_perimeter_layers_for_solid_fill < 2 || intersection({ shell_internal[i] }, max_perimeter_shell, false).empty()) { + shell_internal.erase(shell_internal.begin() + i); + i--; + } + } + } + if (shell_internal.empty()) + continue; + } + + shell = std::move(shell_internal); + } polygons_append(shell, diff(polygonsInternal, holes)); if (shell.empty()) continue;