Distinct extrusion width for external perimeters
This commit is contained in:
parent
d1511f4a00
commit
3599bd0bae
@ -333,6 +333,8 @@ The author of the Silk icon set is Mark James.
|
||||
Set a different extrusion width for first layer
|
||||
--perimeter-extrusion-width
|
||||
Set a different extrusion width for perimeters
|
||||
--external-perimeter-extrusion-width
|
||||
Set a different extrusion width for external perimeters
|
||||
--infill-extrusion-width
|
||||
Set a different extrusion width for infill
|
||||
--solid-infill-extrusion-width
|
||||
|
@ -4,7 +4,8 @@ use warnings;
|
||||
|
||||
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_SUPPORT_MATERIAL_INTERFACE);
|
||||
our %EXPORT_TAGS = (roles => \@EXPORT_OK);
|
||||
|
@ -544,7 +544,7 @@ sub build {
|
||||
{
|
||||
title => 'Extrusion width',
|
||||
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',
|
||||
|
@ -62,12 +62,23 @@ sub flow {
|
||||
sub make_perimeters {
|
||||
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 $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 $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 $ispacing = $solid_infill_flow->scaled_spacing;
|
||||
my $gap_area_threshold = $pwidth ** 2;
|
||||
@ -77,7 +88,8 @@ sub make_perimeters {
|
||||
# with some tolerance in order to avoid triggering medial axis when
|
||||
# some squishing might work. Loops are still spaced by the entire
|
||||
# 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->fill_surfaces->clear;
|
||||
@ -101,26 +113,30 @@ sub make_perimeters {
|
||||
my @offsets = ();
|
||||
if ($i == 1) {
|
||||
# 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(
|
||||
\@last,
|
||||
-(0.5*$pwidth + 0.5*$min_spacing - 1),
|
||||
+(0.5*$min_spacing - 1),
|
||||
-(0.5*$ext_pwidth + 0.5*$ext_min_spacing - 1),
|
||||
+(0.5*$ext_min_spacing - 1),
|
||||
)};
|
||||
|
||||
# look for thin walls
|
||||
if ($self->config->thin_walls) {
|
||||
my $diff = diff_ex(
|
||||
\@last,
|
||||
offset(\@offsets, +0.5*$pwidth),
|
||||
offset(\@offsets, +0.5*$ext_pwidth),
|
||||
1, # medial axis requires non-overlapping geometry
|
||||
);
|
||||
push @thin_walls, @$diff;
|
||||
}
|
||||
} else {
|
||||
my $distance = ($i == 2)
|
||||
? (0.5*$ext_pspacing + 0.5*$pspacing)
|
||||
: (1.0*$pspacing);
|
||||
|
||||
@offsets = @{offset2(
|
||||
\@last,
|
||||
-(1.0*$pspacing + 0.5*$min_spacing - 1),
|
||||
-($distance + 0.5*$min_spacing - 1),
|
||||
+(0.5*$min_spacing - 1),
|
||||
)};
|
||||
|
||||
@ -283,8 +299,8 @@ sub make_perimeters {
|
||||
push @paths, Slic3r::ExtrusionPath->new(
|
||||
polyline => $polyline,
|
||||
role => $role,
|
||||
mm3_per_mm => $mm3_per_mm,
|
||||
width => $perimeter_flow->width,
|
||||
mm3_per_mm => ($is_external ? $ext_mm3_per_mm : $mm3_per_mm),
|
||||
width => ($is_external ? $ext_perimeter_flow->width : $perimeter_flow->width),
|
||||
height => $self->height,
|
||||
);
|
||||
}
|
||||
|
@ -835,6 +835,8 @@ sub write_gcode {
|
||||
my $first_object = $self->objects->[0];
|
||||
my $layer_height = $first_object->config->layer_height;
|
||||
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",
|
||||
$self->regions->[$region_id]->flow(FLOW_ROLE_PERIMETER, $layer_height, 0, 0, undef, $first_object)->width;
|
||||
printf $fh "; infill extrusion width = %.2fmm\n",
|
||||
|
@ -372,11 +372,12 @@ sub make_perimeters {
|
||||
my $layerm = $self->layers->[$i]->regions->[$region_id];
|
||||
my $upper_layerm = $self->layers->[$i+1]->regions->[$region_id];
|
||||
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 $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),
|
||||
);
|
||||
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)
|
||||
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),
|
||||
@{ 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
|
||||
# and it's not wanted in a hollow print even if it would make sense when
|
||||
# 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(
|
||||
$new_internal_solid,
|
||||
offset2($new_internal_solid, -$margin, +$margin, CLIPPER_OFFSET_SCALE, JT_MITER, 5),
|
||||
|
@ -23,6 +23,8 @@ sub flow {
|
||||
# (might be an absolute value, or a percent value, or zero for auto)
|
||||
if ($first_layer && $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) {
|
||||
$config_width = $self->config->perimeter_extrusion_width;
|
||||
} elsif ($role == FLOW_ROLE_INFILL) {
|
||||
@ -42,7 +44,7 @@ sub flow {
|
||||
# get the configured nozzle_diameter for the extruder associated
|
||||
# to the flow role requested
|
||||
my $extruder; # 1-based
|
||||
if ($role == FLOW_ROLE_PERIMETER) {
|
||||
if ($role == FLOW_ROLE_PERIMETER || $role == FLOW_ROLE_EXTERNAL_PERIMETER) {
|
||||
$extruder = $self->config->perimeter_extruder;
|
||||
} elsif ($role == FLOW_ROLE_INFILL || $role == FLOW_ROLE_SOLID_INFILL || $role == FLOW_ROLE_TOP_SOLID_INFILL) {
|
||||
$extruder = $self->config->infill_extruder;
|
||||
|
@ -127,7 +127,7 @@ sub contact_area {
|
||||
} else {
|
||||
my $lower_layer = $object->layers->[$layer_id-1];
|
||||
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;
|
||||
|
||||
# If a threshold angle was specified, use a different logic for detecting overhangs.
|
||||
|
@ -456,6 +456,8 @@ $j
|
||||
Set a different extrusion width for first layer
|
||||
--perimeter-extrusion-width
|
||||
Set a different extrusion width for perimeters
|
||||
--external-perimeter-extrusion-width
|
||||
Set a different extrusion width for external perimeters
|
||||
--infill-extrusion-width
|
||||
Set a different extrusion width for infill
|
||||
--solid-infill-extrusion-width
|
||||
|
3
t/fill.t
3
t/fill.t
@ -275,6 +275,7 @@ for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) {
|
||||
$config->set('nozzle_diameter', [0.35]);
|
||||
$config->set('infill_extruder', 2);
|
||||
$config->set('infill_extrusion_width', 0.52);
|
||||
$config->set('first_layer_extrusion_width', 0);
|
||||
|
||||
my $print = Slic3r::Test::init_print('A', config => $config);
|
||||
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 $layer0_infill = union([ map @{$_->grow($grow_d)}, @{ $infill{0.2} } ]);
|
||||
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';
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ Flow::_width(FlowRole role, float nozzle_diameter, float height, float bridge_fl
|
||||
|
||||
float min = nozzle_diameter * 1.05;
|
||||
float max = -1;
|
||||
if (role == frPerimeter || role == frSupportMaterial) {
|
||||
if (role == frExternalPerimeter || role == frSupportMaterial) {
|
||||
min = max = nozzle_diameter;
|
||||
} else if (role != frInfill) {
|
||||
// do not limit width for sparse infill so that we use full native flow for it
|
||||
|
@ -11,6 +11,7 @@ namespace Slic3r {
|
||||
#define OVERLAP_FACTOR 1.0
|
||||
|
||||
enum FlowRole {
|
||||
frExternalPerimeter,
|
||||
frPerimeter,
|
||||
frInfill,
|
||||
frSolidInfill,
|
||||
|
@ -172,6 +172,13 @@ class PrintConfigDef
|
||||
Options["end_gcode"].full_width = true;
|
||||
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"].label = "External perimeters";
|
||||
Options["external_perimeter_speed"].category = "Speed";
|
||||
@ -555,7 +562,7 @@ class PrintConfigDef
|
||||
Options["perimeter_extrusion_width"].type = coFloatOrPercent;
|
||||
Options["perimeter_extrusion_width"].label = "Perimeters";
|
||||
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"].cli = "perimeter-extrusion-width=s";
|
||||
Options["perimeter_extrusion_width"].aliases.push_back("perimeters_extrusion_width");
|
||||
@ -1088,6 +1095,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig
|
||||
public:
|
||||
ConfigOptionInt bottom_solid_layers;
|
||||
ConfigOptionFloat bridge_speed;
|
||||
ConfigOptionFloatOrPercent external_perimeter_extrusion_width;
|
||||
ConfigOptionFloatOrPercent external_perimeter_speed;
|
||||
ConfigOptionBool extra_perimeters;
|
||||
ConfigOptionInt fill_angle;
|
||||
@ -1117,6 +1125,8 @@ class PrintRegionConfig : public virtual StaticPrintConfig
|
||||
PrintRegionConfig() : StaticPrintConfig() {
|
||||
this->bottom_solid_layers.value = 3;
|
||||
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.percent = 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) {
|
||||
if (opt_key == "bottom_solid_layers") return &this->bottom_solid_layers;
|
||||
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 == "extra_perimeters") return &this->extra_perimeters;
|
||||
if (opt_key == "fill_angle") return &this->fill_angle;
|
||||
|
@ -65,6 +65,7 @@ _new_from_spacing(CLASS, spacing, nozzle_diameter, height, bridge)
|
||||
IV
|
||||
_constant()
|
||||
ALIAS:
|
||||
FLOW_ROLE_EXTERNAL_PERIMETER = frExternalPerimeter
|
||||
FLOW_ROLE_PERIMETER = frPerimeter
|
||||
FLOW_ROLE_INFILL = frInfill
|
||||
FLOW_ROLE_SOLID_INFILL = frSolidInfill
|
||||
|
Loading…
Reference in New Issue
Block a user