From dc0f70678984c483cfd61e5eb4c85e648aeb7fa8 Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Thu, 14 Mar 2013 14:27:08 +0100
Subject: [PATCH 1/6] Bugfix: simplification of support areas could lead to
 complex polygons with bad orientation, thus causing wrong pattern clipping.
 #1032

---
 lib/Slic3r/ExPolygon.pm        |  8 ++++++++
 lib/Slic3r/Geometry/Clipper.pm | 11 ++++++++++-
 lib/Slic3r/Print/Object.pm     |  5 ++++-
 3 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/lib/Slic3r/ExPolygon.pm b/lib/Slic3r/ExPolygon.pm
index 770db9a8b..202258ac9 100644
--- a/lib/Slic3r/ExPolygon.pm
+++ b/lib/Slic3r/ExPolygon.pm
@@ -5,6 +5,7 @@ use warnings;
 # an ExPolygon is a polygon with holes
 
 use Boost::Geometry::Utils;
+use List::Util qw(first);
 use Math::Geometry::Voronoi;
 use Slic3r::Geometry qw(X Y A B point_in_polygon same_line line_length epsilon);
 use Slic3r::Geometry::Clipper qw(union_ex JT_MITER);
@@ -54,6 +55,13 @@ sub clipper_expolygon {
     };
 }
 
+sub is_valid {
+    my $self = shift;
+    return (!first { !$_->is_valid } @$self)
+        && $self->contour->is_counter_clockwise
+        && (!first { $_->is_counter_clockwise } $self->holes);
+}
+
 sub boost_polygon {
     my $self = shift;
     return Boost::Geometry::Utils::polygon(@$self);
diff --git a/lib/Slic3r/Geometry/Clipper.pm b/lib/Slic3r/Geometry/Clipper.pm
index 292e88f27..6b259e0bc 100644
--- a/lib/Slic3r/Geometry/Clipper.pm
+++ b/lib/Slic3r/Geometry/Clipper.pm
@@ -4,7 +4,7 @@ use warnings;
 
 require Exporter;
 our @ISA = qw(Exporter);
-our @EXPORT_OK = qw(safety_offset offset offset_ex
+our @EXPORT_OK = qw(safety_offset offset offset_ex collapse_ex
     diff_ex diff union_ex intersection_ex xor_ex PFT_EVENODD JT_MITER JT_ROUND
     JT_SQUARE is_counter_clockwise);
 
@@ -83,4 +83,13 @@ sub xor_ex {
     ];
 }
 
+sub collapse_ex {
+    my ($polygons, $width) = @_;
+    my @result = offset(
+        [ offset($polygons, -$width/2,) ],
+        +$width/2,
+    );
+    return union_ex([@result]);
+}
+
 1;
diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm
index 6008e02eb..947daee56 100644
--- a/lib/Slic3r/Print/Object.pm
+++ b/lib/Slic3r/Print/Object.pm
@@ -4,7 +4,7 @@ use Moo;
 use List::Util qw(min sum first);
 use Slic3r::ExtrusionPath ':roles';
 use Slic3r::Geometry qw(Z PI scale unscale deg2rad rad2deg scaled_epsilon);
-use Slic3r::Geometry::Clipper qw(diff_ex intersection_ex union_ex offset);
+use Slic3r::Geometry::Clipper qw(diff_ex intersection_ex union_ex offset collapse_ex);
 use Slic3r::Surface ':types';
 
 has 'print'             => (is => 'ro', weak_ref => 1, required => 1);
@@ -774,6 +774,7 @@ sub generate_support_material {
                 [ map @$_, @{ $upper_layers_overhangs[-1] || [] } ],
                 [ map @$_, @current_layer_offsetted_slices ],
             );
+            $layers_contact_areas{$i} = collapse_ex([ map @$_, @{$layers_contact_areas{$i}} ], $flow->scaled_width);
             $_->simplify($flow->scaled_spacing) for @{$layers_contact_areas{$i}};
             
             # to define interface regions of this layer we consider the overhangs of all the upper layers
@@ -785,6 +786,7 @@ sub generate_support_material {
                     (map @$_, @{ $layers_contact_areas{$i} }),
                 ],
             );
+            $layers_interfaces{$i} = collapse_ex([ map @$_, @{$layers_interfaces{$i}} ], $flow->scaled_width);
             $_->simplify($flow->scaled_spacing) for @{$layers_interfaces{$i}};
             
             # generate support material in current layer (for upper layers)
