From d488afd243c07f9fa0a2d556451585202c43193a Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Sat, 22 Sep 2012 19:38:25 +0200
Subject: [PATCH] More work (breaks centering and internal surfaces detection)

---
 lib/Slic3r/Layer.pm          | 10 +++++-----
 lib/Slic3r/Layer/Material.pm | 15 ++++++++-------
 lib/Slic3r/Print.pm          | 15 ++++++++-------
 lib/Slic3r/Print/Object.pm   |  3 +++
 4 files changed, 24 insertions(+), 19 deletions(-)

diff --git a/lib/Slic3r/Layer.pm b/lib/Slic3r/Layer.pm
index 43d014490..e99b44ba9 100644
--- a/lib/Slic3r/Layer.pm
+++ b/lib/Slic3r/Layer.pm
@@ -14,7 +14,7 @@ has 'flow'              => (is => 'lazy');
 has 'perimeter_flow'    => (is => 'lazy');
 has 'infill_flow'       => (is => 'lazy');
 
-# collection of surfaces generated by slicing the original geometry;
+# collection of expolygons generated by slicing the original geometry;
 # also known as 'islands' (all materials are merged here)
 has 'slices'            => (is => 'rw');
 
@@ -68,8 +68,8 @@ sub material {
     my $self = shift;
     my ($material_idx) = @_;
     
-    for my $i (grep !defined $self->materials->[$_], 0..$material_idx) {
-        $self->materials->[$i] = Slic3r::Layer::Material->new(
+    if (!defined $self->materials->[$material_idx]) {
+        $self->materials->[$material_idx] = Slic3r::Layer::Material->new(
             layer => $self,
         );
     }
@@ -83,11 +83,11 @@ sub make_slices {
     # optimization for single-material layers
     my @materials_with_slices = grep { @{$_->slices} } @{$self->materials};
     if (@materials_with_slices == 1) {
-        $self->slices($materials_with_slices[0]->slices);
+        $self->slices([ map $_->expolygon, @{$materials_with_slices[0]->slices} ]);
         return;
     }
     
-    $self->slices(union_ex([ map @{$_->slices}, @{$self->materials} ]));
+    $self->slices(union_ex([ map $_->p, map @{$_->slices}, @{$self->materials} ]));
 }
 
 sub make_perimeters {
diff --git a/lib/Slic3r/Layer/Material.pm b/lib/Slic3r/Layer/Material.pm
index 746d8c320..924a1fc8c 100644
--- a/lib/Slic3r/Layer/Material.pm
+++ b/lib/Slic3r/Layer/Material.pm
@@ -19,36 +19,37 @@ has 'layer' => (
 has 'lines' => (is => 'rw', default => sub { [] });
 
 # collection of surfaces generated by slicing the original geometry
-has 'slices' => (is => 'rw');
+has 'slices' => (is => 'rw', default => sub { [] });
 
 # collection of polygons or polylines representing thin walls contained 
 # in the original geometry
-has 'thin_walls' => (is => 'rw');
+has 'thin_walls' => (is => 'rw', default => sub { [] });
 
 # collection of polygons or polylines representing thin infill regions that
 # need to be filled with a medial axis
-has 'thin_fills' => (is => 'rw');
+has 'thin_fills' => (is => 'rw', default => sub { [] });
 
 # collection of expolygons generated by offsetting the innermost perimeter(s)
 # they represent boundaries of areas to fill, typed (top/bottom/internal)
-has 'surfaces' => (is => 'rw');
+has 'surfaces' => (is => 'rw', default => sub { [] });
 
 # collection of surfaces for infill generation. the difference between surfaces
 # fill_surfaces is that this one honors fill_density == 0 and turns small internal
 # surfaces into solid ones
-has 'fill_surfaces' => (is => 'rw');
+has 'fill_surfaces' => (is => 'rw', default => sub { [] });
 
 # ordered collection of extrusion paths/loops to build all perimeters
-has 'perimeters' => (is => 'rw');
+has 'perimeters' => (is => 'rw', default => sub { [] });
 
 # ordered collection of extrusion paths to fill surfaces
-has 'fills' => (is => 'rw');
+has 'fills' => (is => 'rw', default => sub { [] });
 
 # build polylines from lines
 sub make_surfaces {
     my $self = shift;
     my ($loops) = @_;
     
+    return if !@$loops;    
     {
         my $safety_offset = scale 0.1;
         # merge everything
diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm
index c131dbc4a..eae844b5a 100644
--- a/lib/Slic3r/Print.pm
+++ b/lib/Slic3r/Print.pm
@@ -97,9 +97,10 @@ sub add_model {
         foreach my $volume (@{$object->volumes}) {
             # should the object contain multiple volumes of the same material, merge them
             my $material_id = $volume->material_id // 0; #/
+            my $mesh = $volume->mesh->clone;
             $meshes[$material_id] = $meshes[$material_id]
-                ? Slic3r::TriangleMesh->merge($meshes[$material_id], $volume->mesh)
-                : $volume->mesh;
+                ? Slic3r::TriangleMesh->merge($meshes[$material_id], $mesh)
+                : $mesh;
         }
         
         foreach my $mesh (@meshes) {
@@ -281,10 +282,10 @@ sub export_gcode {
     
     # simplify slices (both layer and material slices),
     # we only need the max resolution for perimeters
-    $_->simplify(scale &Slic3r::RESOLUTION)
-        for map @{$_->expolygon}, 
-            map { my $layer = $_; ((map @{$_->slices}, @{$layer->materials}), @{$layer->slices}) }
-            map @{$_->layers}, @{$self->objects};
+    foreach my $layer (map @{$_->layers}, @{$self->objects}) {
+        $_->simplify(scale &Slic3r::RESOLUTION)
+            for @{$layer->slices}, (map $_->expolygon, map @{$_->slices}, @{$layer->materials});
+    }
     
     # this will clip $layer->surfaces to the infill boundaries 
     # and split them in top/bottom/internal surfaces;
@@ -494,7 +495,7 @@ sub make_skirt {
     foreach my $obj_idx (0 .. $#{$self->objects}) {
         my @layers = map $self->objects->[$obj_idx]->layer($_), 0..($skirt_height-1);
         my @layer_points = (
-            (map @$_, map @{$_->expolygon}, map @{$_->slices}, @layers),
+            (map @$_, map @$_, map @{$_->slices}, @layers),
             (map @$_, map @{$_->thin_walls}, map @{$_->materials}, @layers),
             (map @{$_->unpack->polyline}, map @{$_->support_fills->paths}, grep $_->support_fills, @layers),
         );
diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm
index c1319fd45..9cedc3a7d 100644
--- a/lib/Slic3r/Print/Object.pm
+++ b/lib/Slic3r/Print/Object.pm
@@ -84,6 +84,9 @@ sub slice {
     pop @{$self->layers} if !map @{$_->lines}, @{$self->layers->[-1]->materials};
     
     foreach my $layer (@{ $self->layers }) {
+        # make sure all layers contain layer material objects for all materials
+        $layer->material($_) for 0 .. ($self->print->materials_count-1);
+        
         Slic3r::debugf "Making surfaces for layer %d (slice z = %f):\n",
             $layer->id, unscale $layer->slice_z if $Slic3r::debug;