diff --git a/lib/Slic3r/GCode/Layer.pm b/lib/Slic3r/GCode/Layer.pm
index 9bac7901c..5f3531d6d 100644
--- a/lib/Slic3r/GCode/Layer.pm
+++ b/lib/Slic3r/GCode/Layer.pm
@@ -135,7 +135,7 @@ sub process_layer {
         }
         
         # tweak region ordering to save toolchanges
-        my @region_ids = 0 .. ($self->print->regions_count-1);
+        my @region_ids = 0 .. ($self->print->region_count-1);
         if ($self->gcodegen->multiple_extruders) {
             my $last_extruder = $self->gcodegen->extruder;
             my $best_region_id = first { $self->print->regions->[$_]->config->perimeter_extruder-1 eq $last_extruder } @region_ids;
diff --git a/lib/Slic3r/GUI/Plater/2DToolpaths.pm b/lib/Slic3r/GUI/Plater/2DToolpaths.pm
index 93b61f56e..8e48a7290 100644
--- a/lib/Slic3r/GUI/Plater/2DToolpaths.pm
+++ b/lib/Slic3r/GUI/Plater/2DToolpaths.pm
@@ -135,7 +135,7 @@ sub set_z {
     my $interlaced = (defined first { $_->config->support_material } @{$print->objects})
         || (defined first { $_->config->infill_every_layers > 1 } @{$print->regions});
     
-    my $max_layer_height = $print->max_layer_height;
+    my $max_layer_height = $print->max_allowed_layer_height;
     
     my @layers = ();
     foreach my $object (@{$print->objects}) {
diff --git a/lib/Slic3r/Layer.pm b/lib/Slic3r/Layer.pm
index f6fc9f342..694f7050d 100644
--- a/lib/Slic3r/Layer.pm
+++ b/lib/Slic3r/Layer.pm
@@ -39,24 +39,6 @@ sub regions {
     return [ map $self->get_region($_), 0..($self->region_count-1) ];
 }
 
-# merge all regions' slices to get islands
-sub make_slices {
-    my $self = shift;
-    
-    my $slices;
-    if (@{$self->regions} == 1) {
-        $slices = [ map $_->expolygon->clone, @{$self->regions->[0]->slices} ];
-    } else {
-        $slices = union_ex([ map $_->p, map @{$_->slices}, @{$self->regions} ]);
-    }
-    
-    # sort slices
-    $slices = [ @$slices[@{chained_path([ map $_->contour->first_point, @$slices ])}] ];
-    
-    $self->slices->clear;
-    $self->slices->append(@$slices);
-}
-
 sub merge_slices {
     my ($self) = @_;
     $_->merge_slices for @{$self->regions};
diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm
index 755823661..71e591734 100644
--- a/lib/Slic3r/Print.pm
+++ b/lib/Slic3r/Print.pm
@@ -148,13 +148,6 @@ sub apply_config {
     return $invalidated;
 }
 
-sub has_support_material {
-    my $self = shift;
-    return (first { $_->config->support_material } @{$self->objects})
-        || (first { $_->config->raft_layers > 0 } @{$self->objects})
-        || (first { $_->config->support_material_enforce_layers > 0 } @{$self->objects});
-}
-
 # caller is responsible for supplying models whose objects don't collide
 # and have explicit instance positions
 sub add_model_object {
@@ -311,43 +304,6 @@ sub validate {
     }
 }
 
-# 0-based indices of used extruders
-sub extruders {
-    my ($self) = @_;
-    
-    # initialize all extruder(s) we need
-    my @used_extruders = ();
-    foreach my $region (@{$self->regions}) {
-        push @used_extruders,
-            map $region->config->get("${_}_extruder")-1,
-            qw(perimeter infill);
-    }
-    foreach my $object (@{$self->objects}) {
-        push @used_extruders,
-            map $object->config->get("${_}_extruder")-1,
-            qw(support_material support_material_interface);
-    }
-    
-    my %h = map { $_ => 1 } @used_extruders;
-    return [ sort keys %h ];
-}
-
-sub init_extruders {
-    my $self = shift;
-    
-    return if $self->step_done(STEP_INIT_EXTRUDERS);
-    $self->set_step_started(STEP_INIT_EXTRUDERS);
-    
-    # enforce tall skirt if using ooze_prevention
-    # FIXME: this is not idempotent (i.e. switching ooze_prevention off will not revert skirt settings)
-    if ($self->config->ooze_prevention && @{$self->extruders} > 1) {
-        $self->config->set('skirt_height', -1);
-        $self->config->set('skirts', 1) if $self->config->skirts == 0;
-    }
-    
-    $self->set_step_done(STEP_INIT_EXTRUDERS);
-}
-
 # this value is not supposed to be compared with $layer->id
 # since they have different semantics
 sub total_layer_count {
@@ -355,16 +311,6 @@ sub total_layer_count {
     return max(map $_->total_layer_count, @{$self->objects});
 }
 
-sub regions_count {
-    my $self = shift;
-    return scalar @{$self->regions};
-}
-
-sub max_layer_height {
-    my ($self) = @_;
-    return max(@{$self->config->nozzle_diameter});
-}
-
 # the bounding box of objects placed in copies position
 # (without taking skirt/brim/support material into account)
 sub bounding_box {
@@ -410,16 +356,6 @@ sub size {
     return $self->bounding_box->size;
 }
 
-sub _simplify_slices {
-    my $self = shift;
-    my ($distance) = @_;
-    
-    foreach my $layer (map @{$_->layers}, @{$self->objects}) {
-        $layer->slices->simplify($distance);
-        $_->slices->simplify($distance) for @{$layer->regions};
-    }
-}
-
 sub process {
     my ($self) = @_;
     
diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm
index 182e21998..a1aaff307 100644
--- a/lib/Slic3r/Print/Object.pm
+++ b/lib/Slic3r/Print/Object.pm
@@ -173,7 +173,7 @@ sub slice {
     }
     
     # make sure all layers contain layer region objects for all regions
-    my $regions_count = $self->print->regions_count;
+    my $regions_count = $self->print->region_count;
     foreach my $layer (@{ $self->layers }) {
         $layer->region($_) for 0 .. ($regions_count-1);
     }
@@ -427,7 +427,7 @@ sub make_perimeters {
     # but we don't generate any extra perimeter if fill density is zero, as they would be floating
     # inside the object - infill_only_where_needed should be the method of choice for printing
     # hollow objects
-    for my $region_id (0 .. ($self->print->regions_count-1)) {
+    for my $region_id (0 .. ($self->print->region_count-1)) {
         my $region = $self->print->regions->[$region_id];
         my $region_perimeters = $region->config->perimeters;
         
@@ -555,7 +555,7 @@ sub infill {
         threads => $self->print->config->threads,
         items => sub {
             my @items = ();  # [layer_id, region_id]
-            for my $region_id (0 .. ($self->print->regions_count-1)) {
+            for my $region_id (0 .. ($self->print->region_count-1)) {
                 push @items, map [$_, $region_id], 0..($self->layer_count - 1);
             }
             @items;
@@ -627,7 +627,7 @@ sub detect_surfaces_type {
     my $self = shift;
     Slic3r::debugf "Detecting solid surfaces...\n";
     
-    for my $region_id (0 .. ($self->print->regions_count-1)) {
+    for my $region_id (0 .. ($self->print->region_count-1)) {
         for my $i (0 .. ($self->layer_count - 1)) {
             my $layerm = $self->get_layer($i)->regions->[$region_id];
         
@@ -885,7 +885,7 @@ sub bridge_over_infill {
 sub process_external_surfaces {
     my ($self) = @_;
     
-    for my $region_id (0 .. ($self->print->regions_count-1)) {
+    for my $region_id (0 .. ($self->print->region_count-1)) {
         $self->get_layer(0)->regions->[$region_id]->process_external_surfaces(undef);
         for my $i (1 .. ($self->layer_count - 1)) {
             $self->get_layer($i)->regions->[$region_id]->process_external_surfaces($self->get_layer($i-1));
@@ -898,7 +898,7 @@ sub discover_horizontal_shells {
     
     Slic3r::debugf "==> DISCOVERING HORIZONTAL SHELLS\n";
     
-    for my $region_id (0 .. ($self->print->regions_count-1)) {
+    for my $region_id (0 .. ($self->print->region_count-1)) {
         for (my $i = 0; $i < $self->layer_count; $i++) {
             my $layerm = $self->get_layer($i)->regions->[$region_id];
             
@@ -1048,7 +1048,7 @@ sub combine_infill {
     
     my @layer_heights = map $_->height, @{$self->layers};
     
-    for my $region_id (0 .. ($self->print->regions_count-1)) {
+    for my $region_id (0 .. ($self->print->region_count-1)) {
         my $region = $self->print->regions->[$region_id];
         my $every = $region->config->infill_every_layers;
         
diff --git a/xs/src/Layer.cpp b/xs/src/Layer.cpp
index 69f9fb13a..3df747250 100644
--- a/xs/src/Layer.cpp
+++ b/xs/src/Layer.cpp
@@ -1,4 +1,7 @@
 #include "Layer.hpp"
+#include "ClipperUtils.hpp"
+#include "Geometry.hpp"
+#include "Print.hpp"
 
 
 namespace Slic3r {
@@ -108,6 +111,42 @@ Layer::delete_region(int idx)
     delete item;
 }
 
+// merge all regions' slices to get islands
+void
+Layer::make_slices()
+{
+    ExPolygons slices;
+    if (this->regions.size() == 1) {
+        // optimization: if we only have one region, take its slices
+        slices = this->regions.front()->slices;
+    } else {
+        Polygons slices_p;
+        FOREACH_LAYERREGION(this, layerm) {
+            Polygons region_slices_p = (*layerm)->slices;
+            slices_p.insert(slices_p.end(), region_slices_p.begin(), region_slices_p.end());
+        }
+        union_(slices_p, slices);
+    }
+    
+    this->slices.expolygons.clear();
+    this->slices.expolygons.reserve(slices.size());
+    
+    // prepare ordering points
+    Points ordering_points;
+    ordering_points.reserve(slices.size());
+    for (ExPolygons::const_iterator ex = slices.begin(); ex != slices.end(); ++ex)
+        ordering_points.push_back(ex->contour.first_point());
+    
+    // sort slices
+    std::vector<Points::size_type> order;
+    Slic3r::Geometry::chained_path(ordering_points, order);
+    
+    // populate slices vector
+    for (std::vector<Points::size_type>::const_iterator it = order.begin(); it != order.end(); ++it) {
+        this->slices.expolygons.push_back(slices[*it]);
+    }
+}
+
 
 #ifdef SLIC3RXS
 REGISTER_CLASS(Layer, "Layer");
diff --git a/xs/src/Layer.hpp b/xs/src/Layer.hpp
index ca876be99..bfbaddc3c 100644
--- a/xs/src/Layer.hpp
+++ b/xs/src/Layer.hpp
@@ -84,6 +84,8 @@ class Layer {
     size_t region_count();
     LayerRegion* get_region(int idx);
     LayerRegion* add_region(PrintRegion* print_region);
+    
+    void make_slices();
 
     protected:
     int _id;     // sequential number of layer, 0-based
diff --git a/xs/src/Print.cpp b/xs/src/Print.cpp
index 7137e804b..a4b69be4c 100644
--- a/xs/src/Print.cpp
+++ b/xs/src/Print.cpp
@@ -1,5 +1,6 @@
 #include "Print.hpp"
 #include "BoundingBox.hpp"
+#include <algorithm>
 
 namespace Slic3r {
 
@@ -511,7 +512,7 @@ Print::invalidate_step(PrintStep step)
     if (step == psSkirt) {
         this->invalidate_step(psBrim);
     } else if (step == psInitExtruders) {
-        for (PrintObjectPtrs::iterator object = this->objects.begin(); object != this->objects.end(); ++object) {
+        FOREACH_OBJECT(this, object) {
             (*object)->invalidate_step(posPerimeters);
             (*object)->invalidate_step(posSupportMaterial);
         }
@@ -533,6 +534,77 @@ Print::invalidate_all_steps()
     return invalidated;
 }
 
+// returns 0-based indices of used extruders
+std::set<size_t>
+Print::extruders() const
+{
+    std::set<size_t> extruders;
+    
+    FOREACH_REGION(this, region) {
+        extruders.insert((*region)->config.perimeter_extruder - 1);
+        extruders.insert((*region)->config.infill_extruder - 1);
+    }
+    FOREACH_OBJECT(this, object) {
+        extruders.insert((*object)->config.support_material_extruder - 1);
+        extruders.insert((*object)->config.support_material_interface_extruder - 1);
+    }
+    
+    return extruders;
+}
+
+void
+Print::_simplify_slices(double distance)
+{
+    FOREACH_OBJECT(this, object) {
+        FOREACH_LAYER(*object, layer) {
+            (*layer)->slices.simplify(distance);
+            FOREACH_LAYERREGION(*layer, layerm) {
+                (*layerm)->slices.simplify(distance);
+            }
+        }
+    }
+}
+
+double
+Print::max_allowed_layer_height() const
+{
+    std::vector<double> nozzle_diameter;
+    
+    std::set<size_t> extruders = this->extruders();
+    for (std::set<size_t>::const_iterator e = extruders.begin(); e != extruders.end(); ++e) {
+        nozzle_diameter.push_back(this->config.nozzle_diameter.get_at(*e));
+    }
+    
+    return *std::max_element(nozzle_diameter.begin(), nozzle_diameter.end());
+}
+
+void
+Print::init_extruders()
+{
+    if (this->state.is_done(psInitExtruders)) return;
+    this->state.set_done(psInitExtruders);
+    
+    // enforce tall skirt if using ooze_prevention
+    // FIXME: this is not idempotent (i.e. switching ooze_prevention off will not revert skirt settings)
+    if (this->config.ooze_prevention && this->extruders().size() > 1) {
+        this->config.skirt_height.value = -1;
+        if (this->config.skirts == 0) this->config.skirts.value = 1;
+    }
+    
+    this->state.set_done(psInitExtruders);
+}
+
+bool
+Print::has_support_material() const
+{
+    FOREACH_OBJECT(this, object) {
+        PrintObjectConfig &config = (*object)->config;
+        if (config.support_material || config.raft_layers > 0 || config.support_material_enforce_layers > 0)
+            return true;
+    }
+    return false;
+}
+
 
 #ifdef SLIC3RXS
 REGISTER_CLASS(Print, "Print");
diff --git a/xs/src/Print.hpp b/xs/src/Print.hpp
index 9bd0d8212..aa94ded66 100644
--- a/xs/src/Print.hpp
+++ b/xs/src/Print.hpp
@@ -160,12 +160,25 @@ class Print
     bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
     bool invalidate_step(PrintStep step);
     bool invalidate_all_steps();
-
+    
+    void init_extruders();
+    
+    std::set<size_t> extruders() const;
+    void _simplify_slices(double distance);
+    double max_allowed_layer_height() const;
+    bool has_support_material() const;
+    
     private:
     void clear_regions();
     void delete_region(size_t idx);
 };
 
+#define FOREACH_BASE(type, container, iterator) for (type::const_iterator iterator = (container).begin(); iterator != (container).end(); ++iterator)
+#define FOREACH_REGION(print, region)       FOREACH_BASE(PrintRegionPtrs, (print)->regions, region)
+#define FOREACH_OBJECT(print, object)       FOREACH_BASE(PrintObjectPtrs, (print)->objects, object)
+#define FOREACH_LAYER(object, layer)        FOREACH_BASE(LayerPtrs, (object)->layers, layer)
+#define FOREACH_LAYERREGION(layer, layerm)  FOREACH_BASE(LayerRegionPtrs, (layer)->regions, layerm)
+
 }
 
 #endif
diff --git a/xs/src/SurfaceCollection.cpp b/xs/src/SurfaceCollection.cpp
index 77c2e6d0a..1590e7a21 100644
--- a/xs/src/SurfaceCollection.cpp
+++ b/xs/src/SurfaceCollection.cpp
@@ -3,6 +3,26 @@
 
 namespace Slic3r {
 
+SurfaceCollection::operator Polygons() const
+{
+    Polygons polygons;
+    for (Surfaces::const_iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) {
+        Polygons surface_p = surface->expolygon;
+        polygons.insert(polygons.end(), surface_p.begin(), surface_p.end());
+    }
+    return polygons;
+}
+
+SurfaceCollection::operator ExPolygons() const
+{
+    ExPolygons expp;
+    expp.reserve(this->surfaces.size());
+    for (Surfaces::const_iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) {
+        expp.push_back(surface->expolygon);
+    }
+    return expp;
+}
+
 void
 SurfaceCollection::simplify(double tolerance)
 {
diff --git a/xs/src/SurfaceCollection.hpp b/xs/src/SurfaceCollection.hpp
index cb8088c47..fe3fae8c6 100644
--- a/xs/src/SurfaceCollection.hpp
+++ b/xs/src/SurfaceCollection.hpp
@@ -10,6 +10,9 @@ class SurfaceCollection
 {
     public:
     Surfaces surfaces;
+    
+    operator Polygons() const;
+    operator ExPolygons() const;
     void simplify(double tolerance);
     void group(std::vector<SurfacesPtr> *retval);
 };
diff --git a/xs/xsp/Layer.xsp b/xs/xsp/Layer.xsp
index 6c5243aed..7d297216f 100644
--- a/xs/xsp/Layer.xsp
+++ b/xs/xsp/Layer.xsp
@@ -60,6 +60,8 @@
     
     int ptr()
         %code%{ RETVAL = (int)(intptr_t)THIS; %};
+    
+    void make_slices();
 };
 
 %name{Slic3r::Layer::Support} class SupportLayer {
diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp
index c104eaf30..548123f75 100644
--- a/xs/xsp/Print.xsp
+++ b/xs/xsp/Print.xsp
@@ -153,6 +153,20 @@ _constant()
         %code%{ THIS->state.set_done(step); %};
     void set_step_started(PrintStep step)
         %code%{ THIS->state.set_started(step); %};
+    
+    std::vector<int> extruders()
+        %code%{
+            std::set<size_t> extruders = THIS->extruders();
+            RETVAL.reserve(extruders.size());
+            for (std::set<size_t>::const_iterator e = extruders.begin(); e != extruders.end(); ++e) {
+                RETVAL.push_back(*e);
+            }
+        %};
+    void _simplify_slices(double distance);
+    double max_allowed_layer_height() const;
+    bool has_support_material() const;
+    
+    void init_extruders();
 %{
 
 double