diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm index 0cda8093b..1de0bdda3 100644 --- a/lib/Slic3r/Config.pm +++ b/lib/Slic3r/Config.pm @@ -191,6 +191,7 @@ sub validate { die "Invalid value for --solid-layers\n" if defined $self->solid_layers && $self->solid_layers < 0; die "Invalid value for --top-solid-layers\n" if $self->top_solid_layers < 0; die "Invalid value for --bottom-solid-layers\n" if $self->bottom_solid_layers < 0; + die "Invalid value for --min-top-bottom-shell-thickness\n" if $self->min_top_bottom_shell_thickness < 0; # --gcode-flavor die "Invalid value for --gcode-flavor\n" diff --git a/lib/Slic3r/GUI/PresetEditor.pm b/lib/Slic3r/GUI/PresetEditor.pm index 09f619b28..13c8cf978 100644 --- a/lib/Slic3r/GUI/PresetEditor.pm +++ b/lib/Slic3r/GUI/PresetEditor.pm @@ -438,7 +438,7 @@ sub options { layer_height first_layer_height adaptive_slicing adaptive_slicing_quality match_horizontal_surfaces perimeters spiral_vase - top_solid_layers min_shell_thickness bottom_solid_layers + top_solid_layers min_shell_thickness min_top_bottom_shell_thickness bottom_solid_layers extra_perimeters avoid_crossing_perimeters thin_walls overhangs seam_position external_perimeters_first fill_density fill_pattern top_infill_pattern bottom_infill_pattern fill_gaps @@ -532,6 +532,8 @@ sub build { $line->append_option($optgroup->get_option('top_solid_layers')); $line->append_option($optgroup->get_option('bottom_solid_layers')); $optgroup->append_line($line); + + $optgroup->append_single_option_line('min_top_bottom_shell_thickness'); } { my $optgroup = $page->new_optgroup('Quality (slower slicing)'); @@ -622,7 +624,7 @@ sub build { $optgroup->append_single_option_line('dont_support_bridges'); } } - + { my $page = $self->add_options_page('Speed', 'time.png'); { @@ -802,11 +804,12 @@ sub _update { $opt_key = "all_keys" if (length($key // '') == 0); my $config = $self->{config}; - if (any { /$opt_key/ } qw(all_keys spiral_vase perimeters top_solid_layers fill_density support_material min_shell_thickness)) { - if ($config->spiral_vase && !($config->perimeters == 1 && $config->min_shell_thickness == 0 && $config->top_solid_layers == 0 && $config->fill_density == 0 && $config->support_material == 0)) { + if (any { /$opt_key/ } qw(all_keys spiral_vase perimeters top_solid_layers fill_density support_material min_shell_thickness min_top_bottom_shell_thickness)) { + if ($config->spiral_vase && !($config->perimeters == 1 && $config->min_shell_thickness == 0 && $config->min_top_bottom_shell_thickness == 0 && $config->top_solid_layers == 0 && $config->fill_density == 0 && $config->support_material == 0)) { my $dialog = Wx::MessageDialog->new($self, "The Spiral Vase mode requires:\n" . "- one perimeter\n" + . "- shell thickness to be 0\n" . "- no top solid layers\n" . "- 0% fill density\n" . "- no support material\n" @@ -816,6 +819,7 @@ sub _update { my $new_conf = Slic3r::Config->new; $new_conf->set("perimeters", 1); $new_conf->set("min_shell_thickness", 0); + $new_conf->set("min_top_bottom_shell_thickness", 0); $new_conf->set("top_solid_layers", 0); $new_conf->set("fill_density", 0); $new_conf->set("support_material", 0); @@ -901,7 +905,7 @@ sub _update { solid_infill_below_area infill_extruder); } - my $have_solid_infill = ($config->top_solid_layers > 0) || ($config->bottom_solid_layers > 0); + my $have_solid_infill = ($config->top_solid_layers > 0) || ($config->bottom_solid_layers > 0) || ($config->min_top_bottom_shell_thickness > 0); if (any { /$opt_key/ } qw(all_keys top_solid_layers bottom_solid_layers)) { # solid_infill_extruder uses the same logic as in Print::extruders() $self->get_field($_)->toggle($have_solid_infill) @@ -919,7 +923,7 @@ sub _update { $self->get_field('gap_fill_speed')->toggle($have_perimeters && $have_infill && $config->fill_gaps); } - my $have_top_solid_infill = ($config->top_solid_layers > 0) || ($config->min_shell_thickness > 0); + my $have_top_solid_infill = ($config->top_solid_layers > 0) || ($config->min_top_bottom_shell_thickness > 0); $self->get_field($_)->toggle($have_top_solid_infill) for qw(top_infill_extrusion_width top_solid_infill_speed); diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 3bd01a1cd..be1217167 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -3,6 +3,7 @@ package Slic3r::Print::Object; use strict; use warnings; +use POSIX; use List::Util qw(min max sum first any); use Slic3r::Flow ':roles'; use Slic3r::Geometry qw(X Y Z PI scale unscale chained_path epsilon); @@ -387,10 +388,21 @@ sub discover_horizontal_shells { ]; next if !@$solid; Slic3r::debugf "Layer %d has %s surfaces\n", $i, ($type == S_TYPE_TOP) ? 'top' : 'bottom'; - + my $solid_layers = ($type == S_TYPE_TOP) ? $layerm->region->config->top_solid_layers : $layerm->region->config->bottom_solid_layers; + + if ($layerm->region->config->min_top_bottom_shell_thickness > 0) { + my $current_shell_thickness = $solid_layers * $self->get_layer($i)->height; + my $minimum_shell_thickness = $layerm->region->config->min_top_bottom_shell_thickness; + + while ($minimum_shell_thickness - $current_shell_thickness > epsilon) { + $solid_layers++; + $current_shell_thickness = $solid_layers * $self->get_layer($i)->height; + } + } + NEIGHBOR: for (my $n = ($type == S_TYPE_TOP) ? $i-1 : $i+1; abs($n - $i) <= $solid_layers-1; ($type == S_TYPE_TOP) ? $n-- : $n++) { diff --git a/xs/src/libslic3r/LayerRegion.cpp b/xs/src/libslic3r/LayerRegion.cpp index 88fa6fb1d..49e1775ea 100644 --- a/xs/src/libslic3r/LayerRegion.cpp +++ b/xs/src/libslic3r/LayerRegion.cpp @@ -237,26 +237,25 @@ LayerRegion::prepare_fill_surfaces() the only meaningful information returned by psPerimeters. */ // if no solid layers are requested, turn top/bottom surfaces to internal - if (this->region()->config.min_shell_thickness == 0) { - if (this->region()->config.top_solid_layers == 0) { - for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) { - if (surface->surface_type == stTop) { - if (this->layer()->object()->config.infill_only_where_needed) { - surface->surface_type = stInternalVoid; - } else { - surface->surface_type = stInternal; - } + if (this->region()->config.top_solid_layers == 0 && this->region()->config.min_top_bottom_shell_thickness <= 0) { + for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) { + if (surface->surface_type == stTop) { + if (this->layer()->object()->config.infill_only_where_needed) { + surface->surface_type = stInternalVoid; + } else { + surface->surface_type = stInternal; } } } - if (this->region()->config.bottom_solid_layers == 0) { - for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) { - if (surface->surface_type == stBottom || surface->surface_type == stBottomBridge) - surface->surface_type = stInternal; - } + } + + if (this->region()->config.bottom_solid_layers == 0 && this->region()->config.min_top_bottom_shell_thickness <= 0) { + for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) { + if (surface->surface_type == stBottom || surface->surface_type == stBottomBridge) + surface->surface_type = stInternal; } } - + // turn too small internal regions into solid regions according to the user setting const float &fill_density = this->region()->config.fill_density; if (fill_density > 0 && fill_density < 100) { diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index d413806f9..73c5a25ce 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -338,7 +338,9 @@ Print::object_extruders() const if ((*region)->config.fill_density.value > 0) extruders.insert((*region)->config.infill_extruder - 1); - if ((*region)->config.top_solid_layers.value > 0 || (*region)->config.bottom_solid_layers.value > 0) + if ((*region)->config.top_solid_layers.value > 0 + || (*region)->config.bottom_solid_layers.value > 0 + || (*region)->config.min_top_bottom_shell_thickness.value > 0) extruders.insert((*region)->config.solid_infill_extruder - 1); } diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 533456de1..88a0e2494 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -837,6 +837,15 @@ PrintConfigDef::PrintConfigDef() def->min = 0; def->default_value = new ConfigOptionFloat(0); + def = this->add("min_top_bottom_shell_thickness", coFloat); + def->label = "Minimum shell thickness"; + def->category = "Layers and Perimeters"; + def->sidetext = "mm"; + def->tooltip = "Alternative method of configuring top/bottom layers. If this is above 0 extra solid layers will be generated when necessary"; + def->cli = "min-vertical-shell-thickness=f"; + def->min = 0; + def->default_value = new ConfigOptionFloat(0); + def = this->add("min_layer_height", coFloats); def->label = "Min"; def->tooltip = "This is the lowest printable layer height for this extruder and limits the resolution for adaptive slicing. Typical values are 0.1 or 0.05."; diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 5d9d096e9..02f6887a4 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -256,6 +256,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig ConfigOptionFloatOrPercent infill_overlap; ConfigOptionFloat infill_speed; ConfigOptionFloat min_shell_thickness; + ConfigOptionFloat min_top_bottom_shell_thickness; ConfigOptionBool overhangs; ConfigOptionInt perimeter_extruder; ConfigOptionFloatOrPercent perimeter_extrusion_width; @@ -314,7 +315,8 @@ class PrintRegionConfig : public virtual StaticPrintConfig OPT_PTR(top_infill_pattern); OPT_PTR(top_solid_infill_speed); OPT_PTR(top_solid_layers); - + OPT_PTR(min_top_bottom_shell_thickness); + return NULL; }; }; diff --git a/xs/src/libslic3r/PrintRegion.cpp b/xs/src/libslic3r/PrintRegion.cpp index 55f91f057..6c5c6ed46 100644 --- a/xs/src/libslic3r/PrintRegion.cpp +++ b/xs/src/libslic3r/PrintRegion.cpp @@ -99,6 +99,7 @@ PrintRegion::invalidate_state_by_config(const PrintConfigBase &config) || opt_key == "solid_infill_every_layers" || opt_key == "bottom_solid_layers" || opt_key == "top_solid_layers" + || opt_key == "min_top_bottom_shell_thickness" || opt_key == "min_shell_thickness" || opt_key == "infill_extruder" || opt_key == "solid_infill_extruder"