Browse Source

Customizable number of interface layers for support material and raft

Alessandro Ranellucci 12 years ago
parent
commit
9222526e03
7 changed files with 132 additions and 56 deletions
  1. 4 0
      README.markdown
  2. 16 0
      lib/Slic3r/Config.pm
  3. 6 1
      lib/Slic3r/GUI/Tab.pm
  4. 6 6
      lib/Slic3r/Layer.pm
  5. 6 6
      lib/Slic3r/Print.pm
  6. 90 43
      lib/Slic3r/Print/Object.pm
  7. 4 0
      slic3r.pl

+ 4 - 0
README.markdown

@@ -209,6 +209,10 @@ The author of the Silk icon set is Mark James.
                             Spacing between pattern lines (mm, default: 2.5)
                             Spacing between pattern lines (mm, default: 2.5)
         --support-material-angle
         --support-material-angle
                             Support material angle in degrees (range: 0-90, default: 0)
                             Support material angle in degrees (range: 0-90, default: 0)
+        --support-material-interface-layers
+                            Number of perpendicular layers between support material and object (0+, default: 0)
+        --support-material-interface-spacing
+                            Spacing between interface pattern lines (mm, set 0 to get a solid layer, default: 0)
         --raft-layers       Number of layers to raise the printed objects by (range: 0+, default: 0)
         --raft-layers       Number of layers to raise the printed objects by (range: 0+, default: 0)
       
       
        Retraction options:
        Retraction options:

+ 16 - 0
lib/Slic3r/Config.pm

@@ -578,6 +578,22 @@ our $Options = {
         type    => 'i',
         type    => 'i',
         default => 0,
         default => 0,
     },
     },
