new setting to remove unwanted bottom/top fill on slopes

supermerill/SuperSlicer#253
supermerill/SuperSlicer#426
supermerill/SuperSlicer#1090
This commit is contained in:
supermerill 2021-08-08 19:18:10 +02:00
parent 2384b2fbdd
commit 3153d9612e
5 changed files with 80 additions and 4 deletions

View File

@ -14,6 +14,7 @@ group:Horizontal shells
setting:bottom_solid_min_thickness setting:bottom_solid_min_thickness
end_line end_line
top_bottom_shell_thickness_explanation top_bottom_shell_thickness_explanation
setting:solid_over_perimeters
setting:enforce_full_fill_volume setting:enforce_full_fill_volume
group:Quality group:Quality
line:Only one perimeter on Top surfaces line:Only one perimeter on Top surfaces

View File

@ -446,6 +446,7 @@ const std::vector<std::string>& Preset::print_options()
"top_solid_min_thickness", "top_solid_min_thickness",
"bottom_solid_layers", "bottom_solid_layers",
"bottom_solid_min_thickness", "bottom_solid_min_thickness",
"solid_over_perimeters",
"duplicate_distance", "duplicate_distance",
"extra_perimeters", "extra_perimeters",
"extra_perimeters_odd_layers", "extra_perimeters_odd_layers",

View File

@ -3640,6 +3640,20 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false)); 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 = this->add("support_material", coBool);
def->label = L("Generate support material"); def->label = L("Generate support material");
def->category = OptionCategory::support; def->category = OptionCategory::support;

View File

@ -850,6 +850,7 @@ public:
ConfigOptionFloatOrPercent solid_infill_extrusion_width; ConfigOptionFloatOrPercent solid_infill_extrusion_width;
ConfigOptionInt solid_infill_every_layers; ConfigOptionInt solid_infill_every_layers;
ConfigOptionFloatOrPercent solid_infill_speed; ConfigOptionFloatOrPercent solid_infill_speed;
ConfigOptionInt solid_over_perimeters;
ConfigOptionInt print_temperature; ConfigOptionInt print_temperature;
ConfigOptionBool thin_perimeters; ConfigOptionBool thin_perimeters;
ConfigOptionBool thin_perimeters_all; ConfigOptionBool thin_perimeters_all;
@ -960,6 +961,7 @@ protected:
OPT_PTR(solid_infill_extrusion_width); OPT_PTR(solid_infill_extrusion_width);
OPT_PTR(solid_infill_every_layers); OPT_PTR(solid_infill_every_layers);
OPT_PTR(solid_infill_speed); OPT_PTR(solid_infill_speed);
OPT_PTR(solid_over_perimeters);
OPT_PTR(print_temperature); OPT_PTR(print_temperature);
OPT_PTR(thin_perimeters); OPT_PTR(thin_perimeters);
OPT_PTR(thin_perimeters_all); OPT_PTR(thin_perimeters_all);

View File