@@ -804,6 +806,7 @@ sub generate_support_material {
                     (map @$_, @{ $layers_interfaces{$i} }),
                 ],
             );
+            $layers{$i} = collapse_ex([ map @$_, @{$layers{$i}} ], $flow->scaled_width);
             $_->simplify($flow->scaled_spacing) for @{$layers{$i}};
             
             # get layer overhangs and put them into queue for adding support inside lower layers;

From 33b40eda1848c757b8e659c722683f9c10d35d9f Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Sat, 16 Mar 2013 18:42:56 +0100
Subject: [PATCH 2/6] Always fix self-intersecting polygons that
 Douglas-Peucker might return

---
 lib/Slic3r/ExPolygon.pm           |  9 +++++++--
 lib/Slic3r/ExtrusionPath.pm       |  5 +++++
 lib/Slic3r/GCode/MotionPlanner.pm | 16 +++++++---------
 lib/Slic3r/GUI/Plater.pm          |  3 +--
 lib/Slic3r/Geometry.pm            | 11 +----------
 lib/Slic3r/Geometry/Clipper.pm    | 10 ++++++++++
 lib/Slic3r/Layer/Region.pm        | 16 ++++++++--------
 lib/Slic3r/Polygon.pm             |  5 +++++
 lib/Slic3r/Polyline.pm            |  4 ++--
 lib/Slic3r/Print.pm               |  4 ++--
 lib/Slic3r/Print/Object.pm        | 18 ++++++++++++------
 lib/Slic3r/Surface.pm             | 22 ++++++++++++++++------
 t/clean_polylines.t               | 13 +++++++------
 t/combineinfill.t                 |  4 ++--
 14 files changed, 85 insertions(+), 55 deletions(-)

