mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-12 03:39:02 +08:00
* Added Minimum shell thickness option -Added the option to libslic3r -Created some of the necessary checks for illegal values * Enforce min_shell_thickness as 0 when spiral vase is enabled -This could be switched to match the extrusion width, but we already know there will only be 1 perimeter so this is probably more logical * Feature is implemented -Added a method in PerimeterGenerator to determine the amount of perimeters needed to meet min_shell_thickness * Added a test in perimeters.t * Fixed styling as requested -Removed the magic number in PerimeterGenerator::num_loops() -Added more test cases in perimeters.t -Added documentation of the new feature in slic3r.pl and README.md * Implemented requested changes -Removed the num_loops function from PerimeterGenerator -Added a scalled min_shell_thickness variable to PerimeterGenerator -Changed the loop_number logic to use a previously defined variable loops * Resolved more implementation issues -Added min shell to invalidate state method -Created additional checks in PresetEditor and LayerRegion for min shell -Fixed the tooltip to be more descriptive
This commit is contained in:
parent
61ace41351
commit
f3b590911d
@ -216,6 +216,7 @@ Contributions by Henrik Brix Andersen, Vojtech Bubnik, Nicolas Dandrimont, Mark
|
||||
--perimeters Number of perimeters/horizontal skins (range: 0+, default: 3)
|
||||
--top-solid-layers Number of solid layers to do for top surfaces (range: 0+, default: 3)
|
||||
--bottom-solid-layers Number of solid layers to do for bottom surfaces (range: 0+, default: 3)
|
||||
--min-shell-thickness Minimum thickness of all solid shells (range: 0+, default: 0)
|
||||
--solid-layers Shortcut for setting the two options above at once
|
||||
--fill-density Infill density (range: 0%-100%, default: 40%)
|
||||
--fill-angle Infill angle in degrees (range: 0-90, default: 45)
|
||||
|
@ -176,6 +176,9 @@ sub validate {
|
||||
die "Invalid value for --filament-diameter\n"
|
||||
if grep $_ < 1, @{$self->filament_diameter};
|
||||
|
||||
die "Invalid value for --min-shell-thickness\n"
|
||||
if $self->min_shell_thickness < 0;
|
||||
|
||||
# --nozzle-diameter
|
||||
die "Invalid value for --nozzle-diameter\n"
|
||||
if grep $_ < 0, @{$self->nozzle_diameter};
|
||||
@ -253,7 +256,10 @@ sub validate {
|
||||
|
||||
die "Can't make less than one perimeter when spiral vase mode is enabled\n"
|
||||
if $self->perimeters < 1;
|
||||
|
||||
|
||||
die "Minimum shell thickness should be 0 when spiral vase mode is enabled\n"
|
||||
if $self->min_shell_thickness > 0;
|
||||
|
||||
die "Spiral vase mode can only print hollow objects, so you need to set Fill density to 0\n"
|
||||
if $self->fill_density > 0;
|
||||
|
||||
|
@ -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 bottom_solid_layers
|
||||
top_solid_layers min_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
|
||||
@ -521,6 +521,7 @@ sub build {
|
||||
{
|
||||
my $optgroup = $page->new_optgroup('Vertical shells');
|
||||
$optgroup->append_single_option_line('perimeters');
|
||||
$optgroup->append_single_option_line('min_shell_thickness');
|
||||
$optgroup->append_single_option_line('spiral_vase');
|
||||
}
|
||||
{
|
||||
@ -800,8 +801,9 @@ sub _update {
|
||||
my $opt_key = $key;
|
||||
$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)) {
|
||||
if ($config->spiral_vase && !($config->perimeters == 1 && $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)) {
|
||||
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)) {
|
||||
my $dialog = Wx::MessageDialog->new($self,
|
||||
"The Spiral Vase mode requires:\n"
|
||||
. "- one perimeter\n"
|
||||
@ -813,6 +815,7 @@ sub _update {
|
||||
if ($dialog->ShowModal() == wxID_YES) {
|
||||
my $new_conf = Slic3r::Config->new;
|
||||
$new_conf->set("perimeters", 1);
|
||||
$new_conf->set("min_shell_thickness", 0);
|
||||
$new_conf->set("top_solid_layers", 0);
|
||||
$new_conf->set("fill_density", 0);
|
||||
$new_conf->set("support_material", 0);
|
||||
@ -874,8 +877,7 @@ sub _update {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
my $have_perimeters = $config->perimeters > 0;
|
||||
my $have_perimeters = ($config->perimeters > 0) || ($config->min_shell_thickness > 0);
|
||||
if (any { /$opt_key/ } qw(all_keys perimeters)) {
|
||||
$self->get_field($_)->toggle($have_perimeters)
|
||||
for qw(extra_perimeters thin_walls overhangs seam_position external_perimeters_first
|
||||
@ -917,7 +919,8 @@ 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;
|
||||
my $have_top_solid_infill = ($config->top_solid_layers > 0) || ($config->min_shell_thickness > 0);
|
||||
|
||||
$self->get_field($_)->toggle($have_top_solid_infill)
|
||||
for qw(top_infill_extrusion_width top_solid_infill_speed);
|
||||
|
||||
|
@ -439,6 +439,7 @@ $j
|
||||
--perimeters Number of perimeters/horizontal skins (range: 0+, default: $config->{perimeters})
|
||||
--top-solid-layers Number of solid layers to do for top surfaces (range: 0+, default: $config->{top_solid_layers})
|
||||
--bottom-solid-layers Number of solid layers to do for bottom surfaces (range: 0+, default: $config->{bottom_solid_layers})
|
||||
--min-shell-thickness Minimum thickness of all solid shells (range: 0+, default: 0)
|
||||
--solid-layers Shortcut for setting the two options above at once
|
||||
--fill-density Infill density (range: 0%-100%, default: $config->{fill_density}%)
|
||||
--fill-angle Infill angle in degrees (range: 0-90, default: $config->{fill_angle})
|
||||
|
@ -1,4 +1,4 @@
|
||||
use Test::More tests => 63;
|
||||
use Test::More tests => 66;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
@ -313,6 +313,54 @@ use Slic3r::Test;
|
||||
ok !(grep { $_ % $config->perimeters } values %perimeters), 'no superfluous extra perimeters';
|
||||
}
|
||||
|
||||
{
|
||||
my $config = Slic3r::Config->new_from_defaults;
|
||||
$config->set('skirts', 0);
|
||||
$config->set('perimeters', 3);
|
||||
$config->set('min_shell_thickness', 3);
|
||||
$config->set('layer_height', 0.4);
|
||||
$config->set('first_layer_height', 0.35);
|
||||
$config->set('extra_perimeters', 0);
|
||||
$config->set('first_layer_extrusion_width', 0.5);
|
||||
$config->set('perimeter_extrusion_width', 0.5);
|
||||
$config->set('external_perimeter_extrusion_width', 0.5);
|
||||
$config->set('cooling', 0); # to prevent speeds from being altered
|
||||
$config->set('first_layer_speed', '100%'); # to prevent speeds from being altered
|
||||
$config->set('perimeter_speed', 99);
|
||||
$config->set('external_perimeter_speed', 99);
|
||||
$config->set('small_perimeter_speed', 99);
|
||||
$config->set('thin_walls', 0);
|
||||
|
||||
my $test = sub {
|
||||
my $print = Slic3r::Test::init_print('ipadstand', config => $config);
|
||||
my %perimeters = (); # z => number of loops
|
||||
my $in_loop = 0;
|
||||
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
|
||||
my ($self, $cmd, $args, $info) = @_;
|
||||
|
||||
if ($info->{extruding} && $info->{dist_XY} > 0 && ($args->{F} // $self->F) == $config->perimeter_speed*60) {
|
||||
$perimeters{$self->Z}++ if !$in_loop;
|
||||
$in_loop = 1;
|
||||
} else {
|
||||
$in_loop = 0;
|
||||
}
|
||||
});
|
||||
ok !(grep { $_ % $config->min_shell_thickness/$config->perimeter_extrusion_width } values %perimeters), 'should be 6 perimeters';
|
||||
};
|
||||
|
||||
$test->();
|
||||
|
||||
$config->set('first_layer_extrusion_width', 0.54);
|
||||
$config->set('perimeter_extrusion_width', 0.54);
|
||||
$config->set('external_perimeter_extrusion_width', 0.54);
|
||||
$test->();
|
||||
|
||||
$config->set('first_layer_extrusion_width', 0.59);
|
||||
$config->set('perimeter_extrusion_width', 0.51);
|
||||
$config->set('external_perimeter_extrusion_width', 0.51);
|
||||
$test->();
|
||||
}
|
||||
|
||||
{
|
||||
my $config = Slic3r::Config->new_from_defaults;
|
||||
$config->set('nozzle_diameter', [0.4]);
|
||||
|
@ -237,21 +237,23 @@ 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.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.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.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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,9 @@ PerimeterGenerator::process()
|
||||
// internal flow which is unrelated.
|
||||
coord_t min_spacing = pspacing * (1 - INSET_OVERLAP_TOLERANCE);
|
||||
coord_t ext_min_spacing = ext_pspacing * (1 - INSET_OVERLAP_TOLERANCE);
|
||||
|
||||
// minimum shell thickness
|
||||
coord_t min_shell_thickness = scale_(this->config->min_shell_thickness);
|
||||
|
||||
// prepare grown lower layer slices for overhang detection
|
||||
if (this->lower_slices != NULL && this->config->overhangs) {
|
||||
@ -54,8 +57,21 @@ PerimeterGenerator::process()
|
||||
for (Surfaces::const_iterator surface = this->slices->surfaces.begin();
|
||||
surface != this->slices->surfaces.end(); ++surface) {
|
||||
// detect how many perimeters must be generated for this island
|
||||
const int loop_number = this->config->perimeters + surface->extra_perimeters -1; // 0-indexed loops
|
||||
int loops = this->config->perimeters + surface->extra_perimeters;
|
||||
|
||||
// If the user has defined a minimum shell thickness compute the number of loops needed to satisfy
|
||||
if (min_shell_thickness > 0) {
|
||||
int min_loops = 1;
|
||||
|
||||
min_loops += ceil(((float)min_shell_thickness-ext_pwidth)/pwidth);
|
||||
|
||||
if (loops < min_loops)
|
||||
loops = min_loops;
|
||||
}
|
||||
|
||||
const int loop_number = loops-1; // 0-indexed loops
|
||||
|
||||
|
||||
Polygons gaps;
|
||||
|
||||
Polygons last = surface->expolygon.simplify_p(SCALED_RESOLUTION);
|
||||
|
@ -827,17 +827,27 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->max = 100;
|
||||
def->default_value = new ConfigOptionInt(35);
|
||||
|
||||
|
||||
def = this->add("min_shell_thickness", coFloat);
|
||||
def->label = "Minimum shell thickness";
|
||||
def->category = "Layers and Perimeters";
|
||||
def->sidetext = "mm";
|
||||
def->tooltip = "Alternative method of configuring perimeters and top/bottom layers. If this is above 0 extra perimeters and solid layers will be generated when necessary";
|
||||
def->cli = "min-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.";
|
||||
def->sidetext = "mm";
|
||||
def->cli = "min-layer-height=f@";
|
||||
def->min = 0;
|
||||
{
|
||||
ConfigOptionFloats* opt = new ConfigOptionFloats();
|
||||
opt->values.push_back(0.15);
|
||||
def->default_value = opt;
|
||||
}
|
||||
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.";
|
||||
def->sidetext = "mm";
|
||||
def->cli = "min-layer-height=f@";
|
||||
def->min = 0;
|
||||
{
|
||||
ConfigOptionFloats* opt = new ConfigOptionFloats();
|
||||
opt->values.push_back(0.15);
|
||||
def->default_value = opt;
|
||||
}
|
||||
|
||||
def = this->add("min_print_speed", coFloat);
|
||||
def->label = "Min print speed";
|
||||
|
@ -255,6 +255,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig
|
||||
ConfigOptionInt infill_every_layers;
|
||||
ConfigOptionFloatOrPercent infill_overlap;
|
||||
ConfigOptionFloat infill_speed;
|
||||
ConfigOptionFloat min_shell_thickness;
|
||||
ConfigOptionBool overhangs;
|
||||
ConfigOptionInt perimeter_extruder;
|
||||
ConfigOptionFloatOrPercent perimeter_extrusion_width;
|
||||
@ -296,6 +297,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig
|
||||
OPT_PTR(infill_every_layers);
|
||||
OPT_PTR(infill_overlap);
|
||||
OPT_PTR(infill_speed);
|
||||
OPT_PTR(min_shell_thickness);
|
||||
OPT_PTR(overhangs);
|
||||
OPT_PTR(perimeter_extruder);
|
||||
OPT_PTR(perimeter_extrusion_width);
|
||||
|
@ -76,6 +76,7 @@ PrintRegion::invalidate_state_by_config(const PrintConfigBase &config)
|
||||
for (const t_config_option_key &opt_key : diff) {
|
||||
if (opt_key == "perimeters"
|
||||
|| opt_key == "extra_perimeters"
|
||||
|| opt_key == "min_shell_thickness"
|
||||
|| opt_key == "gap_fill_speed"
|
||||
|| opt_key == "overhangs"
|
||||
|| opt_key == "first_layer_extrusion_width"
|
||||
@ -98,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_shell_thickness"
|
||||
|| opt_key == "infill_extruder"
|
||||
|| opt_key == "solid_infill_extruder"
|
||||
|| opt_key == "infill_extrusion_width") {
|
||||
|
Loading…
x
Reference in New Issue
Block a user