From 08270022dd9bebfb199448db3acc631e9049d133 Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Sat, 25 Aug 2012 20:40:44 +0200
Subject: [PATCH] Refactoring: initialize all layers at once and avoid
 duplication of slicing height math

---
 lib/Slic3r/Print.pm        |  2 +-
 lib/Slic3r/Print/Object.pm | 41 ++++++++++++++++++++------------------
 lib/Slic3r/TriangleMesh.pm |  6 ++----
 3 files changed, 25 insertions(+), 24 deletions(-)

diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm
index f015416de..e701bd1c4 100644
--- a/lib/Slic3r/Print.pm
+++ b/lib/Slic3r/Print.pm
@@ -477,7 +477,7 @@ sub make_skirt {
     $skirt_height = $self->layer_count if $skirt_height > $self->layer_count;
     my @points = ();
     foreach my $obj_idx (0 .. $#{$self->objects}) {
-        my @layers = map $self->objects->[$obj_idx]->layer($_), 0..($skirt_height-1);
+        my @layers = map $self->objects->[$obj_idx]->layers->[$_], 0..($skirt_height-1);
         my @layer_points = (
             (map @$_, map @{$_->expolygon}, map @{$_->slices}, @layers),
             (map @$_, map @{$_->thin_walls}, @layers),
diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm
index 696d72ca3..d8f2c531b 100644
--- a/lib/Slic3r/Print/Object.pm
+++ b/lib/Slic3r/Print/Object.pm
@@ -2,39 +2,42 @@ package Slic3r::Print::Object;
 use Moo;
 
 use Slic3r::ExtrusionPath ':roles';
-use Slic3r::Geometry qw(scale unscale deg2rad);
+use Slic3r::Geometry qw(Z scale unscale deg2rad);
 use Slic3r::Geometry::Clipper qw(diff_ex intersection_ex union_ex);
 use Slic3r::Surface ':types';
 
 has 'input_file'        => (is => 'rw', required => 0);
 has 'mesh'              => (is => 'rw', required => 0);
 has 'size'              => (is => 'rw', required => 1);
+has 'layers'            => (is => 'rw', default => sub { [] } );
 
-has 'layers' => (
-    traits  => ['Array'],
-    is      => 'rw',
-    #isa     => 'ArrayRef[Slic3r::Layer]',
-    default => sub { [] },
-);
+sub BUILD {
+    my $self = shift;
+    
+    # make layers
+    while (!@{$self->layers} || $self->layers->[-1]->slice_z < $self->size->[Z]) {
+        push @{$self->layers}, Slic3r::Layer->new(id => $#{$self->layers} + 1);
+    }
+}
 
 sub layer_count {
     my $self = shift;
     return scalar @{ $self->layers };
 }
 
-sub layer {
+sub get_layer_range {
     my $self = shift;
-    my ($layer_id) = @_;
+    my ($min_z, $max_z) = @_;
     
-    # extend our print by creating all necessary layers
-    
-    if ($self->layer_count < $layer_id + 1) {
-        for (my $i = $self->layer_count; $i <= $layer_id; $i++) {
-            push @{ $self->layers }, Slic3r::Layer->new(id => $i);
+    my ($min_layer, $max_layer) = (0, undef);
+    for my $layer (@{$self->layers}) {
+        $min_layer = $layer->id if $layer->slice_z <= $min_z;
+        if ($layer->slice_z >= $max_z) {
+            $max_layer = $layer->id;
+            last;
         }
     }
-    
-    return $self->layers->[$layer_id];
+    return ($min_layer, $max_layer);
 }
 
 sub slice {
@@ -46,7 +49,7 @@ sub slice {
         my $apply_lines = sub {
             my $lines = shift;
             foreach my $layer_id (keys %$lines) {
-                my $layer = $self->layer($layer_id);
+                my $layer = $self->layers->[$layer_id];
                 push @{$layer->lines}, @{$lines->{$layer_id}};
             }
         };
@@ -399,7 +402,7 @@ sub combine_infill {
     
     # start from bottom, skip first layer
     for (my $i = 1; $i < $self->layer_count; $i++) {
-        my $layer = $self->layer($i);
+        my $layer = $self->layers->[$i];
         
         # skip layer if no internal fill surfaces
         next if !grep $_->surface_type == S_TYPE_INTERNAL, @{$layer->fill_surfaces};
@@ -408,7 +411,7 @@ sub combine_infill {
         # we do this from the greater depth to the smaller
         for (my $d = $Slic3r::Config->infill_every_layers - 1; $d >= 1; $d--) {
             next if ($i - $d) < 0;
-            my $lower_layer = $self->layer($i - 1);
+            my $lower_layer = $self->layers->[$i - 1];
             
             # select surfaces of the lower layer having the depth we're looking for
             my @lower_surfaces = grep $_->depth_layers == $d && $_->surface_type == S_TYPE_INTERNAL,
diff --git a/lib/Slic3r/TriangleMesh.pm b/lib/Slic3r/TriangleMesh.pm
index 6f6589450..b48f91981 100644
--- a/lib/Slic3r/TriangleMesh.pm
+++ b/lib/Slic3r/TriangleMesh.pm
@@ -401,14 +401,12 @@ sub slice_facet {
     }
     
     # calculate the layer extents
-    my $min_layer = int((unscale($min_z) - ($Slic3r::Config->get_value('first_layer_height') + $Slic3r::Config->layer_height / 2)) / $Slic3r::Config->layer_height) - 2;
-    $min_layer = 0 if $min_layer < 0;
-    my $max_layer = int((unscale($max_z) - ($Slic3r::Config->get_value('first_layer_height') + $Slic3r::Config->layer_height / 2)) / $Slic3r::Config->layer_height) + 2;
+    my ($min_layer, $max_layer) = $print_object->get_layer_range($min_z, $max_z);
     Slic3r::debugf "layers: min = %s, max = %s\n", $min_layer, $max_layer;
     
     my $lines = {};  # layer_id => [ lines ]
     for (my $layer_id = $min_layer; $layer_id <= $max_layer; $layer_id++) {
-        my $layer = $print_object->layer($layer_id);
+        my $layer = $print_object->layers->[$layer_id];
         $lines->{$layer_id} ||= [];
         push @{ $lines->{$layer_id} }, $self->intersect_facet($facet_id, $layer->slice_z);
     }