From 0af11c51e38089da839942ab2d1fd442bfb0e8b2 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Wed, 23 Jan 2019 14:00:03 +0100
Subject: [PATCH] Fixed update on reset of the variable layer height profile.
 Fixed update of the layer height profile on PrintObject when changing
 profiles. Fixed crash due to the layer height editing refactoring & wipe
 tower.

---
 src/libslic3r/Print.cpp        | 93 ++++++++++++++++++++--------------
 src/libslic3r/Print.hpp        |  6 +--
 src/libslic3r/PrintObject.cpp  | 11 ++--
 src/libslic3r/TriangleMesh.cpp | 18 +++++++
 src/slic3r/GUI/GLCanvas3D.cpp  |  5 +-
 src/slic3r/GUI/GLCanvas3D.hpp  |  2 +-
 6 files changed, 83 insertions(+), 52 deletions(-)

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);