From c1c8997b4e5917f72c7f0e224712bd021f11d7af Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Mon, 2 Jul 2012 17:09:09 +0200
Subject: [PATCH 1/6] Bugfix: wrong spacing was calculated

---
 lib/Slic3r/Extruder.pm | 4 ++--
 lib/Slic3r/Flow.pm     | 2 +-
 lib/Slic3r/GCode.pm    | 4 ++--
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/lib/Slic3r/Extruder.pm b/lib/Slic3r/Extruder.pm
index 3f06cd641..8ab9c2790 100644
--- a/lib/Slic3r/Extruder.pm
+++ b/lib/Slic3r/Extruder.pm
@@ -9,11 +9,11 @@ has 'extrusion_multiplier'      => (is => 'rw', required => 1);
 has 'temperature'               => (is => 'rw', required => 1);
 has 'first_layer_temperature'   => (is => 'rw', required => 1);
 
-has 'e_per_mmc'             => (is => 'rw');
+has 'e_per_mm3'                 => (is => 'rw');
 
 sub BUILD {
     my $self = shift;
-    $self->e_per_mmc(
+    $self->e_per_mm3(
         $Slic3r::scaling_factor
         * $self->extrusion_multiplier
         * (4 / (($self->filament_diameter ** 2) * PI))
diff --git a/lib/Slic3r/Flow.pm b/lib/Slic3r/Flow.pm
index 23468254b..f73fa7b22 100644
--- a/lib/Slic3r/Flow.pm
+++ b/lib/Slic3r/Flow.pm
@@ -43,7 +43,7 @@ sub BUILD {
         $min_flow_spacing = $flow_width - $self->layer_height * (1 - PI/4);
     } else {
         # rectangle with shrunk semicircles at the ends
-        $min_flow_spacing = $flow_width * (1 - PI/4) + $self->nozzle_diameter * PI/4;
+        $min_flow_spacing = $self->nozzle_diameter * (1 - PI/4) + $flow_width * PI/4;
     }
     $flow_spacing = $flow_width - $Slic3r::overlap_factor * ($flow_width - $min_flow_spacing);
     
diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm
index f8a96e93c..06cb652d9 100644
--- a/lib/Slic3r/GCode.pm
+++ b/lib/Slic3r/GCode.pm
@@ -162,7 +162,7 @@ sub extrude_path {
     my $h = $path->depth_layers * $self->layer->height;
     my $w = ($s - ($self->layer ? $self->layer->flow->min_spacing : $Slic3r::flow->min_spacing) * $Slic3r::overlap_factor) / (1 - $Slic3r::overlap_factor);
     
-    my $area;
+    my $area; # = mm^3 of extrudate per mm of tool movement 
     if ($path->role == EXTR_ROLE_BRIDGE) {
         $area = ($s**2) * PI/4;
     } elsif ($w >= ($self->extruder->nozzle_diameter + $h)) {
@@ -173,7 +173,7 @@ sub extrude_path {
         $area = $self->extruder->nozzle_diameter * $h * (1 - PI/4) + $h * $w * PI/4;
     }
     
-    my $e = $self->extruder->e_per_mmc * $area;
+    my $e = $self->extruder->e_per_mm3 * $area;
     
     # extrude arc or line
     $self->speed( $role_speeds{$path->role} || die "Unknown role: " . $path->role );

From 7b09a56cf7d31fc61ba96c8c76e59fe2fe7f8c0d Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Tue, 3 Jul 2012 18:05:31 +0200
Subject: [PATCH 2/6] New spacing math. Speed optimizations

---
 lib/Slic3r/Config.pm   |  4 +--
 lib/Slic3r/Extruder.pm | 41 +++++++++++++++++-------
 lib/Slic3r/Flow.pm     | 73 ++++++++++++++++++++++--------------------
 lib/Slic3r/GCode.pm    | 21 +++++-------
 4 files changed, 78 insertions(+), 61 deletions(-)

diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm
index a1e862aa2..33500beff 100644
--- a/lib/Slic3r/Config.pm
+++ b/lib/Slic3r/Config.pm
@@ -725,8 +725,8 @@ sub validate {
     $Slic3r::support_material_flow = $Slic3r::extruders->[ $Slic3r::support_material_extruder-1 ]
         ->make_flow(width => $Slic3r::support_material_extrusion_width || $Slic3r::extrusion_width);
     
-    Slic3r::debugf "Default flow width = %s, spacing = %s, min_spacing = %s\n",
-        $Slic3r::flow->width, $Slic3r::flow->spacing, $Slic3r::flow->min_spacing;
+    Slic3r::debugf "Default flow width = %s (spacing = %s)\n",
+        $Slic3r::flow->width, $Slic3r::flow->spacing;
     
     # --perimeters
     die "Invalid value for --perimeters\n"
diff --git a/lib/Slic3r/Extruder.pm b/lib/Slic3r/Extruder.pm
index 8ab9c2790..07a0d0799 100644
--- a/lib/Slic3r/Extruder.pm
+++ b/lib/Slic3r/Extruder.pm
@@ -3,21 +3,18 @@ use Moo;
 
 use Slic3r::Geometry qw(PI);
 
-has 'nozzle_diameter'           => (is => 'rw', required => 1);
-has 'filament_diameter'         => (is => 'rw', required => 1);
-has 'extrusion_multiplier'      => (is => 'rw', required => 1);
-has 'temperature'               => (is => 'rw', required => 1);
+has 'nozzle_diameter'           => (is => 'ro', required => 1);
+has 'filament_diameter'         => (is => 'ro', required => 1);
+has 'extrusion_multiplier'      => (is => 'ro', required => 1);
+has 'temperature'               => (is => 'ro', required => 1);
 has 'first_layer_temperature'   => (is => 'rw', required => 1);
 
-has 'e_per_mm3'                 => (is => 'rw');
+has 'e_per_mm3'                 => (is => 'lazy');
+has '_mm3_per_mm_cache'         => (is => 'ro', default => sub {{}});
 
-sub BUILD {
+sub _build_e_per_mm3 {
     my $self = shift;
-    $self->e_per_mm3(
-        $Slic3r::scaling_factor
-        * $self->extrusion_multiplier
-        * (4 / (($self->filament_diameter ** 2) * PI))
-    );
+    return $self->extrusion_multiplier * (4 / (($self->filament_diameter ** 2) * PI));
 }
 
 sub make_flow {
@@ -25,4 +22,26 @@ sub make_flow {
     return Slic3r::Flow->new(nozzle_diameter => $self->nozzle_diameter, @_);
 }
 
+sub mm3_per_mm {
+    my $self = shift;
+    my ($s, $h) = @_;
+    
+    my $cache_key = "${s}_${h}";
+    if (!exists $self->_mm3_per_mm_cache->{$cache_key}) {
+        my $w_threshold = $h + $self->nozzle_diameter;
+        my $s_threshold = $w_threshold - $Slic3r::overlap_factor * ($w_threshold - ($w_threshold - $h * (1 - PI/4)));
+        
+        if ($s >= $s_threshold) {
+            # rectangle with semicircles at the ends
+            my $w = $s + $Slic3r::overlap_factor * $h * (1 - PI/4);
+            $self->_mm3_per_mm_cache->{$cache_key} = $w * $h + ($h**2) / 4 * (PI - 4);
+        } else {
+            # rectangle with shrunk semicircles at the ends
+            my $w = ($s + $self->nozzle_diameter * $Slic3r::overlap_factor * (PI/4 - 1)) / (1 + $Slic3r::overlap_factor * (PI/4 - 1));
+            $self->_mm3_per_mm_cache->{$cache_key} = $self->nozzle_diameter * $h * (1 - PI/4) + $h * $w * PI/4;
+        }
+    }
+    return $self->_mm3_per_mm_cache->{$cache_key};
+}
+
 1;
diff --git a/lib/Slic3r/Flow.pm b/lib/Slic3r/Flow.pm
index f73fa7b22..959d6e3d3 100644
--- a/lib/Slic3r/Flow.pm
+++ b/lib/Slic3r/Flow.pm
@@ -3,53 +3,56 @@ use Moo;
 
 use Slic3r::Geometry qw(PI);
 
-has 'nozzle_diameter'   => (is => 'rw', required => 1);
-has 'layer_height'      => (is => 'rw', default => sub { $Slic3r::layer_height });
+has 'nozzle_diameter'   => (is => 'ro', required => 1);
+has 'layer_height'      => (is => 'ro', default => sub { $Slic3r::layer_height });
 
-has 'width'             => (is => 'rw');
-has 'min_spacing'       => (is => 'rw');
-has 'spacing'           => (is => 'rw');
+has 'width'             => (is => 'rwp', builder => 1);
+has 'spacing'           => (is => 'lazy');
 
 sub BUILD {
     my $self = shift;
     
-    my ($flow_width, $min_flow_spacing, $flow_spacing);
-    if ($self->width) {
-        $flow_width = $self->width =~ /^(\d+(?:\.\d+)?)%$/
-            ? ($self->layer_height * $1 / 100)
-            : $self->width;
+    if ($self->width =~ /^(\d+(?:\.\d+)?)%$/) {
+        $self->_set_width($self->layer_height * $1 / 100);
+    }
+    $self->_set_width($self->_build_width) if $self->width == 0; # auto
+}
+
+sub _build_width {
+    my $self = shift;
+    
+    # here we calculate a sane default by matching the flow speed (at the nozzle) and the feed rate
+    my $volume = ($self->nozzle_diameter**2) * PI/4;
+    my $shape_threshold = $self->nozzle_diameter * $self->layer_height + ($self->layer_height**2) * PI/4;
+    my $width;
+    if ($volume >= $shape_threshold) {
+        # rectangle with semicircles at the ends
+        $width = (($self->nozzle_diameter**2) * PI + ($self->layer_height**2) * (4 - PI)) / (4 * $self->layer_height);
     } else {
-        # here we calculate a sane default by matching the flow speed (at the nozzle)
-        # and the feed rate
-        my $volume = ($self->nozzle_diameter**2) * PI/4;
-        my $shape_threshold = $self->nozzle_diameter * $self->layer_height
-            + ($self->layer_height**2) * PI/4;
-        if ($volume >= $shape_threshold) {
-            # rectangle with semicircles at the ends
-            $flow_width = (($self->nozzle_diameter**2) * PI + ($self->layer_height**2) * (4 - PI)) / (4 * $self->layer_height);
-        } else {
-            # rectangle with squished semicircles at the ends
-            $flow_width = $self->nozzle_diameter * ($self->nozzle_diameter/$self->layer_height - 4/PI + 1);
-        }
-        
-        my $min_flow_width = $self->nozzle_diameter * 1.05;
-        my $max_flow_width = $self->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;
+        # rectangle with squished semicircles at the ends
+        $width = $self->nozzle_diameter * ($self->nozzle_diameter/$self->layer_height - 4/PI + 1);
     }
     
-    if ($flow_width >= ($self->nozzle_diameter + $self->layer_height)) {
+    my $min = $self->nozzle_diameter * 1.05;
+    my $max = $self->nozzle_diameter * 1.4;
+    $width = $max if $width > $max;
+    $width = $min if $width < $min;
+    
+    return $width;
+}
+
+sub _build_spacing {
+    my $self = shift;
+    
+    my $min_flow_spacing;
+    if ($self->width >= ($self->nozzle_diameter + $self->layer_height)) {
         # rectangle with semicircles at the ends
-        $min_flow_spacing = $flow_width - $self->layer_height * (1 - PI/4);
+        $min_flow_spacing = $self->width - $self->layer_height * (1 - PI/4);
     } else {
         # rectangle with shrunk semicircles at the ends
-        $min_flow_spacing = $self->nozzle_diameter * (1 - PI/4) + $flow_width * PI/4;
+        $min_flow_spacing = $self->nozzle_diameter * (1 - PI/4) + $self->width * PI/4;
     }
-    $flow_spacing = $flow_width - $Slic3r::overlap_factor * ($flow_width - $min_flow_spacing);
-    
-    $self->width($flow_width);
-    $self->min_spacing($min_flow_spacing);
-    $self->spacing($flow_spacing);
+    return $self->width - $Slic3r::overlap_factor * ($self->width - $min_flow_spacing);
 }
 
 1;
diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm
index 06cb652d9..a9e75be98 100644
--- a/lib/Slic3r/GCode.pm
+++ b/lib/Slic3r/GCode.pm
@@ -157,22 +157,17 @@ sub extrude_path {
     # compensate retraction
     $gcode .= $self->unretract if $self->retracted;
     
-    # calculate extrusion length per distance unit
-    my $s = $path->flow_spacing || ($self->layer ? $self->layer->flow->spacing : $Slic3r::flow->spacing);
-    my $h = $path->depth_layers * $self->layer->height;
-    my $w = ($s - ($self->layer ? $self->layer->flow->min_spacing : $Slic3r::flow->min_spacing) * $Slic3r::overlap_factor) / (1 - $Slic3r::overlap_factor);
-    
-    my $area; # = mm^3 of extrudate per mm of tool movement 
+    my $area;  # mm^3 of extrudate per mm of tool movement 
     if ($path->role == EXTR_ROLE_BRIDGE) {
+        my $s = $path->flow_spacing || $self->extruder->nozzle_diameter;
         $area = ($s**2) * PI/4;
-    } elsif ($w >= ($self->extruder->nozzle_diameter + $h)) {
-        # rectangle with semicircles at the ends
-        $area = $w * $h + ($h**2) / 4 * (PI - 4);
     } else {
-        # rectangle with shrunk semicircles at the ends
-        $area = $self->extruder->nozzle_diameter * $h * (1 - PI/4) + $h * $w * PI/4;
+        my $s = $path->flow_spacing || ($self->layer ? $self->layer->flow->spacing : $Slic3r::flow->spacing);
+        my $h = $path->depth_layers * $self->layer->height;
+        $area = $self->extruder->mm3_per_mm($s, $h);
     }
     
+    # calculate extrusion length per distance unit
     my $e = $self->extruder->e_per_mm3 * $area;
     
     # extrude arc or line
@@ -181,12 +176,12 @@ sub extrude_path {
     if ($path->isa('Slic3r::ExtrusionPath::Arc')) {
         $path_length = $path->length;
         $gcode .= $self->G2_G3($path->points->[-1], $path->orientation, 
-            $path->center, $e * $path_length, $description);
+            $path->center, $e * unscale $path_length, $description);
     } else {
         foreach my $line ($path->lines) {
             my $line_length = $line->length;
             $path_length += $line_length;
-            $gcode .= $self->G1($line->b, undef, $e * $line_length, $description);
+            $gcode .= $self->G1($line->b, undef, $e * unscale $line_length, $description);
         }
     }
     

From dd378673249ad9c3ac314aabc0df50abd92ffb05 Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Mon, 2 Jul 2012 17:09:09 +0200
Subject: [PATCH 3/6] Bugfix: wrong spacing was calculated

---
 lib/Slic3r/Extruder.pm | 4 ++--
 lib/Slic3r/Flow.pm     | 2 +-
 lib/Slic3r/GCode.pm    | 4 ++--
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/lib/Slic3r/Extruder.pm b/lib/Slic3r/Extruder.pm
index 3f06cd641..8ab9c2790 100644
--- a/lib/Slic3r/Extruder.pm
+++ b/lib/Slic3r/Extruder.pm
@@ -9,11 +9,11 @@ has 'extrusion_multiplier'      => (is => 'rw', required => 1);
 has 'temperature'               => (is => 'rw', required => 1);
 has 'first_layer_temperature'   => (is => 'rw', required => 1);
 
-has 'e_per_mmc'             => (is => 'rw');
+has 'e_per_mm3'                 => (is => 'rw');
 
 sub BUILD {
     my $self = shift;
-    $self->e_per_mmc(
+    $self->e_per_mm3(
         $Slic3r::scaling_factor
         * $self->extrusion_multiplier
         * (4 / (($self->filament_diameter ** 2) * PI))
diff --git a/lib/Slic3r/Flow.pm b/lib/Slic3r/Flow.pm
index 23468254b..f73fa7b22 100644
--- a/lib/Slic3r/Flow.pm
+++ b/lib/Slic3r/Flow.pm
@@ -43,7 +43,7 @@ sub BUILD {
         $min_flow_spacing = $flow_width - $self->layer_height * (1 - PI/4);
     } else {
         # rectangle with shrunk semicircles at the ends
-        $min_flow_spacing = $flow_width * (1 - PI/4) + $self->nozzle_diameter * PI/4;
+        $min_flow_spacing = $self->nozzle_diameter * (1 - PI/4) + $flow_width * PI/4;
     }
     $flow_spacing = $flow_width - $Slic3r::overlap_factor * ($flow_width - $min_flow_spacing);
     
diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm
index f3afcd985..dcf6918b9 100644
--- a/lib/Slic3r/GCode.pm
+++ b/lib/Slic3r/GCode.pm
@@ -162,7 +162,7 @@ sub extrude_path {
     my $h = $path->depth_layers * $self->layer->height;
     my $w = ($s - ($self->layer ? $self->layer->flow->min_spacing : $Slic3r::flow->min_spacing) * $Slic3r::overlap_factor) / (1 - $Slic3r::overlap_factor);
     
-    my $area;
+    my $area; # = mm^3 of extrudate per mm of tool movement 
     if ($path->role == EXTR_ROLE_BRIDGE) {
         $area = ($s**2) * PI/4;
     } elsif ($w >= ($self->extruder->nozzle_diameter + $h)) {
@@ -173,7 +173,7 @@ sub extrude_path {
         $area = $self->extruder->nozzle_diameter * $h * (1 - PI/4) + $h * $w * PI/4;
     }
     
-    my $e = $self->extruder->e_per_mmc * $area;
+    my $e = $self->extruder->e_per_mm3 * $area;
     
     # extrude arc or line
     $self->speed( $role_speeds{$path->role} || die "Unknown role: " . $path->role );

From 77123ada7c0f74bbcbb1e480be0f7fa2faff0a9c Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Tue, 3 Jul 2012 18:05:31 +0200
Subject: [PATCH 4/6] New spacing math. Speed optimizations

---
 lib/Slic3r/Config.pm   |  4 +--
 lib/Slic3r/Extruder.pm | 41 +++++++++++++++++-------
 lib/Slic3r/Flow.pm     | 73 ++++++++++++++++++++++--------------------
 lib/Slic3r/GCode.pm    | 21 +++++-------
 4 files changed, 78 insertions(+), 61 deletions(-)

diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm
index a1e862aa2..33500beff 100644
--- a/lib/Slic3r/Config.pm
+++ b/lib/Slic3r/Config.pm
@@ -725,8 +725,8 @@ sub validate {
     $Slic3r::support_material_flow = $Slic3r::extruders->[ $Slic3r::support_material_extruder-1 ]
         ->make_flow(width => $Slic3r::support_material_extrusion_width || $Slic3r::extrusion_width);
     
-    Slic3r::debugf "Default flow width = %s, spacing = %s, min_spacing = %s\n",
-        $Slic3r::flow->width, $Slic3r::flow->spacing, $Slic3r::flow->min_spacing;
+    Slic3r::debugf "Default flow width = %s (spacing = %s)\n",
+        $Slic3r::flow->width, $Slic3r::flow->spacing;
     
     # --perimeters
     die "Invalid value for --perimeters\n"
diff --git a/lib/Slic3r/Extruder.pm b/lib/Slic3r/Extruder.pm
index 8ab9c2790..07a0d0799 100644
--- a/lib/Slic3r/Extruder.pm
+++ b/lib/Slic3r/Extruder.pm
@@ -3,21 +3,18 @@ use Moo;
 
 use Slic3r::Geometry qw(PI);
 
-has 'nozzle_diameter'           => (is => 'rw', required => 1);
-has 'filament_diameter'         => (is => 'rw', required => 1);
-has 'extrusion_multiplier'      => (is => 'rw', required => 1);
-has 'temperature'               => (is => 'rw', required => 1);
+has 'nozzle_diameter'           => (is => 'ro', required => 1);
+has 'filament_diameter'         => (is => 'ro', required => 1);
+has 'extrusion_multiplier'      => (is => 'ro', required => 1);
+has 'temperature'               => (is => 'ro', required => 1);
 has 'first_layer_temperature'   => (is => 'rw', required => 1);
 
-has 'e_per_mm3'                 => (is => 'rw');
+has 'e_per_mm3'                 => (is => 'lazy');
+has '_mm3_per_mm_cache'         => (is => 'ro', default => sub {{}});
 
-sub BUILD {
+sub _build_e_per_mm3 {
     my $self = shift;
-    $self->e_per_mm3(
-        $Slic3r::scaling_factor
-        * $self->extrusion_multiplier
-        * (4 / (($self->filament_diameter ** 2) * PI))
-    );
+    return $self->extrusion_multiplier * (4 / (($self->filament_diameter ** 2) * PI));
 }
 
 sub make_flow {
@@ -25,4 +22,26 @@ sub make_flow {
     return Slic3r::Flow->new(nozzle_diameter => $self->nozzle_diameter, @_);
 }
 
+sub mm3_per_mm {
+    my $self = shift;
+    my ($s, $h) = @_;
+    
+    my $cache_key = "${s}_${h}";
+    if (!exists $self->_mm3_per_mm_cache->{$cache_key}) {
+        my $w_threshold = $h + $self->nozzle_diameter;
+        my $s_threshold = $w_threshold - $Slic3r::overlap_factor * ($w_threshold - ($w_threshold - $h * (1 - PI/4)));
+        
+        if ($s >= $s_threshold) {
+            # rectangle with semicircles at the ends
+            my $w = $s + $Slic3r::overlap_factor * $h * (1 - PI/4);
+            $self->_mm3_per_mm_cache->{$cache_key} = $w * $h + ($h**2) / 4 * (PI - 4);
+        } else {
+            # rectangle with shrunk semicircles at the ends
+            my $w = ($s + $self->nozzle_diameter * $Slic3r::overlap_factor * (PI/4 - 1)) / (1 + $Slic3r::overlap_factor * (PI/4 - 1));
+            $self->_mm3_per_mm_cache->{$cache_key} = $self->nozzle_diameter * $h * (1 - PI/4) + $h * $w * PI/4;
+        }
+    }
+    return $self->_mm3_per_mm_cache->{$cache_key};
+}
+
 1;
diff --git a/lib/Slic3r/Flow.pm b/lib/Slic3r/Flow.pm
index f73fa7b22..959d6e3d3 100644
--- a/lib/Slic3r/Flow.pm
+++ b/lib/Slic3r/Flow.pm
@@ -3,53 +3,56 @@ use Moo;
 
 use Slic3r::Geometry qw(PI);
 
-has 'nozzle_diameter'   => (is => 'rw', required => 1);
-has 'layer_height'      => (is => 'rw', default => sub { $Slic3r::layer_height });
+has 'nozzle_diameter'   => (is => 'ro', required => 1);
+has 'layer_height'      => (is => 'ro', default => sub { $Slic3r::layer_height });
 
-has 'width'             => (is => 'rw');
-has 'min_spacing'       => (is => 'rw');
-has 'spacing'           => (is => 'rw');
+has 'width'             => (is => 'rwp', builder => 1);
+has 'spacing'           => (is => 'lazy');
 
 sub BUILD {
     my $self = shift;
     
-    my ($flow_width, $min_flow_spacing, $flow_spacing);
-    if ($self->width) {
-        $flow_width = $self->width =~ /^(\d+(?:\.\d+)?)%$/
-            ? ($self->layer_height * $1 / 100)
-            : $self->width;
+    if ($self->width =~ /^(\d+(?:\.\d+)?)%$/) {
+        $self->_set_width($self->layer_height * $1 / 100);
+    }
+    $self->_set_width($self->_build_width) if $self->width == 0; # auto
+}
+
+sub _build_width {
+    my $self = shift;
+    
+    # here we calculate a sane default by matching the flow speed (at the nozzle) and the feed rate
+    my $volume = ($self->nozzle_diameter**2) * PI/4;
+    my $shape_threshold = $self->nozzle_diameter * $self->layer_height + ($self->layer_height**2) * PI/4;
+    my $width;
+    if ($volume >= $shape_threshold) {
+        # rectangle with semicircles at the ends
+        $width = (($self->nozzle_diameter**2) * PI + ($self->layer_height**2) * (4 - PI)) / (4 * $self->layer_height);
     } else {
-        # here we calculate a sane default by matching the flow speed (at the nozzle)
-        # and the feed rate
-        my $volume = ($self->nozzle_diameter**2) * PI/4;
-        my $shape_threshold = $self->nozzle_diameter * $self->layer_height
-            + ($self->layer_height**2) * PI/4;
-        if ($volume >= $shape_threshold) {
-            # rectangle with semicircles at the ends
-            $flow_width = (($self->nozzle_diameter**2) * PI + ($self->layer_height**2) * (4 - PI)) / (4 * $self->layer_height);
-        } else {
-            # rectangle with squished semicircles at the ends
-            $flow_width = $self->nozzle_diameter * ($self->nozzle_diameter/$self->layer_height - 4/PI + 1);
-        }
-        
-        my $min_flow_width = $self->nozzle_diameter * 1.05;
-        my $max_flow_width = $self->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;
+        # rectangle with squished semicircles at the ends
+        $width = $self->nozzle_diameter * ($self->nozzle_diameter/$self->layer_height - 4/PI + 1);
     }
     
-    if ($flow_width >= ($self->nozzle_diameter + $self->layer_height)) {
+    my $min = $self->nozzle_diameter * 1.05;
+    my $max = $self->nozzle_diameter * 1.4;
+    $width = $max if $width > $max;
+    $width = $min if $width < $min;
+    
+    return $width;
+}
+
+sub _build_spacing {
+    my $self = shift;
+    
+    my $min_flow_spacing;
+    if ($self->width >= ($self->nozzle_diameter + $self->layer_height)) {
         # rectangle with semicircles at the ends
-        $min_flow_spacing = $flow_width - $self->layer_height * (1 - PI/4);
+        $min_flow_spacing = $self->width - $self->layer_height * (1 - PI/4);
     } else {
         # rectangle with shrunk semicircles at the ends
-        $min_flow_spacing = $self->nozzle_diameter * (1 - PI/4) + $flow_width * PI/4;
+        $min_flow_spacing = $self->nozzle_diameter * (1 - PI/4) + $self->width * PI/4;
     }
-    $flow_spacing = $flow_width - $Slic3r::overlap_factor * ($flow_width - $min_flow_spacing);
-    
-    $self->width($flow_width);
-    $self->min_spacing($min_flow_spacing);
-    $self->spacing($flow_spacing);
+    return $self->width - $Slic3r::overlap_factor * ($self->width - $min_flow_spacing);
 }
 
 1;
diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm
index dcf6918b9..a7e0834d4 100644
--- a/lib/Slic3r/GCode.pm
+++ b/lib/Slic3r/GCode.pm
@@ -157,22 +157,17 @@ sub extrude_path {
     # compensate retraction
     $gcode .= $self->unretract if $self->retracted;
     
-    # calculate extrusion length per distance unit
-    my $s = $path->flow_spacing || ($self->layer ? $self->layer->flow->spacing : $Slic3r::flow->spacing);
-    my $h = $path->depth_layers * $self->layer->height;
-    my $w = ($s - ($self->layer ? $self->layer->flow->min_spacing : $Slic3r::flow->min_spacing) * $Slic3r::overlap_factor) / (1 - $Slic3r::overlap_factor);
-    
-    my $area; # = mm^3 of extrudate per mm of tool movement 
+    my $area;  # mm^3 of extrudate per mm of tool movement 
     if ($path->role == EXTR_ROLE_BRIDGE) {
+        my $s = $path->flow_spacing || $self->extruder->nozzle_diameter;
         $area = ($s**2) * PI/4;
-    } elsif ($w >= ($self->extruder->nozzle_diameter + $h)) {
-        # rectangle with semicircles at the ends
-        $area = $w * $h + ($h**2) / 4 * (PI - 4);
     } else {
-        # rectangle with shrunk semicircles at the ends
-        $area = $self->extruder->nozzle_diameter * $h * (1 - PI/4) + $h * $w * PI/4;
+        my $s = $path->flow_spacing || ($self->layer ? $self->layer->flow->spacing : $Slic3r::flow->spacing);
+        my $h = $path->depth_layers * $self->layer->height;
+        $area = $self->extruder->mm3_per_mm($s, $h);
     }
     
+    # calculate extrusion length per distance unit
     my $e = $self->extruder->e_per_mm3 * $area;
     
     # extrude arc or line
@@ -181,12 +176,12 @@ sub extrude_path {
     if ($path->isa('Slic3r::ExtrusionPath::Arc')) {
         $path_length = $path->length;
         $gcode .= $self->G2_G3($path->points->[-1], $path->orientation, 
-            $path->center, $e * $path_length, $description);
+            $path->center, $e * unscale $path_length, $description);
     } else {
         foreach my $line ($path->lines) {
             my $line_length = $line->length;
             $path_length += $line_length;
-            $gcode .= $self->G1($line->b, undef, $e * $line_length, $description);
+            $gcode .= $self->G1($line->b, undef, $e * unscale $line_length, $description);
         }
     }
     

From e4294cffcefd1c4374d642947c3d972b8932bbb8 Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Wed, 4 Jul 2012 10:35:03 +0200
Subject: [PATCH 5/6] Fixed regression causing random extrudates outside the
 object perimeter

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

diff --git a/lib/Slic3r/Layer.pm b/lib/Slic3r/Layer.pm
index 686df1a98..e0a7b2962 100644
--- a/lib/Slic3r/Layer.pm
+++ b/lib/Slic3r/Layer.pm
@@ -136,10 +136,10 @@ sub make_surfaces {
     my $self = shift;
     my ($loops) = @_;
     
-    my $safety_offset = scale 0.1;
     {
+        my $safety_offset = scale 0.1;
         # merge everything
-        my $expolygons = union_ex(safety_offset($loops, $safety_offset));
+        my $expolygons = [ map $_->offset_ex(-$safety_offset), @{union_ex(safety_offset($loops, $safety_offset))} ];
         
         Slic3r::debugf "  %d surface(s) having %d holes detected from %d polylines\n",
             scalar(@$expolygons), scalar(map $_->holes, @$expolygons), scalar(@$loops);
@@ -158,7 +158,7 @@ sub make_surfaces {
             push @{$self->slices}, map Slic3r::Surface->new
                 (expolygon => $_, surface_type => S_TYPE_INTERNAL),
                 map $_->offset_ex(+$distance),
-                $surface->expolygon->offset_ex(-2*$distance - $safety_offset);
+                $surface->expolygon->offset_ex(-2*$distance);
         }
         
         # now detect thin walls by re-outgrowing offsetted surfaces and subtracting

From 7656167a0a92446f2d83cbf3c7273f83a40e83c8 Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Thu, 5 Jul 2012 10:32:29 +0200
Subject: [PATCH 6/6] Infill flow wasn't adjusted for non-solid surfaces

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

diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm
index 80edf518f..b624e8aa1 100644
--- a/lib/Slic3r/Fill.pm
+++ b/lib/Slic3r/Fill.pm
@@ -170,7 +170,7 @@ sub make_fill {
                             ? ($surface->surface_type == S_TYPE_TOP ? EXTR_ROLE_TOPSOLIDFILL : EXTR_ROLE_SOLIDFILL)
                             : EXTR_ROLE_FILL),
                     depth_layers => $surface->depth_layers,
-                    flow_spacing => $params->{flow_spacing},
+                    flow_spacing => $params->{flow_spacing} || $flow_spacing,
                 ), @paths,
             ],
         );