Browse Source

Distinct extrusion width for external perimeters

Alessandro Ranellucci 10 years ago
parent
commit
3599bd0bae

+ 2 - 0
README.md

@@ -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

+ 2 - 1
lib/Slic3r/Flow.pm

@@ -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);

+ 1 - 1
lib/Slic3r/GUI/Tab.pm

@@ -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',

+ 26 - 10
lib/Slic3r/Layer/Region.pm

@@ -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,
                     );
                 }

+ 2 - 0
lib/Slic3r/Print.pm

@@ -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",

+ 4 - 3
lib/Slic3r/Print/Object.pm

@@ -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),

+ 3 - 1
lib/Slic3r/Print/Region.pm

@@ -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;

+ 1 - 1
lib/Slic3r/Print/SupportMaterial.pm

@@ -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.

+ 2 - 0
slic3r.pl

@@ -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

+ 2 - 1
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';
 }
 

Some files were not shown because too many files changed in this diff