From d16dee04afb3ee6d02c4f6c77038c00daa91c00e Mon Sep 17 00:00:00 2001 From: Arthur Date: Thu, 5 Jan 2023 20:25:55 +0800 Subject: [PATCH] ENH: [tree support] use layer_nr_next for calculate_avoidance Previously we used layer_nr-1 as the next support layer below layer_nr, which was not right when we used independent support layer heights. And this would make it difficult for the tree branche to avoid the object. Change-Id: Ic705fbd093e4bd555470646044380703ca259904 (cherry picked from commit 245e1cf4fd071b1f1fea4c5d616ff87432a76911) --- src/libslic3r/TreeSupport.cpp | 65 +++++++++++++++++++++-------------- src/libslic3r/TreeSupport.hpp | 13 ++++++- 2 files changed, 51 insertions(+), 27 deletions(-) diff --git a/src/libslic3r/TreeSupport.cpp b/src/libslic3r/TreeSupport.cpp index e33076b88..147238b8f 100644 --- a/src/libslic3r/TreeSupport.cpp +++ b/src/libslic3r/TreeSupport.cpp @@ -2528,7 +2528,8 @@ void TreeSupport::drop_nodes(std::vector>& contact_nodes) return move_dist; }; - std::vector> layer_heights = plan_layer_heights(contact_nodes); + m_ts_data->layer_heights = plan_layer_heights(contact_nodes); + std::vector &layer_heights = m_ts_data->layer_heights; if (layer_heights.empty()) return; std::unordered_set to_free_node_set; @@ -2548,9 +2549,10 @@ void TreeSupport::drop_nodes(std::vector>& contact_nodes) for (Node *p_node : contact_nodes[layer_nr]) { layer_node_dist.emplace(p_node->dist_mm_to_top); } - if (layer_nr < m_highest_overhang_layer && layer_heights[layer_nr].second>0) { - for (auto node_dist : all_layer_node_dist[layer_nr + 1]) - layer_node_dist.emplace(node_dist + layer_heights[layer_nr].second); + size_t layer_nr_next = layer_heights[layer_nr].next_layer_nr; + if (layer_nr < m_highest_overhang_layer && layer_heights[layer_nr].height>0) { + for (auto node_dist : all_layer_node_dist[layer_nr_next]) + layer_node_dist.emplace(node_dist + layer_heights[layer_nr].height); } for (auto node_dist : layer_node_dist) { layer_radius.emplace(calc_branch_radius(branch_radius, node_dist, diameter_angle_scale_factor)); @@ -2578,11 +2580,9 @@ void TreeSupport::drop_nodes(std::vector>& contact_nodes) if (layer_contact_nodes.empty()) continue; - int layer_nr_next = layer_nr - 1; - while (layer_nr_next>=0 && layer_heights[layer_nr_next].second < EPSILON) - layer_nr_next--; - coordf_t print_z_next = layer_heights[layer_nr_next].first; - coordf_t height_next = layer_heights[layer_nr_next].second; + int layer_nr_next = layer_heights[layer_nr].next_layer_nr; + coordf_t print_z_next = layer_heights[layer_nr_next].print_z; + coordf_t height_next = layer_heights[layer_nr_next].height; std::deque> unsupported_branch_leaves; // All nodes that are leaves on this layer that would result in unsupported ('mid-air') branches. const Layer* ts_layer = m_object->get_support_layer(layer_nr); @@ -2757,7 +2757,7 @@ void TreeSupport::drop_nodes(std::vector>& contact_nodes) const bool to_buildplate = !is_inside_ex(m_ts_data->get_avoidance(0, layer_nr_next), next_position); Node * next_node = new Node(next_position, new_distance_to_top, node.skin_direction, new_support_roof_layers_below, to_buildplate, p_node, - layer_heights[layer_nr_next].first, layer_heights[layer_nr_next].second, new_dist_mm_to_top); + print_z_next, height_next, new_dist_mm_to_top); next_node->movement = next_position - node.position; get_max_move_dist(next_node); next_node->is_merged = true; @@ -3192,7 +3192,7 @@ void TreeSupport::adjust_layer_heights(std::vector>& contact_ } } -std::vector> TreeSupport::plan_layer_heights(std::vector>& contact_nodes) +std::vector TreeSupport::plan_layer_heights(std::vector> &contact_nodes) { const PrintObjectConfig& config = m_object->config(); const PrintConfig & print_config = m_object->print()->config(); @@ -3206,21 +3206,19 @@ std::vector> TreeSupport::plan_layer_heights(std:: } const size_t support_roof_layers = config.support_interface_top_layers.value; const int z_distance_top_layers = round_up_divide(scale_(z_distance_top), scale_(layer_height)) + 1; - std::vector> layer_heights(contact_nodes.size(), std::pair(0.0, 0.0)); + std::vector layer_heights(contact_nodes.size()); std::vector bounds; if (!USE_PLAN_LAYER_HEIGHTS || layer_height == max_layer_height || !print_config.independent_support_layer_height) { for (int layer_nr = 0; layer_nr < contact_nodes.size(); layer_nr++) { - layer_heights[layer_nr].first = m_object->get_layer(layer_nr)->print_z; - layer_heights[layer_nr].second = m_object->get_layer(layer_nr)->height; + layer_heights[layer_nr] = {m_object->get_layer(layer_nr)->print_z, m_object->get_layer(layer_nr)->height, layer_nr > 0 ? size_t(layer_nr - 1) : 0}; } return layer_heights; } bounds.push_back(0); // Keep first layer still - layer_heights[0].first = m_object->get_layer(0)->print_z; - layer_heights[0].second = m_object->get_layer(0)->height; + layer_heights[0] = {m_object->get_layer(0)->print_z, m_object->get_layer(0)->height, 0}; // Collect top contact layers for (int layer_nr = 1; layer_nr < contact_nodes.size(); layer_nr++) { @@ -3228,8 +3226,8 @@ std::vector> TreeSupport::plan_layer_heights(std:: for (int i = 0; i < support_roof_layers + z_distance_top_layers + 1; i++) { if (layer_nr - i > 0) { bounds.push_back(layer_nr - i); - layer_heights[layer_nr - i].first = m_object->get_layer(layer_nr - i)->print_z; - layer_heights[layer_nr - i].second = m_object->get_layer(layer_nr - i)->height; + layer_heights[layer_nr - i].print_z = m_object->get_layer(layer_nr - i)->print_z; + layer_heights[layer_nr - i].height = m_object->get_layer(layer_nr - i)->height; } else { break; @@ -3260,19 +3258,29 @@ std::vector> TreeSupport::plan_layer_heights(std:: for (int layer_nr = extr1_layer_nr + 1; layer_nr < extr2_layer_nr; layer_nr++) { // if (curr_layer_nodes.empty()) continue; if (std::abs(print_z - m_object->get_layer(layer_nr)->print_z) < step / 2 + EPSILON || extr_layers_left < 1) { - layer_heights[layer_nr].first = print_z; - layer_heights[layer_nr].second = step; + layer_heights[layer_nr].print_z = print_z; + layer_heights[layer_nr].height = step; print_z += step; } else { // can't clear curr_layer_nodes, or the model will have empty layers - layer_heights[layer_nr].first = 0.0; - layer_heights[layer_nr].second = 0.0; + layer_heights[layer_nr].print_z = 0.0; + layer_heights[layer_nr].height = 0.0; extr_layers_left--; } } } + for (int i = layer_heights.size() - 1; i >= 0; i--) { + if (layer_heights[i].height < EPSILON) continue; + for (int j = i - 1; j >= 0; j--) { + if (layer_heights[j].height > EPSILON) { + layer_heights[i].next_layer_nr = j; + break; + } + } + } + #ifdef SUPPORT_TREE_DEBUG_TO_SVG // check bounds if (1) @@ -3286,7 +3294,7 @@ std::vector> TreeSupport::plan_layer_heights(std:: } } #endif - for (int i = 0; i < layer_heights.size(); i++) { BOOST_LOG_TRIVIAL(info) << "plan_layer_heights print_z, height: "<< layer_heights[i].first << " " << layer_heights[i].second << std::endl; } + for (int i = 0; i < layer_heights.size(); i++) { BOOST_LOG_TRIVIAL(info) << "plan_layer_heights print_z, height: "<< layer_heights[i].print_z << " " << layer_heights[i].height << std::endl; } return layer_heights; } @@ -3622,13 +3630,18 @@ const ExPolygons& TreeSupportData::calculate_avoidance(const RadiusLayerPair& ke // if the layer at 2N below the current one but we won't exceed our limit unless there are N*N uncalculated layers // below our current one. constexpr auto max_recursion_depth = 100; + size_t layer_nr_next = layer_nr; + for (int i = 0; i < max_recursion_depth && layer_nr_next>0; i++) { + layer_nr_next = layer_heights[layer_nr_next].next_layer_nr; + } // Check if we would exceed the recursion limit by trying to process this layer - if (layer_nr >= max_recursion_depth && m_avoidance_cache.find({radius, layer_nr - max_recursion_depth}) == m_avoidance_cache.end()) { + if (layer_nr >= max_recursion_depth && m_avoidance_cache.find({radius, layer_nr_next}) == m_avoidance_cache.end()) { // Force the calculation of the layer `max_recursion_depth` below our current one, ignoring the result. - get_avoidance(radius, layer_nr - max_recursion_depth); + get_avoidance(radius, layer_nr_next); } - ExPolygons avoidance_areas = std::move(offset_ex(get_avoidance(radius, layer_nr - 1), scale_(-m_max_move))); + layer_nr_next = layer_heights[layer_nr].next_layer_nr; + ExPolygons avoidance_areas = std::move(offset_ex(get_avoidance(radius, layer_nr_next), scale_(-m_max_move))); const ExPolygons &collision = get_collision(radius, layer_nr); avoidance_areas.insert(avoidance_areas.end(), collision.begin(), collision.end()); avoidance_areas = std::move(union_ex(avoidance_areas)); diff --git a/src/libslic3r/TreeSupport.hpp b/src/libslic3r/TreeSupport.hpp index b725b8422..b55612534 100644 --- a/src/libslic3r/TreeSupport.hpp +++ b/src/libslic3r/TreeSupport.hpp @@ -21,6 +21,15 @@ namespace Slic3r class PrintObject; class TreeSupport; +struct LayerHeightData +{ + coordf_t print_z = 0; + coordf_t height = 0; + size_t next_layer_nr = 0; + LayerHeightData() = default; + LayerHeightData(coordf_t z, coordf_t h, size_t next_layer) : print_z(z), height(h), next_layer_nr(next_layer) {} +}; + /*! * \brief Lazily generates tree guidance volumes. * @@ -79,6 +88,8 @@ public: Polygons get_contours(size_t layer_nr) const; Polygons get_contours_with_holes(size_t layer_nr) const; + std::vector layer_heights; + private: /*! * \brief Convenience typedef for the keys to the caches @@ -423,7 +434,7 @@ private: * */ - std::vector> plan_layer_heights(std::vector>& contact_nodes); + std::vector plan_layer_heights(std::vector> &contact_nodes); /*! * \brief Creates points where support contacts the model. *