From 685e8e4dfa75e3abf610207df1bb7a5c8400c635 Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Thu, 19 Dec 2013 15:23:10 +0100
Subject: [PATCH] More work for step-based slicing

---
 lib/Slic3r/Print.pm        | 119 +++++++++++++++++--------------------
 lib/Slic3r/Print/Object.pm |  19 ++++++
 2 files changed, 74 insertions(+), 64 deletions(-)

diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm
index 247d2505f..b409b7326 100644
--- a/lib/Slic3r/Print.pm
+++ b/lib/Slic3r/Print.pm
@@ -398,108 +398,99 @@ sub process {
     # skein the STL into layers
     # each layer has surfaces with holes
     $status_cb->(10, "Processing triangulated mesh");
-    $print_step->(STEP_INIT_EXTRUDERS, sub {
-        my $object = $self->objects->[$_[0]];
-        $object->slice;
-        
-        if ($self->config->resolution) {
-            
-        }
+    $object_step->(STEP_SLICE, sub {
+        $self->objects->[$_[0]]->slice;
     });
     
     die "No layers were detected. You might want to repair your STL file(s) or check their size and retry.\n"
         if !grep @{$_->layers}, @{$self->objects};
     
-    if ($self->config->resolution) {
-        $status_cb->(15, "Simplifying input");
-        $self->_simplify_slices(scale $Slic3r::Config->resolution);
-        $print_step->(STEP_INIT_EXTRUDERS, sub {
-            $self->objects->[$_[0]]->slice;
-        });
-    }
-    
     # make perimeters
     # this will add a set of extrusion loops to each layer
     # as well as generate infill boundaries
     $status_cb->(20, "Generating perimeters");
-    $_->make_perimeters for @{$self->objects};
+    $object_step->(STEP_PERIMETERS, sub {
+        $self->objects->[$_[0]]->make_perimeters;
+    });
     
-    # simplify slices (both layer and region slices),
-    # we only need the max resolution for perimeters
-    $self->_simplify_slices(&Slic3r::SCALED_RESOLUTION);
+    $status_cb->(30, "Preparing infill");
+    $object_step->(STEP_PREPARE_INFILL, sub {
+        my $object = $self->objects->[$_[0]];
+        
+        # this will assign a type (top/bottom/internal) to $layerm->slices
+        # and transform $layerm->fill_surfaces from expolygon 
+        # to typed top/bottom/internal surfaces;
+        $object->detect_surfaces_type;
     
-    # this will assign a type (top/bottom/internal) to $layerm->slices
-    # and transform $layerm->fill_surfaces from expolygon 
-    # to typed top/bottom/internal surfaces;
-    $status_cb->(30, "Detecting solid surfaces");
-    $_->detect_surfaces_type for @{$self->objects};
+        # decide what surfaces are to be filled
+        $_->prepare_fill_surfaces for map @{$_->regions}, @{$object->layers};
     
-    # decide what surfaces are to be filled
-    $status_cb->(35, "Preparing infill surfaces");
-    $_->prepare_fill_surfaces for map @{$_->regions}, map @{$_->layers}, @{$self->objects};
+        # this will detect bridges and reverse bridges
+        # and rearrange top/bottom/internal surfaces
+        $object->process_external_surfaces;
     
-    # this will detect bridges and reverse bridges
-    # and rearrange top/bottom/internal surfaces
-    $status_cb->(45, "Detect bridges");
-    $_->process_external_surfaces for @{$self->objects};
+        # detect which fill surfaces are near external layers
+        # they will be split in internal and internal-solid surfaces
+        $object->discover_horizontal_shells;
+        $object->clip_fill_surfaces;
+        
+        # the following step needs to be done before combination because it may need
+        # to remove only half of the combined infill
+        $object->bridge_over_infill;
     
-    # detect which fill surfaces are near external layers
-    # they will be split in internal and internal-solid surfaces
-    $status_cb->(60, "Generating horizontal shells");
-    $_->discover_horizontal_shells for @{$self->objects};
-    $_->clip_fill_surfaces for @{$self->objects};
-    # the following step needs to be done before combination because it may need
-    # to remove only half of the combined infill
-    $_->bridge_over_infill for @{$self->objects};
-    
-    # combine fill surfaces to honor the "infill every N layers" option
-    $status_cb->(70, "Combining infill");
-    $_->combine_infill for @{$self->objects};
+        # combine fill surfaces to honor the "infill every N layers" option
+        $object->combine_infill;
+    });
     
     # this will generate extrusion paths for each layer
-    $status_cb->(80, "Infilling layers");
-    {
+    $status_cb->(70, "Infilling layers");
+    $object_step->(STEP_INFILL, sub {
+        my $object = $self->objects->[$_[0]];
+        
         Slic3r::parallelize(
             items => sub {
-                my @items = ();  # [obj_idx, layer_id]
-                for my $obj_idx (0 .. $#{$self->objects}) {
-                    for my $region_id (0 .. ($self->regions_count-1)) {
-                        push @items, map [$obj_idx, $_, $region_id], 0..($self->objects->[$obj_idx]->layer_count-1);
-                    }
+                my @items = ();  # [layer_id, region_id]
+                for my $region_id (0 .. ($self->regions_count-1)) {
+                    push @items, map [$_, $region_id], 0..($object->layer_count-1);
                 }
                 @items;
             },
             thread_cb => sub {
                 my $q = shift;
                 while (defined (my $obj_layer = $q->dequeue)) {
-                    my ($obj_idx, $layer_id, $region_id) = @$obj_layer;
-                    my $object = $self->objects->[$obj_idx];
+                    my ($layer_id, $region_id) = @$obj_layer;
                     my $layerm = $object->layers->[$layer_id]->regions->[$region_id];
                     $layerm->fills->append( $object->fill_maker->make_fill($layerm) );
                 }
             },
             collect_cb => sub {},
             no_threads_cb => sub {
-                foreach my $layerm (map @{$_->regions}, map @{$_->layers}, @{$self->objects}) {
-                    $layerm->fills->append($layerm->layer->object->fill_maker->make_fill($layerm));
+                foreach my $layerm (map @{$_->regions}, @{$object->layers}) {
+                    $layerm->fills->append($object->fill_maker->make_fill($layerm));
                 }
             },
         );
-    }
+    
+        ### we could free memory now, but this would make this step not idempotent
+        $_->fill_surfaces->clear for map @{$_->regions}, @{$object->layers};
+    });
     
     # generate support material
-    if ($self->has_support_material) {
-        $status_cb->(85, "Generating support material");
-        $_->generate_support_material for @{$self->objects};
-    }
-    
-    # free memory (note that support material needs fill_surfaces)
-    $_->fill_surfaces->clear for map @{$_->regions}, map @{$_->layers}, @{$self->objects};
+    $status_cb->(85, "Generating support material") if $self->has_support_material;
+    $object_step->(STEP_SUPPORTMATERIAL, sub {
+        $self->objects->[$_[0]]->generate_support_material;
+    });
     
     # make skirt
     $status_cb->(88, "Generating skirt");
-    $self->make_skirt;
-    $self->make_brim;  # must come after make_skirt
+    $print_step->(STEP_SKIRT, sub {
+        $self->make_skirt;
+    });
+    
+    $status_cb->(88, "Generating skirt");
+    $print_step->(STEP_BRIM, sub {
+        $self->make_brim;  # must come after make_skirt
+    });
     
     # time to make some statistics
     if (0) {
diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm
index 44b74c6be..35842e351 100644
--- a/lib/Slic3r/Print/Object.pm
+++ b/lib/Slic3r/Print/Object.pm
@@ -273,6 +273,11 @@ sub slice {
             $self->layers->[$i]->id($i);
         }
     }
+    
+    # simplify slices if required
+    if ($self->config->resolution) {
+        $self->_simplify_slices(scale($self->config->resolution));
+    }
 }
 
 sub make_perimeters {
@@ -348,6 +353,11 @@ sub make_perimeters {
             $_->make_perimeters for @{$self->layers};
         },
     );
+    
+    # simplify slices (both layer and region slices),
+    # we only need the max resolution for perimeters
+    ### This makes this method not-idempotent, so we keep it disabled for now.
+    ###$self->_simplify_slices(&Slic3r::SCALED_RESOLUTION);
 }
 
 sub detect_surfaces_type {
@@ -850,4 +860,13 @@ sub generate_support_material {
         ->generate($self);
 }
 
+sub _simplify_slices {
+    my ($self, $distance) = @_;
+    
+    foreach my $layer (@{$self->layers}) {
+        $layer->slices->simplify($distance);
+        $_->slices->simplify($distance) for @{$layer->regions};
+    }
+}
+
 1;