Browse Source

New --first-layer-extrusion-width option. #385

Alessandro Ranellucci 12 years ago
parent
commit
8a031fe501

+ 4 - 0
lib/Slic3r.pm

@@ -101,11 +101,15 @@ our $infill_every_layers    = 1;
 
 # flow options
 our $extrusion_width        = 0;
+our $first_layer_extrusion_width = 0;
 our $bridge_flow_ratio      = 1;
 our $overlap_factor         = 0.5;
 our $flow_width;
 our $min_flow_spacing;
 our $flow_spacing;
+our $first_layer_flow_width;
+our $first_layer_min_flow_spacing;
+our $first_layer_flow_spacing;
 
 # print options
 our $perimeters         = 3;

+ 57 - 37
lib/Slic3r/Config.pm

@@ -159,7 +159,7 @@ our $Options = {
     },
     'first_layer_speed' => {
         label   => 'First layer speed (mm/s or %)',
-        cli     => 'first-layer-speed=f',
+        cli     => 'first-layer-speed=s',
         type    => 'f',
     },
     
@@ -188,7 +188,7 @@ our $Options = {
     },
     'first_layer_height' => {
         label   => 'First layer height (mm or %)',
-        cli     => 'first-layer-height=f',
+        cli     => 'first-layer-height=s',
         type    => 'f',
     },
     'infill_every_layers' => {
@@ -200,7 +200,12 @@ our $Options = {
     # flow options
     'extrusion_width' => {
         label   => 'Extrusion width (mm or %; leave zero to calculate automatically)',
-        cli     => 'extrusion-width=f',
+        cli     => 'extrusion-width=s',
+        type    => 'f',
+    },
+    'first_layer_extrusion_width' => {
+        label   => 'First layer extrusion width (mm or %; leave zero to use default)',
+        cli     => 'first-layer-extrusion-width=s',
         type    => 'f',
     },
     'bridge_flow_ratio' => {
@@ -283,7 +288,7 @@ our $Options = {
         deserialize => sub { join "\n", split /\\n/, $_[0] },
     },
     'layer_gcode' => {
-        label   => 'Layer Change G-code',
+        label   => 'Layer change G-code',
         cli     => 'layer-gcode=s',
         type    => 's',
         multiline => 1,
@@ -590,43 +595,18 @@ sub validate {
     die "First layer height can't be greater than --nozzle-diameter\n"
         if $Slic3r::_first_layer_height > $Slic3r::nozzle_diameter;
     
-    if ($Slic3r::extrusion_width) {
-        $Slic3r::flow_width = $Slic3r::extrusion_width =~ /^(\d+(?:\.\d+)?)%$/
-            ? ($Slic3r::layer_height * $1 / 100)
-            : $Slic3r::extrusion_width;
-    } else {
-        # here we calculate a sane default by matching the flow speed (at the nozzle)
-        # and the feed rate
-        my $volume = ($Slic3r::nozzle_diameter**2) * PI/4;
-        my $shape_threshold = $Slic3r::nozzle_diameter * $Slic3r::layer_height
-            + ($Slic3r::layer_height**2) * PI/4;
-        if ($volume >= $shape_threshold) {
-            # rectangle with semicircles at the ends
-            $Slic3r::flow_width = (($Slic3r::nozzle_diameter**2) * PI + ($Slic3r::layer_height**2) * (4 - PI)) / (4 * $Slic3r::layer_height);
-        } else {
-            # rectangle with squished semicircles at the ends
-            $Slic3r::flow_width = $Slic3r::nozzle_diameter * ($Slic3r::nozzle_diameter/$Slic3r::layer_height - 4/PI + 1);
-        }
-        
-        my $min_flow_width = $Slic3r::nozzle_diameter * 1.05;
-        my $max_flow_width = $Slic3r::nozzle_diameter * 1.4;
-        $Slic3r::flow_width = $max_flow_width if $Slic3r::flow_width > $max_flow_width;
-        $Slic3r::flow_width = $min_flow_width if $Slic3r::flow_width < $min_flow_width;
-    }
-    
-    if ($Slic3r::flow_width >= ($Slic3r::nozzle_diameter + $Slic3r::layer_height)) {
-        # rectangle with semicircles at the ends
-        $Slic3r::min_flow_spacing = $Slic3r::flow_width - $Slic3r::layer_height * (1 - PI/4);
-    } else {
-        # rectangle with shrunk semicircles at the ends
-        $Slic3r::min_flow_spacing = $Slic3r::flow_width * (1 - PI/4) + $Slic3r::nozzle_diameter * PI/4;
-    }
-    $Slic3r::flow_spacing = $Slic3r::flow_width - $Slic3r::overlap_factor * ($Slic3r::flow_width - $Slic3r::min_flow_spacing);
-    
+    # calculate flow
+    ($Slic3r::flow_width, $Slic3r::min_flow_spacing, $Slic3r::flow_spacing) = calculate_flow($Slic3r::extrusion_width);
     Slic3r::debugf "Flow width = $Slic3r::flow_width\n";
     Slic3r::debugf "Flow spacing = $Slic3r::flow_spacing\n";
     Slic3r::debugf "Min flow spacing = $Slic3r::min_flow_spacing\n";
     
+    # calculate first layer flow
+    ($Slic3r::first_layer_flow_width, $Slic3r::first_layer_min_flow_spacing, $Slic3r::first_layer_flow_spacing) = calculate_flow($Slic3r::first_layer_extrusion_width || $Slic3r::extrusion_width);
+    Slic3r::debugf "First Layer Flow width = $Slic3r::first_layer_flow_width\n";
+    Slic3r::debugf "First Layer Flow spacing = $Slic3r::first_layer_flow_spacing\n";
+    Slic3r::debugf "First Layer Min flow spacing = $Slic3r::first_layer_min_flow_spacing\n";
+    
     # --perimeters
     die "Invalid value for --perimeters\n"
         if $Slic3r::perimeters < 0;
@@ -743,4 +723,44 @@ sub replace_options {
     return $string;
 }
 
+sub calculate_flow {
+    my ($extrusion_width) = @_;
+    
+    my ($flow_width, $min_flow_spacing, $flow_spacing);
+    if ($extrusion_width) {
+        $flow_width = $extrusion_width =~ /^(\d+(?:\.\d+)?)%$/
+            ? ($Slic3r::layer_height * $1 / 100)
+            : $extrusion_width;
+    } else {
+        # here we calculate a sane default by matching the flow speed (at the nozzle)
+        # and the feed rate
+        my $volume = ($Slic3r::nozzle_diameter**2) * PI/4;
+        my $shape_threshold = $Slic3r::nozzle_diameter * $Slic3r::layer_height
+            + ($Slic3r::layer_height**2) * PI/4;
+        if ($volume >= $shape_threshold) {
+            # rectangle with semicircles at the ends
+            $flow_width = (($Slic3r::nozzle_diameter**2) * PI + ($Slic3r::layer_height**2) * (4 - PI)) / (4 * $Slic3r::layer_height);
+        } else {
+            # rectangle with squished semicircles at the ends
+            $flow_width = $Slic3r::nozzle_diameter * ($Slic3r::nozzle_diameter/$Slic3r::layer_height - 4/PI + 1);
+        }
+        
+        my $min_flow_width = $Slic3r::nozzle_diameter * 1.05;
+        my $max_flow_width = $Slic3r::nozzle_diameter * 1.4;
+        $flow_width = $max_flow_width if $flow_width > $max_flow_width;
+        $flow_width = $min_flow_width if $flow_width < $min_flow_width;
+    }
+    
+    if ($flow_width >= ($Slic3r::nozzle_diameter + $Slic3r::layer_height)) {
+        # rectangle with semicircles at the ends
+        $min_flow_spacing = $flow_width - $Slic3r::layer_height * (1 - PI/4);
+    } else {
+        # rectangle with shrunk semicircles at the ends
+        $min_flow_spacing = $flow_width * (1 - PI/4) + $Slic3r::nozzle_diameter * PI/4;
+    }
+    $flow_spacing = $flow_width - $Slic3r::overlap_factor * ($flow_width - $min_flow_spacing);
+    
+    return ($flow_width, $min_flow_spacing, $flow_spacing);
+}
+
 1;

+ 3 - 3
lib/Slic3r/Extruder.pm

@@ -102,7 +102,7 @@ sub extrude_loop {
     # clip the path to avoid the extruder to get exactly on the first point of the loop;
     # if polyline was shorter than the clipping distance we'd get a null polyline, so
     # we discard it in that case
-    $extrusion_path->clip_end(scale $Slic3r::flow_width * 0.15);
+    $extrusion_path->clip_end(scale($self->layer->flow_width || $Slic3r::flow_width) * 0.15);
     return '' if !@{$extrusion_path->polyline};
     
     # extrude along the path
@@ -129,7 +129,7 @@ sub extrude_path {
     {
         my $distance_from_last_pos = $self->last_pos->distance_to($path->points->[0]) * $Slic3r::scaling_factor;
         my $distance_threshold = $Slic3r::retract_before_travel;
-        $distance_threshold = 2 * $Slic3r::flow_width / $Slic3r::fill_density * sqrt(2)
+        $distance_threshold = 2 * ($self->layer->flow_width || $Slic3r::flow_width) / $Slic3r::fill_density * sqrt(2)
             if $Slic3r::fill_density > 0 && $description =~ /fill/;
     
         if ($distance_from_last_pos >= $distance_threshold) {
@@ -145,7 +145,7 @@ sub extrude_path {
     $gcode .= $self->unretract if $self->retracted;
     
     # calculate extrusion length per distance unit
-    my $s = $path->flow_spacing || $Slic3r::flow_spacing;
+    my $s = $path->flow_spacing || $self->layer->flow_spacing || $Slic3r::flow_spacing;
     my $h = $path->depth_layers * $self->layer->height;
     my $w = ($s - $Slic3r::min_flow_spacing * $Slic3r::overlap_factor) / (1 - $Slic3r::overlap_factor);
     

+ 2 - 2
lib/Slic3r/Fill.pm

@@ -99,7 +99,7 @@ sub make_fill {
     
     # add spacing between adjacent surfaces
     {
-        my $distance = scale $Slic3r::flow_spacing / 2;
+        my $distance = scale $layer->flow_spacing / 2;
         my @offsets = ();
         foreach my $surface (@surfaces) {
             my $expolygon = $surface->expolygon;
@@ -137,7 +137,7 @@ sub make_fill {
     SURFACE: foreach my $surface (@surfaces) {
         my $filler          = $Slic3r::fill_pattern;
         my $density         = $Slic3r::fill_density;
-        my $flow_spacing    = $Slic3r::flow_spacing;
+        my $flow_spacing    = $layer->flow_spacing;
         my $is_bridge       = $layer->id > 0 && $surface->surface_type == S_TYPE_BOTTOM;
         my $is_solid        = (grep { $surface->surface_type == $_ } S_TYPE_TOP, S_TYPE_BOTTOM, S_TYPE_INTERNALSOLID) ? 1 : 0;
         

+ 1 - 1
lib/Slic3r/Fill/Concentric.pm

@@ -64,7 +64,7 @@ sub fill_surface {
         $path->deserialize;
         
         # clip the path to avoid the extruder to get exactly on the first point of the loop
-        $path->clip_end(scale $Slic3r::flow_width * 0.15);
+        $path->clip_end(scale($self->layer->flow_width || $Slic3r::flow_width) * 0.15);
         
         push @paths, $path->points if @{$path->points};
     }

+ 1 - 1
lib/Slic3r/Fill/Honeycomb.pm

@@ -21,7 +21,7 @@ sub fill_surface {
     # infill math
     my $min_spacing = scale $params{flow_spacing};
     my $distance = $min_spacing / $params{density};
-    my $overlap_distance = scale $Slic3r::flow_width * 0.4;
+    my $overlap_distance = scale($self->layer->flow_width || $Slic3r::flow_width) * 0.4;
     
     my $cache_id = sprintf "d%s_s%s_a%s",
         $params{density}, $params{flow_spacing}, $rotate_vector->[0][0];

+ 1 - 1
lib/Slic3r/Fill/Rectilinear.pm

@@ -32,7 +32,7 @@ sub fill_surface {
         $flow_spacing = unscale $distance_between_lines;
     }
     
-    my $overlap_distance = scale $Slic3r::flow_width * 0.4;
+    my $overlap_distance = scale($self->layer->flow_width || $Slic3r::flow_width) * 0.4;
     
     my $x = $bounding_box->[X1];
     my $is_line_pattern = $self->isa('Slic3r::Fill::Line');

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

@@ -70,7 +70,7 @@ sub new {
         },
         extrusion => {
             title => 'Extrusion',
-            options => [qw(extrusion_width bridge_flow_ratio)],
+            options => [qw(extrusion_width first_layer_extrusion_width bridge_flow_ratio)],
         },
         output => {
             title => 'Output',

+ 23 - 11
lib/Slic3r/Layer.pm

@@ -19,6 +19,8 @@ has 'slicing_errors' => (is => 'rw');
 has 'slice_z' => (is => 'lazy');
 has 'print_z' => (is => 'lazy');
 has 'height'  => (is => 'lazy');
+has 'flow_spacing'  => (is => 'lazy');
+has 'flow_width'  => (is => 'lazy');
 
 # collection of spare segments generated by slicing the original geometry;
 # these need to be merged in continuos (closed) polylines
@@ -99,6 +101,16 @@ sub _build_height {
     return $self->id == 0 ? $Slic3r::_first_layer_height : $Slic3r::layer_height;
 }
 
+sub _build_flow_spacing {
+    my $self = shift;
+    return $self->id == 0 ? $Slic3r::first_layer_flow_spacing : $Slic3r::flow_spacing;
+}
+
+sub _build_flow_width {
+    my $self = shift;
+    return $self->id == 0 ? $Slic3r::first_layer_flow_width : $Slic3r::flow_width;
+}
+
 sub add_line {
     my $self = shift;
     my ($line) = @_;
@@ -127,7 +139,7 @@ sub make_surfaces {
     
     # the contours must be offsetted by half extrusion width inwards
     {
-        my $distance = scale $Slic3r::flow_width / 2;
+        my $distance = scale $self->flow_width / 2;
         my @surfaces = @{$self->slices};
         @{$self->slices} = ();
         foreach my $surface (@surfaces) {
@@ -146,12 +158,12 @@ sub make_surfaces {
         );
         
         if (@$diff) {
-            my $area_threshold = scale($Slic3r::flow_spacing) ** 2;
+            my $area_threshold = scale($self->flow_spacing) ** 2;
             @$diff = grep $_->area > ($area_threshold), @$diff;
             
             push @{$self->thin_walls},
                 grep $_,
-                map $_->medial_axis(scale $Slic3r::flow_width),
+                map $_->medial_axis(scale $self->flow_width),
                 @$diff;
             
             Slic3r::debugf "  %d thin walls detected\n", scalar(@{$self->thin_walls}) if @{$self->thin_walls};
@@ -201,8 +213,8 @@ sub make_perimeters {
             next unless $circumference <= $Slic3r::small_perimeter_length;
             # revert the compensation done in make_surfaces() and get the actual radius
             # of the hole
-            my $radius = ($circumference / PI / 2) - scale $Slic3r::flow_spacing/2;
-            my $new_radius = (scale($Slic3r::flow_width) + sqrt((scale($Slic3r::flow_width)**2) + (4*($radius**2)))) / 2;
+            my $radius = ($circumference / PI / 2) - scale $self->flow_spacing/2;
+            my $new_radius = (scale($self->flow_width) + sqrt((scale($self->flow_width)**2) + (4*($radius**2)))) / 2;
             # holes are always turned to contours, so reverse point order before and after
             $hole->reverse;
             my @offsetted = $hole->offset(+ ($new_radius - $radius));
@@ -221,7 +233,7 @@ sub make_perimeters {
             push @{ $perimeters[-1] }, [@last_offsets];
             
             # offset distance for inner loops
-            $distance = scale $Slic3r::flow_spacing;
+            $distance = scale $self->flow_spacing;
         }
         
         # create one more offset to be used as boundary for fill
@@ -237,7 +249,7 @@ sub make_perimeters {
             );
             push @{ $self->thin_fills },
                 grep $_,
-                map $_->medial_axis(scale $Slic3r::flow_width),
+                map $_->medial_axis(scale $self->flow_width),
                 @$small_gaps if 0;
         }
     }
@@ -309,7 +321,7 @@ sub add_perimeter {
     my $self = shift;
     my ($polygon, $role) = @_;
     
-    return unless $polygon->is_printable;
+    return unless $polygon->is_printable($self->flow_width);
     push @{ $self->perimeters }, Slic3r::ExtrusionLoop->new(
         polygon => $polygon,
         role => (abs($polygon->length) <= $Slic3r::small_perimeter_length) ? EXTR_ROLE_SMALLPERIMETER : ($role // EXTR_ROLE_PERIMETER),  #/
@@ -324,7 +336,7 @@ sub prepare_fill_surfaces {
     # merge too small internal surfaces with their surrounding tops
     # (if they're too small, they can be treated as solid)
     {
-        my $min_area = ((7 * $Slic3r::flow_spacing / $Slic3r::scaling_factor)**2) * PI;
+        my $min_area = ((7 * $self->flow_spacing / $Slic3r::scaling_factor)**2) * PI;
         my $small_internal = [
             grep { $_->expolygon->contour->area <= $min_area }
             grep { $_->surface_type == S_TYPE_INTERNAL }
@@ -357,7 +369,7 @@ sub prepare_fill_surfaces {
 sub remove_small_surfaces {
     my $self = shift;
     
-    my $distance = scale $Slic3r::flow_spacing / 2;
+    my $distance = scale $self->flow_spacing / 2;
     
     my @surfaces = @{$self->fill_surfaces};
     @{$self->fill_surfaces} = ();
@@ -417,7 +429,7 @@ sub process_bridges {
         # offset the contour and intersect it with the internal surfaces to discover 
         # which of them has contact with our bridge
         my @supporting_surfaces = ();
-        my ($contour_offset) = $expolygon->contour->offset(scale $Slic3r::flow_spacing * sqrt(2));
+        my ($contour_offset) = $expolygon->contour->offset(scale $self->flow_spacing * sqrt(2));
         foreach my $internal_surface (@internal_surfaces) {
             my $intersection = intersection_ex([$contour_offset], [$internal_surface->p]);
             if (@$intersection) {

+ 2 - 1
lib/Slic3r/Polygon.pm

@@ -103,6 +103,7 @@ sub subdivide {
 # returns false if the polyline is too tight to be printed
 sub is_printable {
     my $self = shift;
+    my ($flow_width) = @_;
     
     # try to get an inwards offset
     # for a distance equal to half of the extrusion width;
@@ -113,7 +114,7 @@ sub is_printable {
     # detect them and we would be discarding them.
     my $p = $self->clone;
     $p->make_counter_clockwise;
-    return $p->offset(scale $Slic3r::flow_width / 2) ? 1 : 0;
+    return $p->offset(scale($flow_width || $Slic3r::flow_width) / 2) ? 1 : 0;
 }
 
 sub is_valid {

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