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