diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index acaba9d6a..1ef6c7b84 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -1125,7 +1125,7 @@ std::string Print::validate() const
         // Check horizontal clearance.
         {
             Polygons convex_hulls_other;
-            for (PrintObject *object : m_objects) {
+            for (const PrintObject *object : m_objects) {
                 // Get convex hull of all meshes assigned to this print object.
                 Polygon convex_hull;
                 {
@@ -1186,46 +1186,63 @@ std::string Print::validate() const
             return L("The Wipe Tower is currently only supported for the Marlin, RepRap/Sprinter and Repetier G-code flavors.");
         if (! m_config.use_relative_e_distances)
             return L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1).");
-        SlicingParameters slicing_params0 = m_objects.front()->slicing_parameters();
 
-        const PrintObject* tallest_object = m_objects.front(); // let's find the tallest object
-        for (const auto* object : m_objects)
-            if (*(object->layer_height_profile.end()-2) > *(tallest_object->layer_height_profile.end()-2) )
-                    tallest_object = object;
-
-        for (PrintObject *object : m_objects) {
-            SlicingParameters slicing_params = object->slicing_parameters();
-            if (std::abs(slicing_params.first_print_layer_height - slicing_params0.first_print_layer_height) > EPSILON ||
-                std::abs(slicing_params.layer_height             - slicing_params0.layer_height            ) > EPSILON)
-                return L("The Wipe Tower is only supported for multiple objects if they have equal layer heigths");
-            if (slicing_params.raft_layers() != slicing_params0.raft_layers())
-                return L("The Wipe Tower is only supported for multiple objects if they are printed over an equal number of raft layers");
-            if (object->config().support_material_contact_distance != m_objects.front()->config().support_material_contact_distance)
-                return L("The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance");
-            if (! equal_layering(slicing_params, slicing_params0))
-                return L("The Wipe Tower is only supported for multiple objects if they are sliced equally.");
-
-            if (m_config.variable_layer_height) { // comparing layer height profiles
-                bool failed = false;
-                // layer_height_profile should be set by Print::apply().
-                if (tallest_object->layer_height_profile.size() >= object->layer_height_profile.size()) {
-                    int i = 0;
-                    while (i < object->layer_height_profile.size() && i < tallest_object->layer_height_profile.size()) {
-                        if (std::abs(tallest_object->layer_height_profile[i] - object->layer_height_profile[i])) {
-                            failed = true;
-                            break;
-                        }
-                        ++i;
-                        if (i == object->layer_height_profile.size()-2) // this element contains this objects max z
-                            if (tallest_object->layer_height_profile[i] > object->layer_height_profile[i]) // the difference does not matter in this case
-                                ++i;
-                    }
+        if (m_objects.size() > 1) {
+            bool                                has_custom_layering = false;
+            std::vector<std::vector<coordf_t>>  layer_height_profiles;
+            for (const PrintObject *object : m_objects) {
+                has_custom_layering = ! object->model_object()->layer_height_ranges.empty() || ! object->model_object()->layer_height_profile.empty();
+                if (has_custom_layering) {
+                    layer_height_profiles.assign(m_objects.size(), std::vector<coordf_t>());
+                    break;
                 }
-                else
-                    failed = true;
+            }
+            SlicingParameters slicing_params0    = m_objects.front()->slicing_parameters();
+            size_t            tallest_object_idx = 0;
+            if (has_custom_layering)
+                PrintObject::update_layer_height_profile(*m_objects.front()->model_object(), slicing_params0, layer_height_profiles.front());
+            for (size_t i = 1; i < m_objects.size(); ++ i) {
+                const PrintObject      *object         = m_objects[i];
+                const SlicingParameters slicing_params = object->slicing_parameters();
+                if (std::abs(slicing_params.first_print_layer_height - slicing_params0.first_print_layer_height) > EPSILON ||
+                    std::abs(slicing_params.layer_height             - slicing_params0.layer_height            ) > EPSILON)
+                    return L("The Wipe Tower is only supported for multiple objects if they have equal layer heigths");
+                if (slicing_params.raft_layers() != slicing_params0.raft_layers())
+                    return L("The Wipe Tower is only supported for multiple objects if they are printed over an equal number of raft layers");
+                if (object->config().support_material_contact_distance != m_objects.front()->config().support_material_contact_distance)
+                    return L("The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance");
+                if (! equal_layering(slicing_params, slicing_params0))
+                    return L("The Wipe Tower is only supported for multiple objects if they are sliced equally.");
+                if (has_custom_layering) {
+                    PrintObject::update_layer_height_profile(*object->model_object(), slicing_params, layer_height_profiles[i]);
+                    if (*(layer_height_profiles[i].end()-2) > *(layer_height_profiles[tallest_object_idx].end()-2))
+                        tallest_object_idx = i;
+                }
+            }
 
-                if (failed)
-                    return L("The Wipe tower is only supported if all objects have the same layer height profile");
+            if (has_custom_layering) {
+                const std::vector<coordf_t> &layer_height_profile_tallest = layer_height_profiles[tallest_object_idx];
+                for (size_t idx_object = 0; idx_object < m_objects.size(); ++ idx_object) {
+                    const PrintObject           *object               = m_objects[idx_object];
+                    const std::vector<coordf_t> &layer_height_profile = layer_height_profiles[idx_object];
+                    bool                         failed               = false;
+                    if (layer_height_profile_tallest.size() >= layer_height_profile.size()) {
+                        int i = 0;
+                        while (i < layer_height_profile.size() && i < layer_height_profile_tallest.size()) {
+                            if (std::abs(layer_height_profile_tallest[i] - layer_height_profile[i])) {
+                                failed = true;
+                                break;
+                            }
+                            ++ i;
+                            if (i == layer_height_profile.size() - 2) // this element contains this objects max z
+                                if (layer_height_profile_tallest[i] > layer_height_profile[i]) // the difference does not matter in this case
+                                    ++ i;
+                        }
+                    } else
+                        failed = true;
+                    if (failed)
+                        return L("The Wipe tower is only supported if all objects have the same layer height profile");
+                }
             }
         }
     }
diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp
index d0591e764..3de91818a 100644
--- a/src/libslic3r/Print.hpp
+++ b/src/libslic3r/Print.hpp
@@ -83,10 +83,6 @@ public:
     // vector of (vectors of volume ids), indexed by region_id
     std::vector<std::vector<int>> region_volumes;
 
-    // Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers.
-    // The pairs of <z, layer_height> are packed into a 1D array.
-    std::vector<coordf_t>   layer_height_profile;
-    
     // this is set to true when LayerRegion->slices is split in top/internal/bottom
     // so that next call to make_perimeters() performs a union() before computing loops
     bool                    typed_slices;
@@ -175,7 +171,7 @@ private:
     void infill();
     void generate_support_material();
 
-    void _slice();
+    void _slice(const std::vector<coordf_t> &layer_height_profile);
     std::string _fix_slicing_errors();
     void _simplify_slices(double distance);
     void _make_perimeters();
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index 9dd101123..d516153a9 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -64,8 +64,6 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, bool add_insta
         }
         this->set_copies(copies);
     }
-
-    this->layer_height_profile = model_object->layer_height_profile;
 }
 
 PrintBase::ApplyStatus PrintObject::set_copies(const Points &points)
@@ -105,9 +103,10 @@ void PrintObject::slice()
     if (! this->set_started(posSlice))
         return;
     m_print->set_status(10, "Processing triangulated mesh");
-    this->update_layer_height_profile(*this->model_object(), this->slicing_parameters(), this->layer_height_profile);
+    std::vector<coordf_t> layer_height_profile;
+    this->update_layer_height_profile(*this->model_object(), this->slicing_parameters(), layer_height_profile);
     m_print->throw_if_canceled();
-    this->_slice();
+    this->_slice(layer_height_profile);
     m_print->throw_if_canceled();
     // Fix the model.
     //FIXME is this the right place to do? It is done repeateadly at the UI and now here at the backend.
@@ -1438,7 +1437,7 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c
 // Resulting expolygons of layer regions are marked as Internal.
 //
 // this should be idempotent
-void PrintObject::_slice()
+void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
 {
     BOOST_LOG_TRIVIAL(info) << "Slicing objects..." << log_memory_info();
 
@@ -1457,7 +1456,7 @@ void PrintObject::_slice()
     {
         this->clear_layers();
         // Object layers (pairs of bottom/top Z coordinate), without the raft.
-        std::vector<coordf_t> object_layers = generate_object_layers(slicing_params, this->layer_height_profile);
+        std::vector<coordf_t> object_layers = generate_object_layers(slicing_params, layer_height_profile);
         // Reserve object layers for the raft. Last layer of the raft is the contact layer.
         int id = int(slicing_params.raft_layers());
         slice_zs.reserve(object_layers.size());
diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp
index 8a0a087c0..ff8c20289 100644
--- a/src/libslic3r/TriangleMesh.cpp
+++ b/src/libslic3r/TriangleMesh.cpp
@@ -99,6 +99,8 @@ TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other)
     return *this;
 }
 
+// #define SLIC3R_TRACE_REPAIR
+
 void TriangleMesh::repair()
 {
     if (this->repaired) return;
@@ -109,7 +111,9 @@ void TriangleMesh::repair()
     BOOST_LOG_TRIVIAL(debug) << "TriangleMesh::repair() started";
     
     // checking exact
+#ifdef SLIC3R_TRACE_REPAIR
 	BOOST_LOG_TRIVIAL(trace) << "\tstl_check_faces_exact";
+#endif /* SLIC3R_TRACE_REPAIR */
 	stl_check_facets_exact(&stl);
     stl.stats.facets_w_1_bad_edge = (stl.stats.connected_facets_2_edge - stl.stats.connected_facets_3_edge);
     stl.stats.facets_w_2_bad_edge = (stl.stats.connected_facets_1_edge - stl.stats.connected_facets_2_edge);
@@ -124,7 +128,9 @@ void TriangleMesh::repair()
         for (int i = 0; i < iterations; i++) {
             if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) {
                 //printf("Checking nearby. Tolerance= %f Iteration=%d of %d...", tolerance, i + 1, iterations);
+#ifdef SLIC3R_TRACE_REPAIR
 				BOOST_LOG_TRIVIAL(trace) << "\tstl_check_faces_nearby";
+#endif /* SLIC3R_TRACE_REPAIR */
 				stl_check_facets_nearby(&stl, tolerance);
                 //printf("  Fixed %d edges.\n", stl.stats.edges_fixed - last_edges_fixed);
                 //last_edges_fixed = stl.stats.edges_fixed;
@@ -137,7 +143,9 @@ void TriangleMesh::repair()
     
     // remove_unconnected
     if (stl.stats.connected_facets_3_edge <  stl.stats.number_of_facets) {
+#ifdef SLIC3R_TRACE_REPAIR
         BOOST_LOG_TRIVIAL(trace) << "\tstl_remove_unconnected_facets";
+#endif /* SLIC3R_TRACE_REPAIR */
         stl_remove_unconnected_facets(&stl);
     }
     
@@ -146,26 +154,36 @@ void TriangleMesh::repair()
     // Don't fill holes, the current algorithm does more harm than good on complex holes.
     // Rather let the slicing algorithm close gaps in 2D slices.
     if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) {
+#ifdef SLIC3R_TRACE_REPAIR
         BOOST_LOG_TRIVIAL(trace) << "\tstl_fill_holes";
+#endif /* SLIC3R_TRACE_REPAIR */
         stl_fill_holes(&stl);
         stl_clear_error(&stl);
     }
 #endif
 
     // normal_directions
+#ifdef SLIC3R_TRACE_REPAIR
     BOOST_LOG_TRIVIAL(trace) << "\tstl_fix_normal_directions";
+#endif /* SLIC3R_TRACE_REPAIR */
     stl_fix_normal_directions(&stl);
 
     // normal_values
+#ifdef SLIC3R_TRACE_REPAIR
     BOOST_LOG_TRIVIAL(trace) << "\tstl_fix_normal_values";
+#endif /* SLIC3R_TRACE_REPAIR */
     stl_fix_normal_values(&stl);
     
     // always calculate the volume and reverse all normals if volume is negative
+#ifdef SLIC3R_TRACE_REPAIR
     BOOST_LOG_TRIVIAL(trace) << "\tstl_calculate_volume";
+#endif /* SLIC3R_TRACE_REPAIR */
     stl_calculate_volume(&stl);
     
     // neighbors
+#ifdef SLIC3R_TRACE_REPAIR
     BOOST_LOG_TRIVIAL(trace) << "\tstl_verify_neighbors";
+#endif /* SLIC3R_TRACE_REPAIR */
     stl_verify_neighbors(&stl);
 
     this->repaired = true;
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 0bd3d26ca..6a3e3b47e 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -1179,11 +1179,12 @@ void GLCanvas3D::LayersEditing::adjust_layer_height_profile()
     m_layers_texture.valid = false;
 }
 
-void GLCanvas3D::LayersEditing::reset_layer_height_profile()
+void GLCanvas3D::LayersEditing::reset_layer_height_profile(GLCanvas3D& canvas)
 {
 	const_cast<ModelObject*>(m_model_object)->layer_height_profile.clear();
     m_layer_height_profile.clear();
     m_layers_texture.valid = false;
+    canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
 }
 
 void GLCanvas3D::LayersEditing::generate_layer_height_texture()
@@ -5117,7 +5118,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
             if (evt.LeftDown())
             {
                 // A volume is selected and the mouse is inside the reset button. Reset the ModelObject's layer height profile.
-				m_layers_editing.reset_layer_height_profile();
+				m_layers_editing.reset_layer_height_profile(*this);
                 // Index 2 means no editing, just wait for mouse up event.
                 m_layers_editing.state = LayersEditing::Completed;
 
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index 38f02ff8f..ab53d5048 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -360,7 +360,7 @@ class GLCanvas3D
 
 		void adjust_layer_height_profile();
 		void accept_changes(GLCanvas3D& canvas);
-        void reset_layer_height_profile();
+        void reset_layer_height_profile(GLCanvas3D& canvas);
 
         static float get_cursor_z_relative(const GLCanvas3D& canvas);
         static bool bar_rect_contains(const GLCanvas3D& canvas, float x, float y);