Distinct extrusion width for external perimeters

This commit is contained in:
Alessandro Ranellucci 2014-06-09 21:14:48 +02:00
parent d1511f4a00
commit 3599bd0bae
14 changed files with 60 additions and 20 deletions

View File

@ -333,6 +333,8 @@ The author of the Silk icon set is Mark James.
Set a different extrusion width for first layer Set a different extrusion width for first layer
--perimeter-extrusion-width --perimeter-extrusion-width
Set a different extrusion width for perimeters Set a different extrusion width for perimeters
--external-perimeter-extrusion-width
Set a different extrusion width for external perimeters
--infill-extrusion-width --infill-extrusion-width
Set a different extrusion width for infill Set a different extrusion width for infill
--solid-infill-extrusion-width --solid-infill-extrusion-width

View File

@ -4,7 +4,8 @@ use warnings;
use parent qw(Exporter); use parent qw(Exporter);
our @EXPORT_OK = qw(FLOW_ROLE_PERIMETER FLOW_ROLE_INFILL FLOW_ROLE_SOLID_INFILL our @EXPORT_OK = qw(FLOW_ROLE_EXTERNAL_PERIMETER FLOW_ROLE_PERIMETER FLOW_ROLE_INFILL
FLOW_ROLE_SOLID_INFILL
FLOW_ROLE_TOP_SOLID_INFILL FLOW_ROLE_SUPPORT_MATERIAL FLOW_ROLE_TOP_SOLID_INFILL FLOW_ROLE_SUPPORT_MATERIAL
FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE); FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE);
our %EXPORT_TAGS = (roles => \@EXPORT_OK); our %EXPORT_TAGS = (roles => \@EXPORT_OK);

View File