+    'support_material_interface_layers' => {
+        label   => 'Interface layers',
+        tooltip => 'Number of interface layers to insert between the object(s) and support material.',
+        sidetext => 'layers',
+        cli     => 'support-material-interface-layers=i',
+        type    => 'i',
+        default => 0,
+    },
+    'support_material_interface_spacing' => {
+        label   => 'Interface pattern spacing',
+        tooltip => 'Spacing between interface lines. Set zero to get a solid interface.',
+        sidetext => 'mm',
+        cli     => 'support-material-interface-spacing=f',
+        type    => 'f',
+        default => 0,
+    },
     'raft_layers' => {
     'raft_layers' => {
         label   => 'Raft layers',
         label   => 'Raft layers',
         tooltip => 'Number of total raft layers to insert below the object(s).',
         tooltip => 'Number of total raft layers to insert below the object(s).',

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

@@ -454,12 +454,17 @@ sub build {
     $self->add_options_page('Support material', 'building.png', optgroups => [
     $self->add_options_page('Support material', 'building.png', optgroups => [
         {
         {
             title => 'Support material',
             title => 'Support material',
-            options => [qw(support_material support_material_threshold support_material_pattern support_material_spacing support_material_angle)],
+            options => [qw(support_material support_material_threshold)],
         },
         },
         {
         {
             title => 'Raft',
             title => 'Raft',
             options => [qw(raft_layers)],
             options => [qw(raft_layers)],
         },
         },
+        {
+            title => 'Options for support material and raft',
+            options => [qw(support_material_pattern support_material_spacing support_material_angle
+                support_material_interface_layers support_material_interface_spacing)],
+        },
     ]);
     ]);
     
     
     $self->add_options_page('Notes', 'note.png', optgroups => [
     $self->add_options_page('Notes', 'note.png', optgroups => [

+ 6 - 6
lib/Slic3r/Layer.pm

@@ -22,7 +22,7 @@ has 'slices'            => (is => 'rw');
 # ordered collection of extrusion paths to fill surfaces for support material
 # ordered collection of extrusion paths to fill surfaces for support material
 has 'support_islands'           => (is => 'rw');
 has 'support_islands'           => (is => 'rw');
 has 'support_fills'             => (is => 'rw');
 has 'support_fills'             => (is => 'rw');
-has 'support_interface_fills'   => (is => 'rw');
+has 'support_contact_fills'     => (is => 'rw');
 
 
 sub _trigger_id {
 sub _trigger_id {
     my $self = shift;
     my $self = shift;
@@ -59,8 +59,8 @@ sub _build_height {
 
 
 sub _build_flow { $Slic3r::flow }
 sub _build_flow { $Slic3r::flow }
 
 
-# layer height of interface paths in unscaled coordinates
-sub support_material_interface_height {
+# layer height of contact paths in unscaled coordinates
+sub support_material_contact_height {
     my $self = shift;
     my $self = shift;
     
     
     return $self->height if $self->id == 0;
     return $self->height if $self->id == 0;
@@ -72,10 +72,10 @@ sub support_material_interface_height {
     return 2*$self->height - $self->flow->nozzle_diameter;
     return 2*$self->height - $self->flow->nozzle_diameter;
 }
 }
 
 
-# Z used for printing support material interface in scaled coordinates
-sub support_material_interface_z {
+# Z used for printing support material contact in scaled coordinates
+sub support_material_contact_z {
     my $self = shift;
     my $self = shift;
-    return $self->print_z - ($self->height - $self->support_material_interface_height) / &Slic3r::SCALING_FACTOR;
+    return $self->print_z - ($self->height - $self->support_material_contact_height) / &Slic3r::SCALING_FACTOR;
 }
 }
 
 
 sub region {
 sub region {

+ 6 - 6
lib/Slic3r/Print.pm

@@ -749,7 +749,7 @@ sub write_gcode {
                 if $Slic3r::Config->bed_temperature && $Slic3r::Config->bed_temperature != $Slic3r::Config->first_layer_bed_temperature;
                 if $Slic3r::Config->bed_temperature && $Slic3r::Config->bed_temperature != $Slic3r::Config->first_layer_bed_temperature;
         }
         }
         
         
-        # set new layer, but don't move Z as support material interfaces may need an intermediate one
+        # set new layer, but don't move Z as support material contact areas may need an intermediate one
         $gcode .= $gcodegen->change_layer($self->objects->[$object_copies->[0][0]]->layers->[$layer_id]);
         $gcode .= $gcodegen->change_layer($self->objects->[$object_copies->[0][0]]->layers->[$layer_id]);
         $gcodegen->elapsed_time(0);
         $gcodegen->elapsed_time(0);
         
         
@@ -802,12 +802,12 @@ sub write_gcode {
             # extrude support material before other things because it might use a lower Z
             # extrude support material before other things because it might use a lower Z
             # and also because we avoid travelling on other things when printing it
             # and also because we avoid travelling on other things when printing it
             if ($Slic3r::Config->support_material || $self->config->raft_layers > 0) {
             if ($Slic3r::Config->support_material || $self->config->raft_layers > 0) {
-                $gcode .= $gcodegen->move_z($layer->support_material_interface_z)
-                    if ($layer->support_interface_fills && @{ $layer->support_interface_fills->paths });
+                $gcode .= $gcodegen->move_z($layer->support_material_contact_z)
+                    if ($layer->support_contact_fills && @{ $layer->support_contact_fills->paths });
                 $gcode .= $gcodegen->set_extruder($self->extruders->[$Slic3r::Config->support_material_extruder-1]);
                 $gcode .= $gcodegen->set_extruder($self->extruders->[$Slic3r::Config->support_material_extruder-1]);
-                if ($layer->support_interface_fills) {
-                    $gcode .= $gcodegen->extrude_path($_, 'support material interface') 
-                        for $layer->support_interface_fills->shortest_path($gcodegen->last_pos); 
+                if ($layer->support_contact_fills) {
+                    $gcode .= $gcodegen->extrude_path($_, 'support material contact area') 
+                        for $layer->support_contact_fills->shortest_path($gcodegen->last_pos); 
                 }
                 }
                 
                 
                 $gcode .= $gcodegen->move_z($layer->print_z);
                 $gcode .= $gcodegen->move_z($layer->print_z);

+ 90 - 43
lib/Slic3r/Print/Object.pm

@@ -587,10 +587,11 @@ sub generate_support_material {
     # determine support regions in each layer (for upper layers)
     # determine support regions in each layer (for upper layers)
     Slic3r::debugf "Detecting regions\n";
     Slic3r::debugf "Detecting regions\n";
     my %layers = ();            # this represents the areas of each layer having to support upper layers (excluding interfaces)
     my %layers = ();            # this represents the areas of each layer having to support upper layers (excluding interfaces)
-    my %layers_interfaces = (); # this represents the areas of each layer having an overhang in the immediately upper layer
+    my %layers_interfaces = (); # this represents the areas of each layer to be filled with interface pattern, excluding the contact areas which are stored separately
+    my %layers_contact_areas = (); # this represents the areas of each layer having an overhang in the immediately upper layer
     {
     {
         my @current_support_regions = ();   # expolygons we've started to support (i.e. below the empty interface layers)
         my @current_support_regions = ();   # expolygons we've started to support (i.e. below the empty interface layers)
-        my @queue = ();                     # the number of items of this array determines the number of empty interface layers
+        my @upper_layers_overhangs = (map [], 1..$Slic3r::Config->support_material_interface_layers);
         for my $i (reverse 0 .. $#{$self->layers}) {
         for my $i (reverse 0 .. $#{$self->layers}) {
             next unless $Slic3r::Config->support_material || ($i <= $Slic3r::Config->raft_layers);  # <= because we need to start from the first non-raft layer
             next unless $Slic3r::Config->support_material || ($i <= $Slic3r::Config->raft_layers);  # <= because we need to start from the first non-raft layer
             
             
@@ -599,31 +600,48 @@ sub generate_support_material {
             
             
             my @current_layer_offsetted_slices = map $_->offset_ex($distance_from_object), @{$layer->slices};
             my @current_layer_offsetted_slices = map $_->offset_ex($distance_from_object), @{$layer->slices};
             
             
-            # $queue[-1] contains the overhangs of the upper layer, regardless of any empty interface layers
-            # $queue[0] contains the overhangs of the first upper layer above the empty interface layers
-            $layers_interfaces{$i} = diff_ex(
-                [ map @$_, @{ $queue[-1] || [] } ],
+            # $upper_layers_overhangs[-1] contains the overhangs of the upper layer, regardless of any interface layers
+            # $upper_layers_overhangs[0] contains the overhangs of the first upper layer above the interface layers
+            
+            # we only consider the overhangs of the upper layer to define contact areas of the current one
+            $layers_contact_areas{$i} = diff_ex(
+                [ map @$_, @{ $upper_layers_overhangs[-1] || [] } ],
                 [ map @$_, @current_layer_offsetted_slices ],
                 [ map @$_, @current_layer_offsetted_slices ],
             );
             );
+            $_->simplify($flow->scaled_spacing) for @{$layers_contact_areas{$i}};
             
             
-            # step 1: generate support material in current layer (for upper layers)
-            push @current_support_regions, @{ shift @queue } if @queue && $i < $#{$self->layers};
+            # to define interface regions of this layer we consider the overhangs of all the upper layers
+            # minus the first one
+            $layers_interfaces{$i} = diff_ex(
+                [ map @$_, map @$_, @upper_layers_overhangs[0 .. $#upper_layers_overhangs-1] ],
+                [
+                    (map @$_, @current_layer_offsetted_slices),
+                    (map @$_, @{ $layers_contact_areas{$i} }),
+                ],
+            );
+            $_->simplify($flow->scaled_spacing) for @{$layers_interfaces{$i}};
             
             
+            # generate support material in current layer (for upper layers)
             @current_support_regions = @{diff_ex(
             @current_support_regions = @{diff_ex(
-                [ map @$_, @current_support_regions ],
+                [
+                    (map @$_, @current_support_regions),
+                    (map @$_, @{ $upper_layers_overhangs[-1] || [] }),   # only considering -1 instead of the whole array contents is just an optimization
+                ],
                 [ map @$_, @{$layer->slices} ],
                 [ map @$_, @{$layer->slices} ],
             )};
             )};
+            shift @upper_layers_overhangs;
             
             
             $layers{$i} = diff_ex(
             $layers{$i} = diff_ex(
                 [ map @$_, @current_support_regions ],
                 [ map @$_, @current_support_regions ],
                 [
                 [
                     (map @$_, @current_layer_offsetted_slices),
                     (map @$_, @current_layer_offsetted_slices),
+                    (map @$_, @{ $layers_contact_areas{$i} }),
                     (map @$_, @{ $layers_interfaces{$i} }),
                     (map @$_, @{ $layers_interfaces{$i} }),
                 ],
                 ],
             );
             );
             $_->simplify($flow->scaled_spacing) for @{$layers{$i}};
             $_->simplify($flow->scaled_spacing) for @{$layers{$i}};
             
             
-            # step 2: get layer overhangs and put them into queue for adding support inside lower layers
+            # get layer overhangs and put them into queue for adding support inside lower layers;
             # we need an angle threshold for this
             # we need an angle threshold for this
             my @overhangs = ();
             my @overhangs = ();
             if ($lower_layer) {
             if ($lower_layer) {
@@ -633,17 +651,23 @@ sub generate_support_material {
                     1,
                     1,
                 )};
                 )};
             }
             }
-            push @queue, [@overhangs];
+            push @upper_layers_overhangs, [@overhangs];
+            
+            if ($Slic3r::debug) {
+                printf "Layer %d has %d generic support areas, %d normal interface areas, %d contact areas\n",
+                    $i, scalar(@{$layers{$i}}), scalar(@{$layers_interfaces{$i}}), scalar(@{$layers_contact_areas{$i}});
+            }
         }
         }
     }
     }
     return if !map @$_, values %layers;
     return if !map @$_, values %layers;
     
     
     # generate paths for the pattern that we're going to use
     # generate paths for the pattern that we're going to use
     Slic3r::debugf "Generating patterns\n";
     Slic3r::debugf "Generating patterns\n";
-    my $support_patterns = [];  # in case we want cross-hatching
+    my $support_patterns = [];
+    my $support_interface_patterns = [];
     {
     {
-        # 0.5 makes sure the paths don't get clipped externally when applying them to layers
-        my @support_material_areas = map $_->offset_ex(- 0.5 * $flow->scaled_width),
+        # 0.5 ensures the paths don't get clipped externally when applying them to layers
+        my @areas = map $_->offset_ex(- 0.5 * $flow->scaled_width),
             @{union_ex([ map $_->contour, map @$_, values %layers ])};
             @{union_ex([ map $_->contour, map @$_, values %layers ])};
         
         
         my $pattern = $Slic3r::Config->support_material_pattern;
         my $pattern = $Slic3r::Config->support_material_pattern;
@@ -653,33 +677,46 @@ sub generate_support_material {
             push @angles, $angles[0] + 90;
             push @angles, $angles[0] + 90;
         }
         }
         my $filler = Slic3r::Fill->filler($pattern);
         my $filler = Slic3r::Fill->filler($pattern);
+        my $make_pattern = sub {
+            my ($expolygon, $density) = @_;
+            
+            my @paths = $filler->fill_surface(
+                Slic3r::Surface->new(expolygon => $expolygon),
+                density         => $density,
+                flow_spacing    => $flow->spacing,
+            );
+            my $params = shift @paths;
+            
+            return map Slic3r::ExtrusionPath->new(
+                polyline        => Slic3r::Polyline->new(@$_),
+                role            => EXTR_ROLE_SUPPORTMATERIAL,
+                height          => undef,
+                flow_spacing    => $params->{flow_spacing},
+            ), @paths;
+        };
         foreach my $angle (@angles) {
         foreach my $angle (@angles) {
             $filler->angle($angle);
             $filler->angle($angle);
-            my @patterns = ();
-            foreach my $expolygon (@support_material_areas) {
-                my @paths = $filler->fill_surface(
-                    Slic3r::Surface->new(expolygon => $expolygon),
-                    density         => $flow->spacing / $pattern_spacing,
-                    flow_spacing    => $flow->spacing,
-                );
-                my $params = shift @paths;
+            {
+                my $density = $flow->spacing / $pattern_spacing;
+                push @$support_patterns, [ map $make_pattern->($_, $density), @areas ];
+            }
+            
+            if ($Slic3r::Config->support_material_interface_layers > 0) {
+                # if pattern is not cross-hatched, rotate the interface pattern by 90° degrees
+                $filler->angle($angle + 90) if @angles == 1;
                 
                 
-                push @patterns,
-                    map Slic3r::ExtrusionPath->new(
-                        polyline        => Slic3r::Polyline->new(@$_),
-                        role            => EXTR_ROLE_SUPPORTMATERIAL,
-                        height          => undef,
-                        flow_spacing    => $params->{flow_spacing},
-                    ), @paths;
+                my $spacing = $Slic3r::Config->support_material_interface_spacing;
+                my $density = $spacing == 0 ? 1 : $flow->spacing / $spacing;
+                push @$support_interface_patterns, [ map $make_pattern->($_, $density), @areas ];
             }
             }
-            push @$support_patterns, [@patterns];
         }
         }
     
     
         if (0) {
         if (0) {
             require "Slic3r/SVG.pm";
             require "Slic3r/SVG.pm";
             Slic3r::SVG::output("support_$_.svg",
             Slic3r::SVG::output("support_$_.svg",
                 polylines        => [ map $_->polyline, map @$_, $support_patterns->[$_] ],
                 polylines        => [ map $_->polyline, map @$_, $support_patterns->[$_] ],
-                polygons         => [ map @$_, @support_material_areas ],
+                red_polylines    => [ map $_->polyline, map @$_, $support_interface_patterns->[$_] ],
+                polygons         => [ map @$_, @areas ],
             ) for 0 .. $#$support_patterns;
             ) for 0 .. $#$support_patterns;
         }
         }
     }
     }
@@ -688,32 +725,39 @@ sub generate_support_material {
     Slic3r::debugf "Applying patterns\n";
     Slic3r::debugf "Applying patterns\n";
     {
     {
         my $clip_pattern = sub {
         my $clip_pattern = sub {
-            my ($layer_id, $expolygons, $height) = @_;
+            my ($layer_id, $expolygons, $height, $is_interface) = @_;
             my @paths = ();
             my @paths = ();
             foreach my $expolygon (@$expolygons) {
             foreach my $expolygon (@$expolygons) {
                 push @paths,
                 push @paths,
                     map $_->pack,
                     map $_->pack,
                     map {
                     map {
                         $_->height($height);
                         $_->height($height);
+                        
+                        # useless line because this coderef isn't called for layer 0 anymore;
+                        # let's keep it here just in case we want to make the base flange optional
+                        # in the future
                         $_->flow_spacing($self->print->first_layer_support_material_flow->spacing)
                         $_->flow_spacing($self->print->first_layer_support_material_flow->spacing)
                             if $layer_id == 0;
                             if $layer_id == 0;
+                        
                         $_;
                         $_;
                     }
                     }
                     map $_->clip_with_expolygon($expolygon),
                     map $_->clip_with_expolygon($expolygon),
                     ###map $_->clip_with_polygon($expolygon->bounding_box_polygon),  # currently disabled as a workaround for Boost failing at being idempotent
                     ###map $_->clip_with_polygon($expolygon->bounding_box_polygon),  # currently disabled as a workaround for Boost failing at being idempotent
-                    @{$support_patterns->[ $layer_id % @$support_patterns ]};
+                    ($is_interface && @$support_interface_patterns)
+                        ? @{$support_interface_patterns->[ $layer_id % @$support_interface_patterns ]}
+                        : @{$support_patterns->[ $layer_id % @$support_patterns ]};
             };
             };
             return @paths;
             return @paths;
         };
         };
         my %layer_paths             = ();
         my %layer_paths             = ();
-        my %layer_interface_paths   = ();
+        my %layer_contact_paths     = ();
         my %layer_islands           = ();
         my %layer_islands           = ();
         my $process_layer = sub {
         my $process_layer = sub {
             my ($layer_id) = @_;
             my ($layer_id) = @_;
             my $layer = $self->layers->[$layer_id];
             my $layer = $self->layers->[$layer_id];
             
             
-            my ($paths, $interface_paths) = ([], []);
-            my $islands = union_ex([ map @$_, map @$_, $layers{$layer_id}, $layers_interfaces{$layer_id} ]);
+            my ($paths, $contact_paths) = ([], []);
+            my $islands = union_ex([ map @$_, map @$_, $layers{$layer_id}, $layers_contact_areas{$layer_id} ]);
             
             
             # make a solid base on bottom layer
             # make a solid base on bottom layer
             if ($layer_id == 0) {
             if ($layer_id == 0) {
@@ -735,10 +779,13 @@ sub generate_support_material {
                     ), @paths;
                     ), @paths;
                 }
                 }
             } else {
             } else {
-                $paths           = [ $clip_pattern->($layer_id, $layers{$layer_id}, $layer->height) ];
-                $interface_paths = [ $clip_pattern->($layer_id, $layers_interfaces{$layer_id}, $layer->support_material_interface_height) ];
+                $paths           = [
+                    $clip_pattern->($layer_id, $layers{$layer_id}, $layer->height),
+                    $clip_pattern->($layer_id, $layers_interfaces{$layer_id}, $layer->height, 1),
+                ];
+                $contact_paths   = [ $clip_pattern->($layer_id, $layers_contact_areas{$layer_id}, $layer->support_material_contact_height, 1) ];
             }
             }
-            return ($paths, $interface_paths, $islands);
+            return ($paths, $contact_paths, $islands);
         };
         };
         Slic3r::parallelize(
         Slic3r::parallelize(
             items => [ keys %layers ],
             items => [ keys %layers ],
@@ -753,10 +800,10 @@ sub generate_support_material {
             },
             },
             collect_cb => sub {
             collect_cb => sub {
                 my $result = shift;
                 my $result = shift;
-                ($layer_paths{$_}, $layer_interface_paths{$_}, $layer_islands{$_}) = @{$result->{$_}} for keys %$result;
+                ($layer_paths{$_}, $layer_contact_paths{$_}, $layer_islands{$_}) = @{$result->{$_}} for keys %$result;
             },
             },
             no_threads_cb => sub {
             no_threads_cb => sub {
-                ($layer_paths{$_}, $layer_interface_paths{$_}, $layer_islands{$_}) = $process_layer->($_) for keys %layers;
+                ($layer_paths{$_}, $layer_contact_paths{$_}, $layer_islands{$_}) = $process_layer->($_) for keys %layers;
             },
             },
         );
         );
         
         
@@ -764,9 +811,9 @@ sub generate_support_material {
             my $layer = $self->layers->[$layer_id];
             my $layer = $self->layers->[$layer_id];
             $layer->support_islands($layer_islands{$layer_id});
             $layer->support_islands($layer_islands{$layer_id});
             $layer->support_fills(Slic3r::ExtrusionPath::Collection->new);
             $layer->support_fills(Slic3r::ExtrusionPath::Collection->new);
-            $layer->support_interface_fills(Slic3r::ExtrusionPath::Collection->new);
+            $layer->support_contact_fills(Slic3r::ExtrusionPath::Collection->new);
             push @{$layer->support_fills->paths}, @{$layer_paths{$layer_id}};
             push @{$layer->support_fills->paths}, @{$layer_paths{$layer_id}};
-            push @{$layer->support_interface_fills->paths}, @{$layer_interface_paths{$layer_id}};
+            push @{$layer->support_contact_fills->paths}, @{$layer_contact_paths{$layer_id}};
         }
         }
     }
     }
 }
 }

+ 4 - 0
slic3r.pl

@@ -257,6 +257,10 @@ $j
                         Spacing between pattern lines (mm, default: $config->{support_material_spacing})
                         Spacing between pattern lines (mm, default: $config->{support_material_spacing})
     --support-material-angle
     --support-material-angle
                         Support material angle in degrees (range: 0-90, default: $config->{support_material_angle})
                         Support material angle in degrees (range: 0-90, default: $config->{support_material_angle})
+    --support-material-interface-layers
+                        Number of perpendicular layers between support material and object (0+, default: $config->{support_material_interface_layers})
+    --support-material-interface-spacing
+                        Spacing between interface pattern lines (mm, set 0 to get a solid layer, default: $config->{support_material_interface_spacing})
     --raft-layers       Number of layers to raise the printed objects by (range: 0+, default: $config->{raft_layers})
     --raft-layers       Number of layers to raise the printed objects by (range: 0+, default: $config->{raft_layers})
   
   
    Retraction options:
    Retraction options: