From d9b82c79da5c22a21a911d636137394d703246af Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Wed, 13 Mar 2013 01:03:54 +0100
Subject: [PATCH 1/5] Grow narrow infill regions into void - to be tested more

---
 lib/Slic3r/Fill.pm         | 33 +++++++++++++++++++++++++++++----
 lib/Slic3r/Print/Object.pm | 21 ++++++++++++++++++---
 lib/Slic3r/Surface.pm      | 22 ++--------------------
 3 files changed, 49 insertions(+), 27 deletions(-)

diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm
index 85c189cfe..1a76c6a67 100644
--- a/lib/Slic3r/Fill.pm
+++ b/lib/Slic3r/Fill.pm
@@ -13,7 +13,7 @@ use Slic3r::Fill::PlanePath;
 use Slic3r::Fill::Rectilinear;
 use Slic3r::ExtrusionPath ':roles';
 use Slic3r::Geometry qw(X Y PI scale chained_path);
-use Slic3r::Geometry::Clipper qw(union_ex diff_ex);
+use Slic3r::Geometry::Clipper qw(union_ex diff_ex intersection_ex offset);
 use Slic3r::Surface ':types';
 
 
@@ -98,15 +98,40 @@ sub make_fill {
         }
     }
     
-    # add spacing between surfaces
+    # we need to detect any narrow surfaces that might collapse
+    # when adding spacing below
+    # such narrow surfaces are often generated in sloping walls
+    # by bridge_over_infill() and combine_infill() as a result of the
+    # subtraction of the combinable area from the layer infill area,
+    # which leaves small areas near the perimeters
+    # we are going to grow such regions by overlapping them with the void (if any)
+    # TODO: detect and investigate whether there could be narrow regions without
+    # any void neighbors
+    my $distance_between_surfaces = $layerm->infill_flow->scaled_spacing;
     {
-        my $distance = $layerm->infill_flow->scaled_spacing / 2;
-        @surfaces = map $_->offset(-$distance), @surfaces;
+        my $collapsed = diff_ex(
+            [ map @{$_->expolygon}, @surfaces ],
+            [ offset(
+                [ offset([ map @{$_->expolygon}, @surfaces ], -$distance_between_surfaces/2) ],
+                +$distance_between_surfaces/2
+            ) ],
+        );
+        push @surfaces, map Slic3r::Surface->new(
+            expolygon       => $_,
+            surface_type    => S_TYPE_INTERNALSOLID,
+        ), @{intersection_ex(
+            [ offset([ map @$_, @$collapsed ], $distance_between_surfaces) ],
+            [ map @{$_->expolygon}, grep $_->surface_type == S_TYPE_INTERNALVOID, @surfaces ],
+        )};
     }
     
+    # add spacing between surfaces
+    @surfaces = map $_->offset(-$distance_between_surfaces/2), @surfaces;
+    
     my @fills = ();
     my @fills_ordering_points =  ();
     SURFACE: foreach my $surface (@surfaces) {
+        next if $surface->surface_type == S_TYPE_INTERNALVOID;
         my $filler          = $Slic3r::Config->fill_pattern;
         my $density         = $Slic3r::Config->fill_density;
         my $flow_spacing    = ($surface->surface_type == S_TYPE_TOP)
diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm
index 6008e02eb..3e4c1fafc 100644
--- a/lib/Slic3r/Print/Object.pm
+++ b/lib/Slic3r/Print/Object.pm
@@ -516,6 +516,13 @@ sub bridge_over_infill {
                                 [ map $_->p, @$group ],
                                 [ map @$_, @$to_bridge ],
                             )};
+                            push @new_surfaces, map Slic3r::Surface->new(
+                                expolygon       => $_,
+                                surface_type    => S_TYPE_INTERNALVOID,
+                            ), @{intersection_ex(
+                                [ map $_->p, @$group ],
+                                [ map @$_, @$to_bridge ],
+                            )};
                         }
                         @{$lower_layerm->fill_surfaces} = @new_surfaces;
                     }
@@ -713,7 +720,7 @@ sub combine_infill {
                     my @this_type   = grep $_->surface_type == $type, @{$layerm->fill_surfaces};
                     my @other_types = grep $_->surface_type != $type, @{$layerm->fill_surfaces};
                     
-                    @this_type = map Slic3r::Surface->new(expolygon => $_, surface_type => $type),
+                    my @new_this_type = map Slic3r::Surface->new(expolygon => $_, surface_type => $type),
                         @{diff_ex(
                             [ map @{$_->expolygon}, @this_type ],
                             [ @intersection_with_clearance ],
@@ -721,12 +728,20 @@ sub combine_infill {
                     
                     # apply surfaces back with adjusted depth to the uppermost layer
                     if ($layerm->id == $layer_id) {
-                        push @this_type,
+                        push @new_this_type,
                             map Slic3r::Surface->new(expolygon => $_, surface_type => $type, depth_layers => $every),
                             @$intersection;
+                    } else {
+                        # save void surfaces
+                        push @this_type,
+                            map Slic3r::Surface->new(expolygon => $_, surface_type => S_TYPE_INTERNALVOID),
+                            @{intersection_ex(
+                                [ map @{$_->expolygon}, @this_type ],
+                                [ @intersection_with_clearance ],
+                            )};
                     }
                     
-                    @{$layerm->fill_surfaces} = (@this_type, @other_types);
+                    @{$layerm->fill_surfaces} = (@new_this_type, @other_types);
                 }
             }
         }
diff --git a/lib/Slic3r/Surface.pm b/lib/Slic3r/Surface.pm
index efa0f46a9..cb8aab313 100644
--- a/lib/Slic3r/Surface.pm
+++ b/lib/Slic3r/Surface.pm
@@ -4,7 +4,7 @@ use warnings;
 
 require Exporter;
 our @ISA = qw(Exporter);
-our @EXPORT_OK   = qw(S_TYPE_TOP S_TYPE_BOTTOM S_TYPE_INTERNAL S_TYPE_INTERNALSOLID S_TYPE_INTERNALBRIDGE);
+our @EXPORT_OK   = qw(S_TYPE_TOP S_TYPE_BOTTOM S_TYPE_INTERNAL S_TYPE_INTERNALSOLID S_TYPE_INTERNALBRIDGE S_TYPE_INTERNALVOID);
 our %EXPORT_TAGS = (types => \@EXPORT_OK);
 
 use constant S_EXPOLYGON    => 0;
@@ -18,6 +18,7 @@ use constant S_TYPE_BOTTOM          => 1;
 use constant S_TYPE_INTERNAL        => 2;
 use constant S_TYPE_INTERNALSOLID   => 3;
 use constant S_TYPE_INTERNALBRIDGE  => 4;
+use constant S_TYPE_INTERNALVOID    => 5;
 
 sub new {
     my $class = shift;
@@ -74,17 +75,6 @@ sub offset {
     } $self->expolygon->offset_ex(@_);
 }
 
-sub clipper_polygon {
-    my $self = shift;
-    
-    return {
-        outer => $self->contour->p,
-        holes => [
-            map $_->p, @{$self->holes}
-        ],
-    };
-}
-
 sub p {
     my $self = shift;
     return @{$self->expolygon};
@@ -99,14 +89,6 @@ sub is_solid {
         || $type == S_TYPE_INTERNALSOLID;
 }
 
-sub is_internal {
-    my $self = shift;
-    my $type = $self->surface_type;
-    return $type == S_TYPE_INTERNAL
-        || $type == S_TYPE_INTERNALSOLID
-        || $type == S_TYPE_INTERNALBRIDGE;
-}
-
 sub is_bridge {
     my $self = shift;
     my $type = $self->surface_type;

From 9713b9f524da2fc7c8cd63f9013f311633cb047a Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Wed, 13 Mar 2013 14:55:58 +0100
Subject: [PATCH 2/5] Fix narrow fills growing

---
 lib/Slic3r/Fill.pm             | 14 ++++++++++----
 lib/Slic3r/Geometry/Clipper.pm | 10 +++++++++-
 2 files changed, 19 insertions(+), 5 deletions(-)

diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm
index 1a76c6a67..f954c0599 100644
--- a/lib/Slic3r/Fill.pm
+++ b/lib/Slic3r/Fill.pm
@@ -13,7 +13,7 @@ use Slic3r::Fill::PlanePath;
 use Slic3r::Fill::Rectilinear;
 use Slic3r::ExtrusionPath ':roles';
 use Slic3r::Geometry qw(X Y PI scale chained_path);
-use Slic3r::Geometry::Clipper qw(union_ex diff_ex intersection_ex offset);
+use Slic3r::Geometry::Clipper qw(union_ex diff diff_ex intersection_ex offset);
 use Slic3r::Surface ':types';
 
 
@@ -109,19 +109,25 @@ sub make_fill {
     # any void neighbors
     my $distance_between_surfaces = $layerm->infill_flow->scaled_spacing;
     {
-        my $collapsed = diff_ex(
+        my $collapsed = diff(
             [ map @{$_->expolygon}, @surfaces ],
             [ offset(
                 [ offset([ map @{$_->expolygon}, @surfaces ], -$distance_between_surfaces/2) ],
                 +$distance_between_surfaces/2
             ) ],
+            1,
         );
         push @surfaces, map Slic3r::Surface->new(
             expolygon       => $_,
             surface_type    => S_TYPE_INTERNALSOLID,
         ), @{intersection_ex(
-            [ offset([ map @$_, @$collapsed ], $distance_between_surfaces) ],
-            [ map @{$_->expolygon}, grep $_->surface_type == S_TYPE_INTERNALVOID, @surfaces ],
+            [ offset($collapsed, $distance_between_surfaces) ],
+            [
+                (map @{$_->expolygon}, grep $_->surface_type == S_TYPE_INTERNALVOID, @surfaces),
+                (@$collapsed),
+            ],
+            undef,
+            1,
         )};
     }
     
diff --git a/lib/Slic3r/Geometry/Clipper.pm b/lib/Slic3r/Geometry/Clipper.pm
index 292e88f27..724f6994e 100644
--- a/lib/Slic3r/Geometry/Clipper.pm
+++ b/lib/Slic3r/Geometry/Clipper.pm
@@ -45,7 +45,15 @@ sub diff_ex {
 }
 
 sub diff {
-    return [ map @$_, diff_ex(@_) ];
+    my ($subject, $clip, $safety_offset) = @_;
+    
+    $clipper->clear;
+    $clipper->add_subject_polygons($subject);
+    $clipper->add_clip_polygons($safety_offset ? safety_offset($clip) : $clip);
+    return [
+        map Slic3r::Polygon->new($_),
+            @{ $clipper->execute(CT_DIFFERENCE, PFT_NONZERO, PFT_NONZERO) },
+    ];
 }
 
 sub union_ex {

From 8d2c651ef2bbbcdc046cbd0a598594549add36da Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Sun, 17 Mar 2013 14:58:10 +0100
Subject: [PATCH 3/5] $surface->thickness was erroneously defaulting to 1 mm

---
 lib/Slic3r/Surface.pm | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/Slic3r/Surface.pm b/lib/Slic3r/Surface.pm
index 8849448a2..966dcde41 100644
--- a/lib/Slic3r/Surface.pm
+++ b/lib/Slic3r/Surface.pm
@@ -28,7 +28,7 @@ sub new {
     my $self = [
         map delete $args{$_}, qw(expolygon surface_type thickness thickness_layers bridge_angle extra_perimeters),
     ];
-    $self->[$_] //= 1 for S_THICKNESS, S_THICKNESS_LAYERS;
+    $self->[S_THICKNESS_LAYERS] = 1;
     
     bless $self, $class;
     $self;
@@ -73,8 +73,8 @@ sub group {
     foreach my $surface (@surfaces) {
         my $type = join '_',
             ($params->{merge_solid} && $surface->is_solid) ? 'solid' : $surface->surface_type,
-            ($surface->bridge_angle // ''),
-            $surface->thickness,
+            $surface->bridge_angle // '',
+            $surface->thickness // '',
             $surface->thickness_layers;
         $unique_types{$type} ||= [];
         push @{ $unique_types{$type} }, $surface;

From 7f917671ab9c4ccf998049ffd72cc62e2b785587 Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Sun, 17 Mar 2013 15:39:51 +0100
Subject: [PATCH 4/5] Bugfix: horizontal projection for high-res models might
 show corrupted result

---
 lib/Slic3r/TriangleMesh.pm | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/Slic3r/TriangleMesh.pm b/lib/Slic3r/TriangleMesh.pm
index ea9e664e5..74efc39db 100644
--- a/lib/Slic3r/TriangleMesh.pm
+++ b/lib/Slic3r/TriangleMesh.pm
@@ -585,8 +585,8 @@ sub horizontal_projection {
         push @f, Slic3r::Polygon->new([ map [ @{$self->vertices->[$_]}[X,Y] ], @$facet ]);
     }
     
-    $_->make_counter_clockwise for @f;
     my $scale_vector = Math::Clipper::integerize_coordinate_sets({ bits => 32 }, @f);
+    $_->make_counter_clockwise for @f;  # do this after scaling, as winding order might change while doing that
     my $union = union_ex([ Slic3r::Geometry::Clipper::offset(\@f, 10000) ]);
     Math::Clipper::unscale_coordinate_sets($scale_vector, $_) for @$union;
     return $union;

From 8ce31c2a2bbaf9b984ce87e3234a599fa0e0d3ec Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Mon, 18 Mar 2013 13:32:19 +0100
Subject: [PATCH 5/5] Don't exclude any infill under internal bridges; revert
 infill pattern to rectilinear for internal bridges. #240

---
 lib/Slic3r/Fill.pm         | 4 +---
 lib/Slic3r/Print/Object.pm | 3 ++-
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm
index 6fbb14b7b..e08bc2e70 100644
--- a/lib/Slic3r/Fill.pm
+++ b/lib/Slic3r/Fill.pm
@@ -155,9 +155,7 @@ sub make_fill {
             $density = 1;
             $filler = $Slic3r::Config->solid_fill_pattern;
             if ($is_bridge) {
-                $filler = $surface->surface_type == S_TYPE_INTERNALBRIDGE
-                    ? 'concentric'
-                    : 'rectilinear';
+                $filler = 'rectilinear';
                 $flow_spacing = $layerm->extruders->{infill}->bridge_flow->spacing;
             } elsif ($surface->surface_type == S_TYPE_INTERNALSOLID) {
                 $filler = 'rectilinear';
diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm
index 01c498026..dcca26096 100644
--- a/lib/Slic3r/Print/Object.pm
+++ b/lib/Slic3r/Print/Object.pm
@@ -509,7 +509,8 @@ sub bridge_over_infill {
             
             # exclude infill from the layers below if needed
             # see discussion at https://github.com/alexrj/Slic3r/issues/240
-            {
+            # Update: do not exclude any infill. Sparse infill is able to absorb the excess material.
+            if (0) {
                 my $excess = $layerm->extruders->{infill}->bridge_flow->width - $layerm->height;
                 for (my $i = $layer_id-1; $excess >= $self->layers->[$i]->height; $i--) {
                     Slic3r::debugf "  skipping infill below those areas at layer %d\n", $i;