From 473802ce8c7cd0dd4cc4af2822e1ae906d13d6d5 Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Tue, 23 Dec 2014 01:04:25 +0100
Subject: [PATCH] Use support material interface extruder for layers above
 object's top surfaces too. #1939

---
 lib/Slic3r/Print/SupportMaterial.pm | 66 ++++++++++++++++++++++++-----
 1 file changed, 56 insertions(+), 10 deletions(-)

diff --git a/lib/Slic3r/Print/SupportMaterial.pm b/lib/Slic3r/Print/SupportMaterial.pm
index 5771fcc66..1cb6b4188 100644
--- a/lib/Slic3r/Print/SupportMaterial.pm
+++ b/lib/Slic3r/Print/SupportMaterial.pm
@@ -66,6 +66,10 @@ sub generate {
     $self->clip_with_object($base, $support_z, $object);
     $self->clip_with_shape($base, $shape) if @$shape;
     
+    # Detect what part of base support layers are "reverse interfaces" because they
+    # lie above object's top surfaces.
+    $self->generate_bottom_interface_layers($support_z, $base, $top, $interface);
+    
     # Install support layers into object.
     for my $i (0 .. $#$support_z) {
         $object->add_support_layer(
@@ -415,6 +419,48 @@ sub generate_interface_layers {
     return \%interface;
 }
 
+sub generate_bottom_interface_layers {
+    my ($self, $support_z, $base, $top, $interface) = @_;
+    
+    my $area_threshold = $self->interface_flow->scaled_spacing ** 2;
+    
+    # loop through object's top surfaces
+    foreach my $top_z (sort keys %$top) {
+        my $this = $top->{$top_z};
+        
+        # keep a count of the interface layers we generated for this top surface
+        my $interface_layers = 0;
+        
+        # loop through support layers until we find the one(s) right above the top
+        # surface
+        foreach my $layer_id (0 .. $#$support_z) {
+            my $z = $support_z->[$layer_id];
+            next unless $z > $top_z;
+            
+            # get the support material area that should be considered interface
+            my $interface_area = intersection(
+                $base->{$layer_id},
+                $this,
+            );
+            
+            # discard too small areas
+            $interface_area = [ grep abs($_->area) >= $area_threshold, @$interface_area ];
+            
+            # subtract new interface area from base
+            $base->{$layer_id} = diff(
+                $base->{$layer_id},
+                $interface_area,
+            );
+            
+            # add new interface area to interface
+            push @{$interface->{$layer_id}}, @$interface_area;
+            
+            $interface_layers++;
+            last if $interface_layers == $self->object_config->support_material_interface_layers;
+        }
+    }
+}
+
 sub generate_base_layers {
     my ($self, $support_z, $contact, $interface, $top) = @_;
     
@@ -620,6 +666,7 @@ sub generate_toolpaths {
         # interface and contact infill
         if (@$interface || @$contact_infill) {
             $fillers{interface}->angle($interface_angle);
+            $fillers{interface}->spacing($_interface_flow->spacing);
             
             # find centerline of the external loop
             $interface = offset2($interface, +scaled_epsilon, -(scaled_epsilon + $_interface_flow->scaled_width/2));
@@ -645,20 +692,19 @@ sub generate_toolpaths {
             
             my @paths = ();
             foreach my $expolygon (@{union_ex($interface)}) {
-                my ($params, @p) = $fillers{interface}->fill_surface(
+                my @p = $fillers{interface}->fill_surface(
                     Slic3r::Surface->new(expolygon => $expolygon, surface_type => S_TYPE_INTERNAL),
-                    density     => $interface_density,
-                    flow        => $_interface_flow,
+                    density      => $interface_density,
                     layer_height => $layer->height,
-                    complete    => 1,
+                    complete     => 1,
                 );
-                my $mm3_per_mm = $params->{flow}->mm3_per_mm;
+                my $mm3_per_mm = $_interface_flow->mm3_per_mm;
                 
                 push @paths, map Slic3r::ExtrusionPath->new(
                     polyline    => Slic3r::Polyline->new(@$_),
                     role        => EXTR_ROLE_SUPPORTMATERIAL_INTERFACE,
                     mm3_per_mm  => $mm3_per_mm,
-                    width       => $params->{flow}->width,
+                    width       => $_interface_flow->width,
                     height      => $layer->height,
                 ), @p;
             }
@@ -699,22 +745,22 @@ sub generate_toolpaths {
                 # TODO: use offset2_ex()
                 $to_infill = offset_ex([ map @$_, @$to_infill ], -$_flow->scaled_spacing);
             }
+            $filler->spacing($base_flow->spacing);
             
             foreach my $expolygon (@$to_infill) {
-                my ($params, @p) = $filler->fill_surface(
+                my @p = $filler->fill_surface(
                     Slic3r::Surface->new(expolygon => $expolygon, surface_type => S_TYPE_INTERNAL),
                     density     => $density,
-                    flow        => $base_flow,
                     layer_height => $layer->height,
                     complete    => 1,
                 );
-                my $mm3_per_mm = $params->{flow}->mm3_per_mm;
+                my $mm3_per_mm = $base_flow->mm3_per_mm;
                 
                 push @paths, map Slic3r::ExtrusionPath->new(
                     polyline    => Slic3r::Polyline->new(@$_),
                     role        => EXTR_ROLE_SUPPORTMATERIAL,
                     mm3_per_mm  => $mm3_per_mm,
-                    width       => $params->{flow}->width,
+                    width       => $base_flow->width,
                     height      => $layer->height,
                 ), @p;
             }