@ -778,6 +778,7 @@ namespace Slic3r {
|| opt_key == "solid_infill_below_area" || opt_key == "solid_infill_below_area"
|| opt_key == "solid_infill_extruder" || opt_key == "solid_infill_extruder"
|| opt_key == "solid_infill_every_layers" || opt_key == "solid_infill_every_layers"
|| opt_key == "solid_over_perimeters"
|| opt_key == "top_solid_layers" || opt_key == "top_solid_layers"
|| opt_key == "top_solid_min_thickness") { || opt_key == "top_solid_min_thickness") {
steps.emplace_back(posPrepareInfill); steps.emplace_back(posPrepareInfill);
@ -1479,7 +1480,11 @@ namespace Slic3r {
{ {
// Collected polygons, offsetted // Collected polygons, offsetted
Polygons top_surfaces; Polygons top_surfaces;
Polygons top_fill_surfaces;
Polygons top_perimeter_surfaces;
Polygons bottom_surfaces; Polygons bottom_surfaces;
Polygons bottom_fill_surfaces;
Polygons bottom_perimeter_surfaces;
Polygons holes; Polygons holes;
}; };
bool spiral_vase = this->print()->config().spiral_vase.value; bool spiral_vase = this->print()->config().spiral_vase.value;
@ -1538,10 +1543,14 @@ namespace Slic3r {
// Top surfaces. // 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.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_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. // Bottom surfaces.
const SurfaceType surfaces_bottom[2] = { stPosBottom | stDensSolid, stPosBottom | stDensSolid | stModBridge }; 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.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_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. // 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. // First find the maxium number of perimeters per region slice.
unsigned int perimeters = 0; unsigned int perimeters = 0;
@ -1596,13 +1605,16 @@ namespace Slic3r {
//FIXME Improve the heuristics for a grain size. //FIXME Improve the heuristics for a grain size.
size_t grain_size = std::max(num_layers / 16, size_t(1)); 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) { 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 // 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. // is calculated over a single material.
BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << idx_region << " in parallel - start : cache top / bottom"; BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << idx_region << " in parallel - start : cache top / bottom";
tbb::parallel_for( tbb::parallel_for(
tbb::blocked_range<size_t>(0, num_layers, grain_size), tbb::blocked_range<size_t>(0, num_layers, grain_size),
[this, idx_region, &cache_top_botom_regions](const tbb::blocked_range<size_t>& range) { [this, idx_region, &cache_top_botom_regions, nb_perimeter_layers_for_solid_fill](const tbb::blocked_range<size_t>& range) {
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) { for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) {
m_print->throw_if_canceled(); m_print->throw_if_canceled();
Layer& layer = *m_layers[idx_layer]; Layer& layer = *m_layers[idx_layer];
@ -1612,10 +1624,18 @@ namespace Slic3r {
auto& cache = cache_top_botom_regions[idx_layer]; 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); 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_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. // Bottom surfaces.
const SurfaceType surfaces_bottom[2] = { stPosBottom | stDensSolid, stPosBottom | stDensSolid | stModBridge }; 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); 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_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. // Holes over all regions. Only collect them once, they are valid for all idx_region iterations.
if (cache.holes.empty()) { if (cache.holes.empty()) {
for (size_t idx_region = 0; idx_region < layer.regions().size(); ++idx_region) 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"; BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << idx_region << " in parallel - start : ensure vertical wall thickness";
tbb::parallel_for( tbb::parallel_for(
tbb::blocked_range<size_t>(0, num_layers, grain_size), tbb::blocked_range<size_t>(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<size_t>& range) { (const tbb::blocked_range<size_t>& range) {
// printf("discover_vertical_shells from %d to %d\n", range.begin(), range.end()); // 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) { 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(); 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. // Find a union of perimeters below / above this surface to guarantee a minimum shell thickness.
Polygons shell; Polygons shell;
Polygons fill_shell;
Polygons max_perimeter_shell; // for nb_perimeter_layers_for_solid_fill
Polygons holes; Polygons holes;
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
ExPolygons shell_ex; ExPolygons shell_ex;
@ -1701,6 +1723,16 @@ namespace Slic3r {
// than running the union_ all at once. // than running the union_ all at once.
shell = union_(shell, false); 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) { 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. // than running the union_ all at once.
shell = union_(shell, false); 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 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
@ -1780,11 +1822,27 @@ namespace Slic3r {
svg.Close(); svg.Close();
} }
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
// Trim the shells region by the internal & internal void surfaces. // Trim the shells region by the internal & internal void surfaces.
const SurfaceType surfaceTypesInternal[] = { stPosInternal | stDensSparse, stPosInternal | stDensVoid, stPosInternal | stDensSolid }; const SurfaceType surfaceTypesInternal[] = { stPosInternal | stDensSparse, stPosInternal | stDensVoid, stPosInternal | stDensSolid };
const Polygons polygonsInternal = to_polygons(layerm->fill_surfaces.filter_by_types(surfaceTypesInternal, 3)); 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)); polygons_append(shell, diff(polygonsInternal, holes));
if (shell.empty()) if (shell.empty())
continue; continue;