@ -544,7 +544,7 @@ sub build {
{ {
title => 'Extrusion width', title => 'Extrusion width',
label_width => 180, label_width => 180,
options => [qw(extrusion_width first_layer_extrusion_width perimeter_extrusion_width infill_extrusion_width solid_infill_extrusion_width top_infill_extrusion_width support_material_extrusion_width)], options => [qw(extrusion_width first_layer_extrusion_width perimeter_extrusion_width external_perimeter_extrusion_width infill_extrusion_width solid_infill_extrusion_width top_infill_extrusion_width support_material_extrusion_width)],
}, },
{ {
title => 'Flow', title => 'Flow',

View File

@ -62,12 +62,23 @@ sub flow {
sub make_perimeters { sub make_perimeters {
my $self = shift; my $self = shift;
# external perimeters
my $ext_perimeter_flow = $self->flow(FLOW_ROLE_EXTERNAL_PERIMETER);
my $ext_mm3_per_mm = $ext_perimeter_flow->mm3_per_mm($self->height);
my $ext_pwidth = $ext_perimeter_flow->scaled_width;
my $ext_pspacing = $ext_perimeter_flow->scaled_spacing;
# other perimeters
my $perimeter_flow = $self->flow(FLOW_ROLE_PERIMETER); my $perimeter_flow = $self->flow(FLOW_ROLE_PERIMETER);
my $mm3_per_mm = $perimeter_flow->mm3_per_mm($self->height); my $mm3_per_mm = $perimeter_flow->mm3_per_mm($self->height);
my $overhang_flow = $self->region->flow(FLOW_ROLE_PERIMETER, -1, 1, 0, undef, $self->layer->object);
my $mm3_per_mm_overhang = $overhang_flow->mm3_per_mm(-1);
my $pwidth = $perimeter_flow->scaled_width; my $pwidth = $perimeter_flow->scaled_width;
my $pspacing = $perimeter_flow->scaled_spacing; my $pspacing = $perimeter_flow->scaled_spacing;
# overhang perimeters
my $overhang_flow = $self->region->flow(FLOW_ROLE_PERIMETER, -1, 1, 0, undef, $self->layer->object);
my $mm3_per_mm_overhang = $overhang_flow->mm3_per_mm(-1);
# solid infill
my $solid_infill_flow = $self->flow(FLOW_ROLE_SOLID_INFILL); my $solid_infill_flow = $self->flow(FLOW_ROLE_SOLID_INFILL);
my $ispacing = $solid_infill_flow->scaled_spacing; my $ispacing = $solid_infill_flow->scaled_spacing;
my $gap_area_threshold = $pwidth ** 2; my $gap_area_threshold = $pwidth ** 2;
@ -78,6 +89,7 @@ sub make_perimeters {
# some squishing might work. Loops are still spaced by the entire # some squishing might work. Loops are still spaced by the entire
# flow spacing; this only applies to collapsing parts. # flow spacing; this only applies to collapsing parts.
my $min_spacing = $pspacing * (1 - &Slic3r::INSET_OVERLAP_TOLERANCE); my $min_spacing = $pspacing * (1 - &Slic3r::INSET_OVERLAP_TOLERANCE);
my $ext_min_spacing = $ext_pspacing * (1 - &Slic3r::INSET_OVERLAP_TOLERANCE);
$self->perimeters->clear; $self->perimeters->clear;
$self->fill_surfaces->clear; $self->fill_surfaces->clear;
@ -101,26 +113,30 @@ sub make_perimeters {
my @offsets = (); my @offsets = ();
if ($i == 1) { if ($i == 1) {
# the minimum thickness of a single loop is: # the minimum thickness of a single loop is:
# width/2 + spacing/2 + spacing/2 + width/2 # ext_width/2 + ext_spacing/2 + spacing/2 + width/2
@offsets = @{offset2( @offsets = @{offset2(
\@last, \@last,
-(0.5*$pwidth + 0.5*$min_spacing - 1), -(0.5*$ext_pwidth + 0.5*$ext_min_spacing - 1),
+(0.5*$min_spacing - 1), +(0.5*$ext_min_spacing - 1),
)}; )};
# look for thin walls # look for thin walls
if ($self->config->thin_walls) { if ($self->config->thin_walls) {
my $diff = diff_ex( my $diff = diff_ex(
\@last, \@last,
offset(\@offsets, +0.5*$pwidth), offset(\@offsets, +0.5*$ext_pwidth),
1, # medial axis requires non-overlapping geometry 1, # medial axis requires non-overlapping geometry
); );
push @thin_walls, @$diff; push @thin_walls, @$diff;
} }
} else { } else {
my $distance = ($i == 2)
? (0.5*$ext_pspacing + 0.5*$pspacing)
: (1.0*$pspacing);
@offsets = @{offset2( @offsets = @{offset2(
\@last, \@last,
-(1.0*$pspacing + 0.5*$min_spacing - 1), -($distance + 0.5*$min_spacing - 1),
+(0.5*$min_spacing - 1), +(0.5*$min_spacing - 1),
)}; )};
@ -283,8 +299,8 @@ sub make_perimeters {
push @paths, Slic3r::ExtrusionPath->new( push @paths, Slic3r::ExtrusionPath->new(
polyline => $polyline, polyline => $polyline,
role => $role, role => $role,
mm3_per_mm => $mm3_per_mm, mm3_per_mm => ($is_external ? $ext_mm3_per_mm : $mm3_per_mm),
width => $perimeter_flow->width, width => ($is_external ? $ext_perimeter_flow->width : $perimeter_flow->width),
height => $self->height, height => $self->height,
); );
} }

View File

@ -835,6 +835,8 @@ sub write_gcode {
my $first_object = $self->objects->[0]; my $first_object = $self->objects->[0];
my $layer_height = $first_object->config->layer_height; my $layer_height = $first_object->config->layer_height;
for my $region_id (0..$#{$self->regions}) { for my $region_id (0..$#{$self->regions}) {
printf $fh "; external perimeters extrusion width = %.2fmm\n",
$self->regions->[$region_id]->flow(FLOW_ROLE_EXTERNAL_PERIMETER, $layer_height, 0, 0, undef, $first_object)->width;
printf $fh "; perimeters extrusion width = %.2fmm\n", printf $fh "; perimeters extrusion width = %.2fmm\n",
$self->regions->[$region_id]->flow(FLOW_ROLE_PERIMETER, $layer_height, 0, 0, undef, $first_object)->width; $self->regions->[$region_id]->flow(FLOW_ROLE_PERIMETER, $layer_height, 0, 0, undef, $first_object)->width;
printf $fh "; infill extrusion width = %.2fmm\n", printf $fh "; infill extrusion width = %.2fmm\n",

View File

@ -372,11 +372,12 @@ sub make_perimeters {
my $layerm = $self->layers->[$i]->regions->[$region_id]; my $layerm = $self->layers->[$i]->regions->[$region_id];
my $upper_layerm = $self->layers->[$i+1]->regions->[$region_id]; my $upper_layerm = $self->layers->[$i+1]->regions->[$region_id];
my $perimeter_spacing = $layerm->flow(FLOW_ROLE_PERIMETER)->scaled_spacing; my $perimeter_spacing = $layerm->flow(FLOW_ROLE_PERIMETER)->scaled_spacing;
my $ext_perimeter_spacing = $layerm->flow(FLOW_ROLE_EXTERNAL_PERIMETER)->scaled_spacing;
my $overlap = $perimeter_spacing; # one perimeter my $overlap = $perimeter_spacing; # one perimeter
my $diff = diff( my $diff = diff(
offset([ map @{$_->expolygon}, @{$layerm->slices} ], -($region_perimeters * $perimeter_spacing)), offset([ map @{$_->expolygon}, @{$layerm->slices} ], -($ext_perimeter_spacing + ($region_perimeters-1) * $perimeter_spacing)),
offset([ map @{$_->expolygon}, @{$upper_layerm->slices} ], -$overlap), offset([ map @{$_->expolygon}, @{$upper_layerm->slices} ], -$overlap),
); );
next if !@$diff; next if !@$diff;
@ -453,7 +454,7 @@ sub detect_surfaces_type {
); );
# collapse very narrow parts (using the safety offset in the diff is not enough) # collapse very narrow parts (using the safety offset in the diff is not enough)
my $offset = $layerm->flow(FLOW_ROLE_PERIMETER)->scaled_width / 10; my $offset = $layerm->flow(FLOW_ROLE_EXTERNAL_PERIMETER)->scaled_width / 10;
return map Slic3r::Surface->new(expolygon => $_, surface_type => $result_type), return map Slic3r::Surface->new(expolygon => $_, surface_type => $result_type),
@{ offset2_ex($diff, -$offset, +$offset) }; @{ offset2_ex($diff, -$offset, +$offset) };
}; };
@ -768,7 +769,7 @@ sub discover_horizontal_shells {
# than a perimeter width, since it's probably just crossing a sloping wall # than a perimeter width, since it's probably just crossing a sloping wall
# and it's not wanted in a hollow print even if it would make sense when # and it's not wanted in a hollow print even if it would make sense when
# obeying the solid shell count option strictly (DWIM!) # obeying the solid shell count option strictly (DWIM!)
my $margin = $neighbor_layerm->flow(FLOW_ROLE_PERIMETER)->scaled_width; my $margin = $neighbor_layerm->flow(FLOW_ROLE_EXTERNAL_PERIMETER)->scaled_width;
my $too_narrow = diff( my $too_narrow = diff(
$new_internal_solid, $new_internal_solid,
offset2($new_internal_solid, -$margin, +$margin, CLIPPER_OFFSET_SCALE, JT_MITER, 5), offset2($new_internal_solid, -$margin, +$margin, CLIPPER_OFFSET_SCALE, JT_MITER, 5),

View File

@ -23,6 +23,8 @@ sub flow {
# (might be an absolute value, or a percent value, or zero for auto) # (might be an absolute value, or a percent value, or zero for auto)
if ($first_layer && $self->print->config->first_layer_extrusion_width) { if ($first_layer && $self->print->config->first_layer_extrusion_width) {
$config_width = $self->print->config->first_layer_extrusion_width; $config_width = $self->print->config->first_layer_extrusion_width;
} elsif ($role == FLOW_ROLE_EXTERNAL_PERIMETER) {
$config_width = $self->config->external_perimeter_extrusion_width;
} elsif ($role == FLOW_ROLE_PERIMETER) { } elsif ($role == FLOW_ROLE_PERIMETER) {
$config_width = $self->config->perimeter_extrusion_width; $config_width = $self->config->perimeter_extrusion_width;
} elsif ($role == FLOW_ROLE_INFILL) { } elsif ($role == FLOW_ROLE_INFILL) {
@ -42,7 +44,7 @@ sub flow {
# get the configured nozzle_diameter for the extruder associated # get the configured nozzle_diameter for the extruder associated
# to the flow role requested # to the flow role requested
my $extruder; # 1-based my $extruder; # 1-based
if ($role == FLOW_ROLE_PERIMETER) { if ($role == FLOW_ROLE_PERIMETER || $role == FLOW_ROLE_EXTERNAL_PERIMETER) {
$extruder = $self->config->perimeter_extruder; $extruder = $self->config->perimeter_extruder;
} elsif ($role == FLOW_ROLE_INFILL || $role == FLOW_ROLE_SOLID_INFILL || $role == FLOW_ROLE_TOP_SOLID_INFILL) { } elsif ($role == FLOW_ROLE_INFILL || $role == FLOW_ROLE_SOLID_INFILL || $role == FLOW_ROLE_TOP_SOLID_INFILL) {
$extruder = $self->config->infill_extruder; $extruder = $self->config->infill_extruder;

View File

@ -127,7 +127,7 @@ sub contact_area {
} else { } else {
my $lower_layer = $object->layers->[$layer_id-1]; my $lower_layer = $object->layers->[$layer_id-1];
foreach my $layerm (@{$layer->regions}) { foreach my $layerm (@{$layer->regions}) {
my $fw = $layerm->flow(FLOW_ROLE_PERIMETER)->scaled_width; my $fw = $layerm->flow(FLOW_ROLE_EXTERNAL_PERIMETER)->scaled_width;
my $diff; my $diff;
# If a threshold angle was specified, use a different logic for detecting overhangs. # If a threshold angle was specified, use a different logic for detecting overhangs.

View File

@ -456,6 +456,8 @@ $j
Set a different extrusion width for first layer Set a different extrusion width for first layer
--perimeter-extrusion-width --perimeter-extrusion-width
Set a different extrusion width for perimeters Set a different extrusion width for perimeters
--external-perimeter-extrusion-width
Set a different extrusion width for external perimeters
--infill-extrusion-width --infill-extrusion-width
Set a different extrusion width for infill Set a different extrusion width for infill
--solid-infill-extrusion-width --solid-infill-extrusion-width

View File

@ -275,6 +275,7 @@ for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) {
$config->set('nozzle_diameter', [0.35]); $config->set('nozzle_diameter', [0.35]);
$config->set('infill_extruder', 2); $config->set('infill_extruder', 2);
$config->set('infill_extrusion_width', 0.52); $config->set('infill_extrusion_width', 0.52);
$config->set('first_layer_extrusion_width', 0);
my $print = Slic3r::Test::init_print('A', config => $config); my $print = Slic3r::Test::init_print('A', config => $config);
my %infill = (); # Z => [ Line, Line ... ] my %infill = (); # Z => [ Line, Line ... ]
@ -298,7 +299,7 @@ for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) {
my $grow_d = scale($config->infill_extrusion_width)/2; my $grow_d = scale($config->infill_extrusion_width)/2;
my $layer0_infill = union([ map @{$_->grow($grow_d)}, @{ $infill{0.2} } ]); my $layer0_infill = union([ map @{$_->grow($grow_d)}, @{ $infill{0.2} } ]);
my $layer1_infill = union([ map @{$_->grow($grow_d)}, @{ $infill{0.4} } ]); my $layer1_infill = union([ map @{$_->grow($grow_d)}, @{ $infill{0.4} } ]);
my $diff = [ grep $_->area >= 2*$grow_d**2, @{diff_ex($layer0_infill, $layer1_infill)} ]; my $diff = [ grep $_->area >= 4*($grow_d**2), @{diff_ex($layer0_infill, $layer1_infill)} ];
is scalar(@$diff), 0, 'no missing parts in solid shell when fill_density is 0'; is scalar(@$diff), 0, 'no missing parts in solid shell when fill_density is 0';
} }

View File

@ -65,7 +65,7 @@ Flow::_width(FlowRole role, float nozzle_diameter, float height, float bridge_fl
float min = nozzle_diameter * 1.05; float min = nozzle_diameter * 1.05;
float max = -1; float max = -1;
if (role == frPerimeter || role == frSupportMaterial) { if (role == frExternalPerimeter || role == frSupportMaterial) {
min = max = nozzle_diameter; min = max = nozzle_diameter;
} else if (role != frInfill) { } else if (role != frInfill) {
// do not limit width for sparse infill so that we use full native flow for it // do not limit width for sparse infill so that we use full native flow for it

View File

@ -11,6 +11,7 @@ namespace Slic3r {
#define OVERLAP_FACTOR 1.0 #define OVERLAP_FACTOR 1.0
enum FlowRole { enum FlowRole {
frExternalPerimeter,
frPerimeter, frPerimeter,
frInfill, frInfill,
frSolidInfill, frSolidInfill,

View File

@ -172,6 +172,13 @@ class PrintConfigDef
Options["end_gcode"].full_width = true; Options["end_gcode"].full_width = true;
Options["end_gcode"].height = 120; Options["end_gcode"].height = 120;
Options["external_perimeter_extrusion_width"].type = coFloatOrPercent;
Options["external_perimeter_extrusion_width"].label = "External perimeters";
Options["external_perimeter_extrusion_width"].category = "Extrusion Width";
Options["external_perimeter_extrusion_width"].tooltip = "Set this to a non-zero value to set a manual extrusion width for external perimeters. If left zero, an automatic value will be used that maximizes accuracy of the external visible surfaces. If expressed as percentage (for example 200%) it will be computed over layer height.";
Options["external_perimeter_extrusion_width"].sidetext = "mm or % (leave 0 for default)";
Options["external_perimeter_extrusion_width"].cli = "external-perimeter-extrusion-width=s";
Options["external_perimeter_speed"].type = coFloatOrPercent; Options["external_perimeter_speed"].type = coFloatOrPercent;
Options["external_perimeter_speed"].label = "External perimeters"; Options["external_perimeter_speed"].label = "External perimeters";
Options["external_perimeter_speed"].category = "Speed"; Options["external_perimeter_speed"].category = "Speed";
@ -555,7 +562,7 @@ class PrintConfigDef
Options["perimeter_extrusion_width"].type = coFloatOrPercent; Options["perimeter_extrusion_width"].type = coFloatOrPercent;
Options["perimeter_extrusion_width"].label = "Perimeters"; Options["perimeter_extrusion_width"].label = "Perimeters";
Options["perimeter_extrusion_width"].category = "Extrusion Width"; Options["perimeter_extrusion_width"].category = "Extrusion Width";
Options["perimeter_extrusion_width"].tooltip = "Set this to a non-zero value to set a manual extrusion width for perimeters. You may want to use thinner extrudates to get more accurate surfaces. If expressed as percentage (for example 90%) it will be computed over layer height."; Options["perimeter_extrusion_width"].tooltip = "Set this to a non-zero value to set a manual extrusion width for perimeters. You may want to use thinner extrudates to get more accurate surfaces. If expressed as percentage (for example 200%) it will be computed over layer height.";
Options["perimeter_extrusion_width"].sidetext = "mm or % (leave 0 for default)"; Options["perimeter_extrusion_width"].sidetext = "mm or % (leave 0 for default)";
Options["perimeter_extrusion_width"].cli = "perimeter-extrusion-width=s"; Options["perimeter_extrusion_width"].cli = "perimeter-extrusion-width=s";
Options["perimeter_extrusion_width"].aliases.push_back("perimeters_extrusion_width"); Options["perimeter_extrusion_width"].aliases.push_back("perimeters_extrusion_width");
@ -1088,6 +1095,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig
public: public:
ConfigOptionInt bottom_solid_layers; ConfigOptionInt bottom_solid_layers;
ConfigOptionFloat bridge_speed; ConfigOptionFloat bridge_speed;
ConfigOptionFloatOrPercent external_perimeter_extrusion_width;
ConfigOptionFloatOrPercent external_perimeter_speed; ConfigOptionFloatOrPercent external_perimeter_speed;
ConfigOptionBool extra_perimeters; ConfigOptionBool extra_perimeters;
ConfigOptionInt fill_angle; ConfigOptionInt fill_angle;
@ -1117,6 +1125,8 @@ class PrintRegionConfig : public virtual StaticPrintConfig
PrintRegionConfig() : StaticPrintConfig() { PrintRegionConfig() : StaticPrintConfig() {
this->bottom_solid_layers.value = 3; this->bottom_solid_layers.value = 3;
this->bridge_speed.value = 60; this->bridge_speed.value = 60;
this->external_perimeter_extrusion_width.value = 0;
this->external_perimeter_extrusion_width.percent = false;
this->external_perimeter_speed.value = 70; this->external_perimeter_speed.value = 70;
this->external_perimeter_speed.percent = true; this->external_perimeter_speed.percent = true;
this->extra_perimeters.value = true; this->extra_perimeters.value = true;
@ -1155,6 +1165,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig
ConfigOption* option(const t_config_option_key opt_key, bool create = false) { ConfigOption* option(const t_config_option_key opt_key, bool create = false) {
if (opt_key == "bottom_solid_layers") return &this->bottom_solid_layers; if (opt_key == "bottom_solid_layers") return &this->bottom_solid_layers;
if (opt_key == "bridge_speed") return &this->bridge_speed; if (opt_key == "bridge_speed") return &this->bridge_speed;
if (opt_key == "external_perimeter_extrusion_width") return &this->external_perimeter_extrusion_width;
if (opt_key == "external_perimeter_speed") return &this->external_perimeter_speed; if (opt_key == "external_perimeter_speed") return &this->external_perimeter_speed;
if (opt_key == "extra_perimeters") return &this->extra_perimeters; if (opt_key == "extra_perimeters") return &this->extra_perimeters;
if (opt_key == "fill_angle") return &this->fill_angle; if (opt_key == "fill_angle") return &this->fill_angle;

View File

@ -65,6 +65,7 @@ _new_from_spacing(CLASS, spacing, nozzle_diameter, height, bridge)
IV IV
_constant() _constant()
ALIAS: ALIAS:
FLOW_ROLE_EXTERNAL_PERIMETER = frExternalPerimeter
FLOW_ROLE_PERIMETER = frPerimeter FLOW_ROLE_PERIMETER = frPerimeter
FLOW_ROLE_INFILL = frInfill FLOW_ROLE_INFILL = frInfill
FLOW_ROLE_SOLID_INFILL = frSolidInfill FLOW_ROLE_SOLID_INFILL = frSolidInfill