mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	ENH: improve smoothness of tree supports
1. Instead of smoothing top-down, now we smooth tree branches bottom-up, and do not stop at merged nodes. 2. Fix a bug where some nodes don't have child. This is critical for bottom-up smoothing. Change-Id: Iac0fecd81dac541ca390bcf5cbdfe7fd66cfd3a2 (cherry picked from commit 536a8a4f0ef76fa0358f4b4b181c4c7e7fff8bc7)
This commit is contained in:
		
							parent
							
								
									763cf8ebfc
								
							
						
					
					
						commit
						719f273fa2
					
				
					 2 changed files with 69 additions and 34 deletions
				
			
		|  | @ -27,6 +27,9 @@ | ||||||
| 
 | 
 | ||||||
| // #define SUPPORT_TREE_DEBUG_TO_SVG
 | // #define SUPPORT_TREE_DEBUG_TO_SVG
 | ||||||
| 
 | 
 | ||||||
|  | #if SUPPORT_TREE_DEBUG_TO_SVG | ||||||
|  | #include "nlohmann/json.hpp" | ||||||
|  | #endif | ||||||
| namespace Slic3r | namespace Slic3r | ||||||
| { | { | ||||||
| #define unscale_(val) ((val) * SCALING_FACTOR) | #define unscale_(val) ((val) * SCALING_FACTOR) | ||||||
|  | @ -2983,64 +2986,94 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes) | ||||||
| 
 | 
 | ||||||
| void TreeSupport::smooth_nodes(std::vector<std::vector<Node *>> &contact_nodes) | void TreeSupport::smooth_nodes(std::vector<std::vector<Node *>> &contact_nodes) | ||||||
| { | { | ||||||
|     std::map<Node *, bool> is_processed; |  | ||||||
|     for (int layer_nr = 0; layer_nr < contact_nodes.size(); layer_nr++) { |     for (int layer_nr = 0; layer_nr < contact_nodes.size(); layer_nr++) { | ||||||
|         std::vector<Node *> &curr_layer_nodes = contact_nodes[layer_nr]; |         std::vector<Node *> &curr_layer_nodes = contact_nodes[layer_nr]; | ||||||
|         if (curr_layer_nodes.empty()) continue; |         if (curr_layer_nodes.empty()) continue; | ||||||
|         for (Node *node : curr_layer_nodes) { |         for (Node *node : curr_layer_nodes) { | ||||||
|             is_processed.emplace(node, false); |             node->is_processed = false; | ||||||
|             if (layer_nr == 0) node->is_merged = true;  // nodes on plate are also merged nodes
 |             if (layer_nr == 0) node->is_merged = true;  // nodes on plate are also merged nodes
 | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for (int layer_nr = contact_nodes.size()-1; layer_nr >=0 ; layer_nr--) { |     for (int layer_nr = 0; layer_nr< contact_nodes.size(); layer_nr++) { | ||||||
|         std::vector<Node *> &curr_layer_nodes = contact_nodes[layer_nr]; |         std::vector<Node *> &curr_layer_nodes = contact_nodes[layer_nr]; | ||||||
|         if (curr_layer_nodes.empty()) continue; |         if (curr_layer_nodes.empty()) continue; | ||||||
|         for (Node *node : curr_layer_nodes) { |         for (Node *node : curr_layer_nodes) { | ||||||
|             if (!is_processed[node]) {  |             if (!node->is_processed) { | ||||||
|                 std::vector<Point> pts; |                 std::vector<Point> pts; | ||||||
|                 std::vector<Node *>   branch; |                 std::vector<Node *>   branch; | ||||||
|                 Node *              p_node = node; |                 Node *              p_node = node; | ||||||
|                 // add head for second path from the merged node if there are multiple ones
 |                 // add a fixed head
 | ||||||
|                 if (!node->is_merged && node->parent) { |                 if (node->child) { | ||||||
|                     pts.push_back(p_node->parent->position); |                     pts.push_back(p_node->child->position); | ||||||
|                     branch.push_back(p_node->parent); |                     branch.push_back(p_node->child); | ||||||
|                 } |                 } | ||||||
|                 do { |                 do { | ||||||
|                     pts.push_back(p_node->position); |                     pts.push_back(p_node->position); | ||||||
|                     //is_processed[p_node] = true;
 |  | ||||||
|                     branch.push_back(p_node); |                     branch.push_back(p_node); | ||||||
|                     p_node = p_node->child; |                     p_node = p_node->parent; | ||||||
|                 } while (p_node && !p_node->is_merged && !is_processed[p_node]); |                 } while (p_node && !p_node->is_processed); | ||||||
|                 // TODO is it necessary to add tail also?
 |  | ||||||
|                 if (p_node && p_node->is_merged) { |  | ||||||
|                     pts.push_back(p_node->position); |  | ||||||
|                     branch.push_back(p_node); |  | ||||||
|                 } |  | ||||||
|                 if (pts.size() < 3) continue; |                 if (pts.size() < 3) continue; | ||||||
| 
 | 
 | ||||||
|                 std::vector<Point> pts1 = pts; |                 std::vector<Point> pts1 = pts; | ||||||
|                 // TODO here we assume layer height gap is constant. If not true, need to consider height jump
 |                 // TODO here we assume layer height gap is constant. If not true, need to consider height jump
 | ||||||
|                 // TODO it seems the smooth iterations can't be larger than 1, otherwise some nodes will fly away
 |                 const int iterations = 100; | ||||||
|                 for (size_t k = 0; k < 50; k++) { |                 for (size_t k = 0; k < iterations; k++) { | ||||||
|                     for (size_t i = 1; i < pts.size() - 1; i++) { |                     for (size_t i = 1; i < pts.size() - 1; i++) { | ||||||
|                         size_t   i2 = i >= 2 ? i - 2 : 0; |                         size_t   i2 = i >= 2 ? i - 2 : 0; | ||||||
|                         size_t   i3 = i < pts.size() - 2 ? i + 2 : pts.size() - 1; |                         size_t   i3 = i < pts.size() - 2 ? i + 2 : pts.size() - 1; | ||||||
|                         Point pt  = (pts[i2] + pts[i - 1] + pts[i] + pts[i + 1] + pts[i3]) / 5; |                         Point pt  = (pts[i2] + pts[i - 1] + pts[i] + pts[i + 1] + pts[i3]) / 5; | ||||||
|                         pts1[i] = pt; |                         pts1[i] = pt; | ||||||
|  |                         if (k == iterations - 1) { | ||||||
|  |                             branch[i]->position = pt; | ||||||
|  |                             branch[i]->movement = (pts[i + 1] - pts[i - 1]) / 2; | ||||||
|  |                             branch[i]->is_processed = true; | ||||||
|  |                         } | ||||||
|                     } |                     } | ||||||
|                     std::swap(pts, pts1); |                     if (k < iterations - 1) | ||||||
|                 } |                         std::swap(pts, pts1); | ||||||
|                 for (size_t i = 1; i < pts.size() - 1; i++) { |  | ||||||
|                     if (!is_processed[branch[i]]) { |  | ||||||
|                         branch[i]->position = pts[i];  |  | ||||||
|                         branch[i]->movement     = branch[i]->parent ? (branch[i]->position - branch[i]->parent->position) : Point(0, 0); |  | ||||||
|                         is_processed[branch[i]] = true; |  | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | #if SUPPORT_TREE_DEBUG_TO_SVG | ||||||
|  |     // save tree structure for viewing in python
 | ||||||
|  |     struct TreeNode { | ||||||
|  |         Vec3f pos; | ||||||
|  |         std::vector<int> children;  // index of children in the storing vector
 | ||||||
|  |         TreeNode(Point pt, float z) { | ||||||
|  |             pos = { float(unscale_(pt.x())),float(unscale_(pt.y())),z }; | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |     std::vector<TreeNode> tree_nodes; | ||||||
|  |     std::map<Node*, int> ptr2idx; | ||||||
|  |     std::map<int, Node*> idx2ptr; | ||||||
|  |     for (int layer_nr = 0; layer_nr < contact_nodes.size(); layer_nr++) { | ||||||
|  |         std::vector<Node*>& curr_layer_nodes = contact_nodes[layer_nr]; | ||||||
|  |         for (Node* node : curr_layer_nodes) { | ||||||
|  |             ptr2idx.emplace(node, tree_nodes.size()); | ||||||
|  |             idx2ptr.emplace(tree_nodes.size(), node); | ||||||
|  |             tree_nodes.emplace_back(node->position, node->print_z); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     for (size_t i = 0; i < tree_nodes.size(); i++) { | ||||||
|  |         TreeNode& tree_node = tree_nodes[i]; | ||||||
|  |         Node* p_node = idx2ptr[i]; | ||||||
|  |         if (p_node->child) | ||||||
|  |             tree_node.children.push_back(ptr2idx[p_node->child]); | ||||||
|  |     } | ||||||
|  |     nlohmann::json jj; | ||||||
|  |     for (size_t i = 0; i < tree_nodes.size(); i++) { | ||||||
|  |         nlohmann::json j; | ||||||
|  |         j["pos"] = tree_nodes[i].pos; | ||||||
|  |         j["children"] = tree_nodes[i].children; | ||||||
|  |         jj.push_back(j); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     std::ofstream ofs("tree_nodes.json"); | ||||||
|  |     ofs << jj.dump(); | ||||||
|  |     ofs.close(); | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void TreeSupport::adjust_layer_heights(std::vector<std::vector<Node*>>& contact_nodes) | void TreeSupport::adjust_layer_heights(std::vector<std::vector<Node*>>& contact_nodes) | ||||||
|  |  | ||||||
|  | @ -259,6 +259,8 @@ public: | ||||||
|                 if (dist_mm_to_top==0) |                 if (dist_mm_to_top==0) | ||||||
|                     dist_mm_to_top = parent->dist_mm_to_top + parent->height; |                     dist_mm_to_top = parent->dist_mm_to_top + parent->height; | ||||||
|                 parent->child = this; |                 parent->child = this; | ||||||
|  |                 for (auto& neighbor : parent->merged_neighbours) | ||||||
|  |                     neighbor->child = this; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -280,15 +282,15 @@ public: | ||||||
|         /*!
 |         /*!
 | ||||||
|          * \brief The position of this node on the layer. |          * \brief The position of this node on the layer. | ||||||
|          */ |          */ | ||||||
|         Point position; |         Point            position; | ||||||
| 
 |         Point            movement; // movement towards neighbor center or outline
 | ||||||
|         Point movement;  // movement towards neighbor center or outline
 |         mutable double   radius        = 0.0; | ||||||
|         mutable double radius   = 0.0; |         mutable double   max_move_dist = 0.0; | ||||||
|         mutable double max_move_dist = 0.0; |         NodeType         type          = eCircle; | ||||||
|         NodeType type = eCircle; |         bool             is_merged     = false; // this node is generated by merging upper nodes
 | ||||||
|         bool             is_merged     = false;   // this node is generated by merging upper nodes
 |  | ||||||
|         bool             is_corner     = false; |         bool             is_corner     = false; | ||||||
|         const ExPolygon* overhang = nullptr;  // when type==ePolygon, set this value to get original overhang area
 |         bool             is_processed  = false; | ||||||
|  |         const ExPolygon *overhang      = nullptr; // when type==ePolygon, set this value to get original overhang area
 | ||||||
| 
 | 
 | ||||||
|         /*!
 |         /*!
 | ||||||
|          * \brief The direction of the skin lines above the tip of the branch. |          * \brief The direction of the skin lines above the tip of the branch. | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Arthur
						Arthur