diff --git a/lib/Slic3r/ExPolygon.pm b/lib/Slic3r/ExPolygon.pm
index 202258ac9..558f9fe21 100644
--- a/lib/Slic3r/ExPolygon.pm
+++ b/lib/Slic3r/ExPolygon.pm
@@ -172,8 +172,13 @@ sub clip_line {
 
 sub simplify {
     my $self = shift;
-    $_->simplify(@_) for @$self;
-    $self;
+    my ($tolerance) = @_;
+    
+    # it would be nice to have a multilinestring_simplify method in B::G::U
+    my @simplified = Slic3r::Geometry::Clipper::simplify_polygons(
+        [ map Boost::Geometry::Utils::linestring_simplify($_, $tolerance), @$self ],
+    );
+    return @{ Slic3r::Geometry::Clipper::union_ex([ @simplified ]) };
 }
 
 sub scale {
diff --git a/lib/Slic3r/ExtrusionPath.pm b/lib/Slic3r/ExtrusionPath.pm
index 825d23e6e..3de639649 100644
--- a/lib/Slic3r/ExtrusionPath.pm
+++ b/lib/Slic3r/ExtrusionPath.pm
@@ -81,6 +81,11 @@ sub clip_with_expolygon {
     return @paths;
 }
 
+sub simplify {
+    my $self = shift;
+    $self->polyline($self->polyline->simplify(@_));
+}
+
 sub points {
     my $self = shift;
     return $self->polyline;
diff --git a/lib/Slic3r/GCode/MotionPlanner.pm b/lib/Slic3r/GCode/MotionPlanner.pm
index d55faeb2a..3708a65e3 100644
--- a/lib/Slic3r/GCode/MotionPlanner.pm
+++ b/lib/Slic3r/GCode/MotionPlanner.pm
@@ -56,22 +56,20 @@ sub BUILD {
         }
     };
     
+    # simplify islands
+    @{$self->islands} = map $_->simplify($self->_inner_margin), @{$self->islands};
+    
     # process individual islands
-    for my $i (0 .. $#{$self->islands}) {
-        # simplify the island's contours
-        $self->islands->[$i]->simplify($self->_inner_margin);
-        
+    for my $i (0 .. $#{$self->islands}) {        
         # offset the island inwards to make the boundaries for internal movements
         # so that no motion along external perimeters happens
-        $self->_inner->[$i] = [ $self->islands->[$i]->offset_ex(-$self->_inner_margin) ]
-            if !$self->no_internal;
+        $self->_inner->[$i] = $self->no_internal
+            ? []
+            : [ $self->islands->[$i]->offset_ex(-$self->_inner_margin) ];
         
         # offset the island outwards to make the boundaries for external movements
         $self->_outer->[$i] = [ $self->islands->[$i]->contour->offset($self->_outer_margin) ];
         
-        # further simplification (isn't this a duplication of the one above?)
-        $_->simplify($self->_inner_margin) for @{$self->_inner->[$i]}, @{$self->_outer->[$i]};
-        
         # if internal motion is enabled, build a set of utility expolygons representing
         # the outer boundaries (as contours) and the inner boundaries (as holes). whenever
         # we jump from a hole to a contour or viceversa, we know we're crossing a perimeter
diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm
index 3b86a597c..0cdd5d04b 100644
--- a/lib/Slic3r/GUI/Plater.pm
+++ b/lib/Slic3r/GUI/Plater.pm
@@ -1137,9 +1137,8 @@ sub make_thumbnail {
     for (map @$_, map @$_, @{$thumbnail->expolygons}) {
         @$_ = map $_ * $self->thumbnail_scaling_factor, @$_;
     }
+    @{$thumbnail->expolygons} = map $_->simplify(0.5), grep $_->area >= 1, @{$thumbnail->expolygons};
     foreach my $expolygon (@{$thumbnail->expolygons}) {
-    	@$expolygon = grep $_->area >= 1, @$expolygon;
-	    $expolygon->simplify(0.5);
     	$expolygon->rotate(Slic3r::Geometry::deg2rad($self->rotate));
     	$expolygon->scale($self->scale);
     }
diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm
index 6a91a2046..0d2d9df4d 100644
--- a/lib/Slic3r/Geometry.pm
+++ b/lib/Slic3r/Geometry.pm
@@ -12,7 +12,7 @@ our @EXPORT_OK = qw(
     point_is_on_left_of_segment polyline_lines polygon_lines nearest_point
     point_along_segment polygon_segment_having_point polygon_has_subsegment
     polygon_has_vertex polyline_length can_connect_points deg2rad rad2deg
-    rotate_points move_points remove_coinciding_points clip_segment_polygon
+    rotate_points move_points clip_segment_polygon
     sum_vectors multiply_vector subtract_vectors dot perp polygon_points_visibility
     line_intersection bounding_box bounding_box_intersect same_point same_line
     longest_segment angle3points three_points_aligned line_direction
@@ -375,15 +375,6 @@ sub move_points {
     return map Slic3r::Point->new($shift->[X] + $_->[X], $shift->[Y] + $_->[Y]), @points;
 }
 
-# preserves order
-sub remove_coinciding_points {
-    my ($points) = @_;
-    
-    my %p = map { sprintf('%f,%f', @$_) => "$_" } @$points;
-    %p = reverse %p;
-    @$points = grep $p{"$_"}, @$points;
-}
-
 # implementation of Liang-Barsky algorithm
 # polygon must be convex and ccw
 sub clip_segment_polygon {
diff --git a/lib/Slic3r/Geometry/Clipper.pm b/lib/Slic3r/Geometry/Clipper.pm
index 6b259e0bc..0cc78b188 100644
--- a/lib/Slic3r/Geometry/Clipper.pm
+++ b/lib/Slic3r/Geometry/Clipper.pm
@@ -92,4 +92,14 @@ sub collapse_ex {
     return union_ex([@result]);
 }
 
+sub simplify_polygon {
+    my ($polygon, $pft) = @_;
+    return @{ Math::Clipper::simplify_polygon($polygon, $pft // PFT_NONZERO) };
+}
+
+sub simplify_polygons {
+    my ($polygons, $pft) = @_;
+    return @{ Math::Clipper::simplify_polygons($polygons, $pft // PFT_NONZERO) };
+}
+
 1;
diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm
index a3b6abe06..99bdbfc15 100644
--- a/lib/Slic3r/Layer/Region.pm
+++ b/lib/Slic3r/Layer/Region.pm
@@ -263,14 +263,14 @@ sub make_perimeters {
             # we offset by half the perimeter spacing (to get to the actual infill boundary)
             # and then we offset back and forth by the infill spacing to only consider the
             # non-collapsing regions
-            my @fill_boundaries = @{union_ex([
-                Slic3r::Geometry::Clipper::offset(
-                    [Slic3r::Geometry::Clipper::offset([ map @$_, @last_offsets ], -($perimeter_spacing/2 + $infill_spacing))], 
-                    +$infill_spacing,
-                ),
-            ])};
-            $_->simplify(&Slic3r::SCALED_RESOLUTION) for @fill_boundaries;
-            push @{ $self->fill_surfaces }, @fill_boundaries;
+            push @{ $self->fill_surfaces },
+                map $_->simplify(&Slic3r::SCALED_RESOLUTION),
+                @{union_ex([
+                    Slic3r::Geometry::Clipper::offset(
+                        [Slic3r::Geometry::Clipper::offset([ map @$_, @last_offsets ], -($perimeter_spacing/2 + $infill_spacing))], 
+                        +$infill_spacing,
+                    ),
+                ])};
         }
         
         # fill gaps
diff --git a/lib/Slic3r/Polygon.pm b/lib/Slic3r/Polygon.pm
index f5b275510..1d759a06b 100644
--- a/lib/Slic3r/Polygon.pm
+++ b/lib/Slic3r/Polygon.pm
@@ -97,6 +97,11 @@ sub grow {
     return $self->split_at_first_point->grow(@_);
 }
 
+sub simplify {
+    my $self = shift;
+    return Slic3r::Geometry::Clipper::simplify_polygon( $self->SUPER::simplify(@_) );
+}
+
 # this method subdivides the polygon segments to that no one of them
 # is longer than the length provided
 sub subdivide {
diff --git a/lib/Slic3r/Polyline.pm b/lib/Slic3r/Polyline.pm
index 631030604..2578e505d 100644
--- a/lib/Slic3r/Polyline.pm
+++ b/lib/Slic3r/Polyline.pm
@@ -68,8 +68,8 @@ sub simplify {
     my $self = shift;
     my $tolerance = shift || 10;
     
-    @$self = @{ Boost::Geometry::Utils::linestring_simplify($self, $tolerance) };
-    bless $_, 'Slic3r::Point' for @$self;
+    my $simplified = Boost::Geometry::Utils::linestring_simplify($self, $tolerance);
+    return (ref $self)->new($simplified);
 }
 
 sub reverse {
diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm
index e69ed7563..075b4edc2 100644
--- a/lib/Slic3r/Print.pm
+++ b/lib/Slic3r/Print.pm
@@ -335,8 +335,8 @@ sub export_gcode {
     # simplify slices (both layer and region slices),
     # we only need the max resolution for perimeters
     foreach my $layer (map @{$_->layers}, @{$self->objects}) {
-        $_->simplify(&Slic3r::SCALED_RESOLUTION)
-            for @{$layer->slices}, (map $_->expolygon, map @{$_->slices}, @{$layer->regions});
+        @$_ = map $_->simplify(&Slic3r::SCALED_RESOLUTION), @$_
+            for $layer->slices, (map $_->slices, @{$layer->regions});
     }
     
     # this will assign a type (top/bottom/internal) to $layerm->slices
diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm
index 947daee56..51527d0f6 100644
--- a/lib/Slic3r/Print/Object.pm
+++ b/lib/Slic3r/Print/Object.pm
@@ -774,8 +774,10 @@ sub generate_support_material {
                 [ map @$_, @{ $upper_layers_overhangs[-1] || [] } ],
                 [ map @$_, @current_layer_offsetted_slices ],
             );
-            $layers_contact_areas{$i} = collapse_ex([ map @$_, @{$layers_contact_areas{$i}} ], $flow->scaled_width);
-            $_->simplify($flow->scaled_spacing) for @{$layers_contact_areas{$i}};
+            $layers_contact_areas{$i} = [
+                map $_->simplify($flow->scaled_spacing), 
+                    collapse_ex([ map @$_, @{$layers_contact_areas{$i}} ], $flow->scaled_width),
+            ];
             
             # to define interface regions of this layer we consider the overhangs of all the upper layers
             # minus the first one
@@ -786,8 +788,10 @@ sub generate_support_material {
                     (map @$_, @{ $layers_contact_areas{$i} }),
                 ],
             );
-            $layers_interfaces{$i} = collapse_ex([ map @$_, @{$layers_interfaces{$i}} ], $flow->scaled_width);
-            $_->simplify($flow->scaled_spacing) for @{$layers_interfaces{$i}};
+            $layers_interfaces{$i} = [
+                map $_->simplify($flow->scaled_spacing), 
+                    collapse_ex([ map @$_, @{$layers_interfaces{$i}} ], $flow->scaled_width),
+            ];
             
             # generate support material in current layer (for upper layers)
             @current_support_regions = @{diff_ex(
@@ -806,8 +810,10 @@ sub generate_support_material {
                     (map @$_, @{ $layers_interfaces{$i} }),
                 ],
             );
-            $layers{$i} = collapse_ex([ map @$_, @{$layers{$i}} ], $flow->scaled_width);
-            $_->simplify($flow->scaled_spacing) for @{$layers{$i}};
+            $layers{$i} = [
+                map $_->simplify($flow->scaled_spacing), 
+                    collapse_ex([ map @$_, @{$layers{$i}} ], $flow->scaled_width),
+            ];
             
             # get layer overhangs and put them into queue for adding support inside lower layers;
             # we need an angle threshold for this
diff --git a/lib/Slic3r/Surface.pm b/lib/Slic3r/Surface.pm
index 2864a8643..2272c6d38 100644
--- a/lib/Slic3r/Surface.pm
+++ b/lib/Slic3r/Surface.pm
@@ -81,12 +81,22 @@ sub group {
 
 sub offset {
     my $self = shift;
-    return map {
-        (ref $self)->new(
-            expolygon => $_,
-            map { $_ => $self->$_ } qw(surface_type depth_layers bridge_angle),
-        )
-    } $self->expolygon->offset_ex(@_);
+    return map $self->_inflate_expolygon($_), $self->expolygon->offset_ex(@_);
+}
+
+sub simplify {
+    my $self = shift;
+    return map $self->_inflate_expolygon($_), $self->expolygon->simplify(@_);
+}
+
+sub _inflate_expolygon {
+    my $self = shift;
+    my ($expolygon) = @_;
+    
+    return (ref $self)->new(
+        expolygon => $expolygon,
+        map { $_ => $self->$_ } qw(surface_type depth_layers bridge_angle),
+    );
 }
 
 sub clipper_polygon {
diff --git a/t/clean_polylines.t b/t/clean_polylines.t
index 064b7bd3a..9f7b3ce27 100644
--- a/t/clean_polylines.t
+++ b/t/clean_polylines.t
@@ -2,7 +2,7 @@ use Test::More;
 use strict;
 use warnings;
 
-plan tests => 6;
+plan tests => 7;
 
 BEGIN {
     use FindBin;
@@ -24,7 +24,7 @@ use Slic3r;
     my $polyline = Slic3r::Polyline->new([
         [0,0],[1,0],[2,0],[2,1],[2,2],[1,2],[0,2],[0,1],[0,0],
     ]);
-    $polyline->simplify(1);
+    $polyline = $polyline->simplify(1);
     is_deeply $polyline, [ [0, 0], [2, 0], [2, 2], [0, 2], [0, 0] ], 'Douglas-Peucker';
 }
 
@@ -33,7 +33,7 @@ use Slic3r;
         [0,0],[0.5,0.5],[1,0],[1.25,-0.25],[1.5,.5],
     ]);
     $polyline->scale(100);
-    $polyline->simplify(25);
+    $polyline = $polyline->simplify(25);
     is_deeply $polyline, [ [0, 0], [50, 50], [125, -25], [150, 50] ], 'Douglas-Peucker';
 }
 
@@ -75,9 +75,10 @@ use Slic3r;
     ok @$polygon < @$gear, 'gear was simplified using merge_continuous_lines';
 
     my $num_points = scalar @$polygon;
-    $polygon->simplify;
-    note sprintf "original points: %d\nnew points: %d", $num_points, scalar(@$polygon);
-    ok @$polygon < $num_points, 'gear was further simplified using Douglas-Peucker';
+    my @simplified = $polygon->simplify;
+    ok @simplified == 1, 'gear simplified to a single polygon';
+    note sprintf "original points: %d\nnew points: %d", $num_points, scalar(@{$simplified[0]});
+    ok @{$simplified[0]} < $num_points, 'gear was further simplified using Douglas-Peucker';
 }
 
 {
diff --git a/t/combineinfill.t b/t/combineinfill.t
index e2e63f4a0..f5f54fa85 100644
--- a/t/combineinfill.t
+++ b/t/combineinfill.t
@@ -43,8 +43,8 @@ use Slic3r::Test;
         $_->slice(keep_meshes => 1) for @{$self->objects};
         $_->make_perimeters for @{$self->objects};
         foreach my $layer (map @{$_->layers}, @{$self->objects}) {
-            $_->simplify(&Slic3r::SCALED_RESOLUTION)
-                for @{$layer->slices}, (map $_->expolygon, map @{$_->slices}, @{$layer->regions});
+            @$_ = map $_->simplify(&Slic3r::SCALED_RESOLUTION), @$_
+                for $layer->slices, (map $_->slices, @{$layer->regions});
         }
         $_->detect_surfaces_type for @{$self->objects};
         $_->prepare_fill_surfaces for map @{$_->regions}, map @{$_->layers}, @{$self->objects};

From db2e76a0df1d030b48fa66d44f384dffd2bd4802 Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Sat, 16 Mar 2013 18:56:49 +0100
Subject: [PATCH 3/6] New option to change perimeter order. #534

---
 README.markdown            | 1 +
 lib/Slic3r/Config.pm       | 7 +++++++
 lib/Slic3r/GUI/Tab.pm      | 2 +-
 lib/Slic3r/Layer/Region.pm | 8 ++++++--
 slic3r.pl                  | 1 +
 5 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/README.markdown b/README.markdown
index 5015e2314..df651b6a0 100644
--- a/README.markdown
+++ b/README.markdown
@@ -197,6 +197,7 @@ The author of the Silk icon set is Mark James.
         --extra-perimeters  Add more perimeters when needed (default: yes)
         --randomize-start   Randomize starting point across layers (default: yes)
         --avoid-crossing-perimeters Optimize travel moves so that no perimeters are crossed (default: no)
+        --external-perimeters-first Reverse perimeter order. (default: no)
         --only-retract-when-crossing-perimeters
                             Disable retraction when travelling between infill paths inside the same island.
                             (default: yes)
diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm
index 0017d9257..454afd40c 100644
--- a/lib/Slic3r/Config.pm
+++ b/lib/Slic3r/Config.pm
@@ -562,6 +562,13 @@ our $Options = {
         type    => 'bool',
         default => 0,
     },
+    'external_perimeters_first' => {
+        label   => 'External perimeters first',
+        tooltip => 'Print contour perimeters from the outermost one to the innermost one instead of the default inverse order.',
+        cli     => 'external-perimeters-first!',
+        type    => 'bool',
+        default => 0,
+    },
     'only_retract_when_crossing_perimeters' => {
         label   => 'Only retract when crossing perimeters',
         tooltip => 'Disables retraction when travelling between infill paths inside the same island.',
diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm
index 35637c886..79f9af96e 100644
--- a/lib/Slic3r/GUI/Tab.pm
+++ b/lib/Slic3r/GUI/Tab.pm
@@ -407,7 +407,7 @@ sub build {
         },
         {
             title => 'Advanced',
-            options => [qw(avoid_crossing_perimeters)],
+            options => [qw(avoid_crossing_perimeters external_perimeters_first)],
         },
     ]);
     
diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm
index 99bdbfc15..1c365dd42 100644
--- a/lib/Slic3r/Layer/Region.pm
+++ b/lib/Slic3r/Layer/Region.pm
@@ -404,10 +404,14 @@ sub make_perimeters {
             }
         }
         
-        # do holes, then contours starting from innermost one
+        # first do holes
         $self->_add_perimeter($holes[$_], $is_external{$_} ? EXTR_ROLE_EXTERNAL_PERIMETER : undef)
             for reverse 0 .. $#holes;
-        for my $depth (reverse 0 .. $#$island) {
+        
+        # then do contours according to the user settings
+        my @contour_order = 0 .. $#$island;
+        @contour_order = reverse @contour_order if !$Slic3r::Config->external_perimeters_first;
+        for my $depth (@contour_order) {
             my $role = $depth == $#$island ? EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER
                 : $depth == 0 ? EXTR_ROLE_EXTERNAL_PERIMETER
                 : EXTR_ROLE_PERIMETER;
diff --git a/slic3r.pl b/slic3r.pl
index 301c6b85d..4290ceb8e 100755
--- a/slic3r.pl
+++ b/slic3r.pl
@@ -250,6 +250,7 @@ $j
     --extra-perimeters  Add more perimeters when needed (default: yes)
     --randomize-start   Randomize starting point across layers (default: yes)
     --avoid-crossing-perimeters Optimize travel moves so that no perimeters are crossed (default: no)
+    --external-perimeters-first Reverse perimeter order. (default: no)
     --only-retract-when-crossing-perimeters
                         Disable retraction when travelling between infill paths inside the same island.
                         (default: no)

From f4b81856988456984f71457367696557e2a8c6f3 Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Sat, 16 Mar 2013 19:11:49 +0100
Subject: [PATCH 4/6] Fixed typo preventing support material to work with new
 simplify() syntax

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

diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm
index 51527d0f6..6ab07bd6b 100644
--- a/lib/Slic3r/Print/Object.pm
+++ b/lib/Slic3r/Print/Object.pm
@@ -776,7 +776,7 @@ sub generate_support_material {
             );
             $layers_contact_areas{$i} = [
                 map $_->simplify($flow->scaled_spacing), 
-                    collapse_ex([ map @$_, @{$layers_contact_areas{$i}} ], $flow->scaled_width),
+                    @{collapse_ex([ map @$_, @{$layers_contact_areas{$i}} ], $flow->scaled_width)},
             ];
             
             # to define interface regions of this layer we consider the overhangs of all the upper layers
@@ -790,7 +790,7 @@ sub generate_support_material {
             );
             $layers_interfaces{$i} = [
                 map $_->simplify($flow->scaled_spacing), 
-                    collapse_ex([ map @$_, @{$layers_interfaces{$i}} ], $flow->scaled_width),
+                    @{collapse_ex([ map @$_, @{$layers_interfaces{$i}} ], $flow->scaled_width)},
             ];
             
             # generate support material in current layer (for upper layers)
@@ -812,7 +812,7 @@ sub generate_support_material {
             );
             $layers{$i} = [
                 map $_->simplify($flow->scaled_spacing), 
-                    collapse_ex([ map @$_, @{$layers{$i}} ], $flow->scaled_width),
+                    @{collapse_ex([ map @$_, @{$layers{$i}} ], $flow->scaled_width)},
             ];
             
             # get layer overhangs and put them into queue for adding support inside lower layers;

From 10b6bc9d15e8a284cb8c98abb6aadb8d5724e9fb Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Sat, 16 Mar 2013 19:39:00 +0100
Subject: [PATCH 5/6] Removed keep_meshes

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

diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm
index 075b4edc2..e5025cc09 100644
--- a/lib/Slic3r/Print.pm
+++ b/lib/Slic3r/Print.pm
@@ -324,7 +324,7 @@ sub export_gcode {
     # skein the STL into layers
     # each layer has surfaces with holes
     $status_cb->(10, "Processing triangulated mesh");
-    $_->slice(keep_meshes => $params{keep_meshes}) for @{$self->objects};
+    $_->slice for @{$self->objects};
     
     # make perimeters
     # this will add a set of extrusion loops to each layer
@@ -477,7 +477,7 @@ sub export_svg {
     # calls ->perimeter_flow
     $self->init_extruders;
     
-    $_->slice(keep_meshes => $params{keep_meshes}) for @{$self->objects};
+    $_->slice for @{$self->objects};
     $self->arrange_objects;
     
     my $output_file = $self->expanded_output_filepath($params{output_file});
diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm
index 6ab07bd6b..3abc5c2d7 100644
--- a/lib/Slic3r/Print/Object.pm
+++ b/lib/Slic3r/Print/Object.pm
@@ -121,7 +121,7 @@ sub slice {
     die "Invalid input file\n" if !@{$self->layers};
     
     # free memory
-    $self->meshes(undef) unless $params{keep_meshes};
+    $self->meshes(undef);
     
     # remove last layer if empty
     # (we might have created it because of the $max_layer = ... + 1 code in TriangleMesh)
diff --git a/t/combineinfill.t b/t/combineinfill.t
index f5f54fa85..77eabcc02 100644
--- a/t/combineinfill.t
+++ b/t/combineinfill.t
@@ -40,7 +40,7 @@ use Slic3r::Test;
         # copy of Print::export_gcode() up to the point 
         # after fill surfaces are combined
         $self->init_extruders;
-        $_->slice(keep_meshes => 1) for @{$self->objects};
+        $_->slice for @{$self->objects};
         $_->make_perimeters for @{$self->objects};
         foreach my $layer (map @{$_->layers}, @{$self->objects}) {
             @$_ = map $_->simplify(&Slic3r::SCALED_RESOLUTION), @$_

From cf5adca928d246802bc47bf3d4df648538ca80c3 Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Sat, 16 Mar 2013 19:58:34 +0100
Subject: [PATCH 6/6] New --resolution option to simplify input models

---
 README.markdown       |  1 +
 lib/Slic3r/Config.pm  |  9 +++++++++
 lib/Slic3r/GUI/Tab.pm |  6 +++---
 lib/Slic3r/Print.pm   | 20 ++++++++++++++++----
 slic3r.pl             |  1 +
 5 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/README.markdown b/README.markdown
index df651b6a0..ffebd1481 100644
--- a/README.markdown
+++ b/README.markdown
@@ -289,6 +289,7 @@ The author of the Silk icon set is Mark James.
        
        Miscellaneous options:
         --notes             Notes to be added as comments to the output file
+        --resolution        Minimum detail resolution (mm, set zero for full resolution, default: 0)
       
        Flow options (advanced):
         --extrusion-width   Set extrusion width manually; it accepts either an absolute value in mm
diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm
index 454afd40c..1bd9657a0 100644
--- a/lib/Slic3r/Config.pm
+++ b/lib/Slic3r/Config.pm
@@ -37,6 +37,15 @@ our $Options = {
         default => $Slic3r::have_threads ? 2 : 1,
         readonly => !$Slic3r::have_threads,
     },
+    'resolution' => {
+        label   => 'Resolution',
+        tooltip => 'Minimum detail resolution, used to simplify the input file for speeding up the slicing job and reducing memory usage. High-resolution models often carry more detail than printers can render. Set to zero to disable any simplification and use full resolution from input.',
+        sidetext => 'mm',
+        cli     => 'resolution=f',
+        type    => 'f',
+        min     => 0,
+        default => 0,
+    },
 
     # output options
     'output_filename_format' => {
diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm
index 79f9af96e..fa10383e5 100644
--- a/lib/Slic3r/GUI/Tab.pm
+++ b/lib/Slic3r/GUI/Tab.pm
@@ -517,10 +517,10 @@ sub build {
             title => 'Flow',
             options => [qw(bridge_flow_ratio)],
         },
-        $Slic3r::have_threads ? {
+        {
             title => 'Other',
-            options => [qw(threads)],
-        } : (),
+            options => [($Slic3r::have_threads ? qw(threads) : ()), qw(resolution)],
+        },
     ]);
 }
 
diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm
index e5025cc09..3be7fe87b 100644
--- a/lib/Slic3r/Print.pm
+++ b/lib/Slic3r/Print.pm
@@ -313,6 +313,16 @@ sub size {
     return [ $bb[X2] - $bb[X1], $bb[Y2] - $bb[Y1] ];
 }
 
+sub _simplify_slices {
+    my $self = shift;
+    my ($distance) = @_;
+    
+    foreach my $layer (map @{$_->layers}, @{$self->objects}) {
+        @$_ = map $_->simplify($distance), @$_
+            for $layer->slices, (map $_->slices, @{$layer->regions});
+    }
+}
+
 sub export_gcode {
     my $self = shift;
     my %params = @_;
@@ -326,6 +336,11 @@ sub export_gcode {
     $status_cb->(10, "Processing triangulated mesh");
     $_->slice for @{$self->objects};
     
+    if ($Slic3r::Config->resolution) {
+        $status_cb->(15, "Simplifying input");
+        $self->_simplify_slices(scale $Slic3r::Config->resolution);
+    }
+    
     # make perimeters
     # this will add a set of extrusion loops to each layer
     # as well as generate infill boundaries
@@ -334,10 +349,7 @@ sub export_gcode {
     
     # simplify slices (both layer and region slices),
     # we only need the max resolution for perimeters
-    foreach my $layer (map @{$_->layers}, @{$self->objects}) {
-        @$_ = map $_->simplify(&Slic3r::SCALED_RESOLUTION), @$_
-            for $layer->slices, (map $_->slices, @{$layer->regions});
-    }
+    $self->_simplify_slices(&Slic3r::SCALED_RESOLUTION);
     
     # this will assign a type (top/bottom/internal) to $layerm->slices
     # and transform $layerm->fill_surfaces from expolygon 
diff --git a/slic3r.pl b/slic3r.pl
index 4290ceb8e..c4cfd8487 100755
--- a/slic3r.pl
+++ b/slic3r.pl
@@ -342,6 +342,7 @@ $j
    
    Miscellaneous options:
     --notes             Notes to be added as comments to the output file
+    --resolution        Minimum detail resolution (mm, set zero for full resolution, default: $config->{resolution})
   
    Flow options (advanced):
     --extrusion-width   Set extrusion width manually; it accepts either an absolute value in mm