mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	FIX: special model slice color is incorrect
Change-Id: I35eb51920e4d586354a98aac61aa4a806ea66464 (cherry picked from commit 7eae730907e25733968853a850762458bf0682ac)
This commit is contained in:
		
							parent
							
								
									d55cd76ebf
								
							
						
					
					
						commit
						fe3a1f724c
					
				
					 1 changed files with 152 additions and 49 deletions
				
			
		|  | @ -1100,8 +1100,12 @@ static MMU_Graph build_graph(size_t layer_idx, const std::vector<std::vector<Col | |||
|     return graph; | ||||
| } | ||||
| 
 | ||||
| static inline Polygon to_polygon(const std::vector<Linef> &lines) | ||||
| static inline Polygon to_polygon(const std::vector<std::pair<size_t, Linef>> &id_to_lines) | ||||
| { | ||||
|     std::vector<Linef> lines; | ||||
|     for (auto id_to_line : id_to_lines) | ||||
|         lines.emplace_back(id_to_line.second); | ||||
| 
 | ||||
|     Polygon poly_out; | ||||
|     poly_out.points.reserve(lines.size()); | ||||
|     for (const Linef &line : lines) | ||||
|  | @ -1109,6 +1113,112 @@ static inline Polygon to_polygon(const std::vector<Linef> &lines) | |||
|     return poly_out; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static std::vector<std::vector<const MMU_Graph::Arc *>> get_all_next_arcs( | ||||
|     const MMU_Graph &graph, | ||||
|     std::vector<bool> &used_arcs, | ||||
|     const Linef &process_line, | ||||
|     const MMU_Graph::Arc &original_arc, | ||||
|     const int color) | ||||
| { | ||||
|     std::vector<std::vector<const MMU_Graph::Arc *>> all_next_arcs; | ||||
|     for (const size_t &arc_idx : graph.nodes[original_arc.to_idx].arc_idxs) { | ||||
|         std::vector<const MMU_Graph::Arc *> next_continue_arc; | ||||
| 
 | ||||
|         const MMU_Graph::Arc &              arc = graph.arcs[arc_idx]; | ||||
|         if (graph.nodes[arc.to_idx].point == process_line.a || used_arcs[arc_idx]) | ||||
|             continue; | ||||
| 
 | ||||
|         if (original_arc.type == MMU_Graph::ARC_TYPE::BORDER && original_arc.color != color) | ||||
|             continue; | ||||
| 
 | ||||
|         if (arc.type == MMU_Graph::ARC_TYPE::BORDER && arc.color != color) | ||||
|             continue; | ||||
| 
 | ||||
|         Vec2d arc_line = graph.nodes[arc.to_idx].point - graph.nodes[arc.from_idx].point; | ||||
|         if (arc_line.norm() < 5) { // two points whose distance is less than 5 are considered as one point
 | ||||
|             Linef process_line_1(graph.nodes[arc.from_idx].point, graph.nodes[arc.to_idx].point); | ||||
|             std::vector<std::vector<const MMU_Graph::Arc *>> next_arcs = get_all_next_arcs(graph, used_arcs, process_line_1, arc, color); | ||||
|             if (next_arcs.empty()) | ||||
|                 continue; | ||||
| 
 | ||||
|             for (std::vector<const MMU_Graph::Arc *> &next_arc : next_arcs) { | ||||
|                 next_continue_arc.emplace_back(&arc); | ||||
|                 next_continue_arc.insert(next_continue_arc.end(), next_arc.begin(), next_arc.end()); | ||||
|                 all_next_arcs.emplace_back(next_continue_arc); | ||||
|             } | ||||
|         } else { | ||||
|             next_continue_arc.emplace_back(&arc); | ||||
|             all_next_arcs.emplace_back(next_continue_arc); | ||||
|         } | ||||
|     } | ||||
|     return all_next_arcs; | ||||
| } | ||||
| 
 | ||||
| // two points that are very close are considered as one point
 | ||||
| // std::vector contain the close points
 | ||||
| static std::vector<const MMU_Graph::Arc *> get_next_arc( | ||||
|     const MMU_Graph &graph, | ||||
|     std::vector<bool> &used_arcs, | ||||
|     const Linef &process_line, | ||||
|     const MMU_Graph::Arc &original_arc, | ||||
|     const int color) | ||||
| { | ||||
|     std::vector<const MMU_Graph::Arc *> res; | ||||
| 
 | ||||
|     std::vector<std::vector<const MMU_Graph::Arc *>> all_next_arcs = get_all_next_arcs(graph, used_arcs, process_line, original_arc, color); | ||||
|     if (all_next_arcs.empty()) { | ||||
|         res.emplace_back(&original_arc); | ||||
|         return res; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<std::pair<std::vector<const MMU_Graph::Arc *>, double>> sorted_arcs; | ||||
|     for (auto next_arc : all_next_arcs) { | ||||
|         if (next_arc.empty()) | ||||
|             continue; | ||||
| 
 | ||||
|         Vec2d process_line_vec_n   = (process_line.a - process_line.b).normalized(); | ||||
|         Vec2d neighbour_line_vec_n = (graph.nodes[next_arc.back()->to_idx].point - graph.nodes[next_arc.back()->from_idx].point).normalized(); | ||||
| 
 | ||||
|         double angle = ::acos(std::clamp(neighbour_line_vec_n.dot(process_line_vec_n), -1.0, 1.0)); | ||||
|         if (Slic3r::cross2(neighbour_line_vec_n, process_line_vec_n) < 0.0) | ||||
|             angle = 2.0 * (double) PI - angle; | ||||
| 
 | ||||
|         sorted_arcs.emplace_back(next_arc, angle); | ||||
|     } | ||||
| 
 | ||||
|     std::sort(sorted_arcs.begin(), sorted_arcs.end(), | ||||
|         [](std::pair<std::vector<const MMU_Graph::Arc *>, double> &l, std::pair<std::vector<const MMU_Graph::Arc *>, double> &r) -> bool { | ||||
|             return l.second < r.second; | ||||
|         }); | ||||
| 
 | ||||
|     // Try to return left most edge witch is unused
 | ||||
|     for (auto &sorted_arc : sorted_arcs) { | ||||
|         if (size_t arc_idx = sorted_arc.first.back() - &graph.arcs.front(); !used_arcs[arc_idx]) | ||||
|             return sorted_arc.first; | ||||
|     } | ||||
| 
 | ||||
|     if (sorted_arcs.empty()) { | ||||
|         res.emplace_back(&original_arc); | ||||
|         return res; | ||||
|     } | ||||
| 
 | ||||
|     return sorted_arcs.front().first; | ||||
| } | ||||
| 
 | ||||
| static bool is_profile_self_interaction(Polygon poly) | ||||
| { | ||||
|     auto lines = poly.lines(); | ||||
|     Point intersection; | ||||
|     for (int i = 0; i < lines.size(); ++i) { | ||||
|         for (int j = i + 2; j < std::min(lines.size(), lines.size() + i - 1); ++j) { | ||||
|             if (lines[i].intersection(lines[j], &intersection)) | ||||
|                 return true; | ||||
|         } | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| // Returns list of polygons and assigned colors.
 | ||||
| // It iterates through all nodes on the border between two different colors, and from this point,
 | ||||
| // start selection always left most edges for every node to construct CCW polygons.
 | ||||
|  | @ -1116,43 +1226,7 @@ static inline Polygon to_polygon(const std::vector<Linef> &lines) | |||
| static std::vector<ExPolygons> extract_colored_segments(const MMU_Graph &graph, const size_t num_extruders) | ||||
| { | ||||
|     std::vector<bool> used_arcs(graph.arcs.size(), false); | ||||
|     // When there is no next arc, then is returned original_arc or edge with is marked as used
 | ||||
|     auto get_next = [&graph, &used_arcs](const Linef &process_line, const MMU_Graph::Arc &original_arc, const int color) -> const MMU_Graph::Arc & { | ||||
|         std::vector<std::pair<const MMU_Graph::Arc *, double>> sorted_arcs; | ||||
|         for (const size_t &arc_idx : graph.nodes[original_arc.to_idx].arc_idxs) { | ||||
|             const MMU_Graph::Arc &arc = graph.arcs[arc_idx]; | ||||
|             if (graph.nodes[arc.to_idx].point == process_line.a || used_arcs[arc_idx]) | ||||
|                 continue; | ||||
| 
 | ||||
|             // BBS
 | ||||
|             if (original_arc.type == MMU_Graph::ARC_TYPE::BORDER && original_arc.color != color) | ||||
|                 continue; | ||||
| 
 | ||||
|             assert(original_arc.to_idx == arc.from_idx); | ||||
|             Vec2d process_line_vec_n   = (process_line.a - process_line.b).normalized(); | ||||
|             Vec2d neighbour_line_vec_n = (graph.nodes[arc.to_idx].point - graph.nodes[arc.from_idx].point).normalized(); | ||||
| 
 | ||||
|             double angle = ::acos(std::clamp(neighbour_line_vec_n.dot(process_line_vec_n), -1.0, 1.0)); | ||||
|             if (Slic3r::cross2(neighbour_line_vec_n, process_line_vec_n) < 0.0) | ||||
|                 angle = 2.0 * (double) PI - angle; | ||||
| 
 | ||||
|             sorted_arcs.emplace_back(&arc, angle); | ||||
|         } | ||||
| 
 | ||||
|         std::sort(sorted_arcs.begin(), sorted_arcs.end(), | ||||
|                   [](std::pair<const MMU_Graph::Arc *, double> &l, std::pair<const MMU_Graph::Arc *, double> &r) -> bool { return l.second < r.second; }); | ||||
| 
 | ||||
|         // Try to return left most edge witch is unused
 | ||||
|         for (auto &sorted_arc : sorted_arcs) | ||||
|             if (size_t arc_idx = sorted_arc.first - &graph.arcs.front(); !used_arcs[arc_idx]) | ||||
|                 return *sorted_arc.first; | ||||
| 
 | ||||
|         if (sorted_arcs.empty()) | ||||
|             return original_arc; | ||||
| 
 | ||||
|         return *(sorted_arcs.front().first); | ||||
|     }; | ||||
| 
 | ||||
|      | ||||
|     auto all_arc_used = [&used_arcs](const MMU_Graph::Node &node) -> bool { | ||||
|         return std::all_of(node.arc_idxs.cbegin(), node.arc_idxs.cend(), [&used_arcs](const size_t &arc_idx) -> bool { return used_arcs[arc_idx]; }); | ||||
|     }; | ||||
|  | @ -1166,29 +1240,58 @@ static std::vector<ExPolygons> extract_colored_segments(const MMU_Graph &graph, | |||
|             if (arc.type == MMU_Graph::ARC_TYPE::NON_BORDER || used_arcs[arc_idx]) | ||||
|                 continue; | ||||
| 
 | ||||
|             Linef process_line(node.point, graph.nodes[arc.to_idx].point); | ||||
|             Linef process_line(graph.nodes[arc.from_idx].point, graph.nodes[arc.to_idx].point); | ||||
|             used_arcs[arc_idx] = true; | ||||
| 
 | ||||
|             std::vector<Linef> face_lines; | ||||
|             face_lines.emplace_back(process_line); | ||||
|             std::vector<std::pair<size_t, Linef>> arc_id_to_face_lines; | ||||
|             arc_id_to_face_lines.emplace_back(std::make_pair(arc_idx, process_line)); | ||||
|             Vec2d start_p = process_line.a; | ||||
| 
 | ||||
|             Linef                 p_vec = process_line; | ||||
|             const MMU_Graph::Arc *p_arc = &arc; | ||||
|             bool                  flag  = false; | ||||
|             do { | ||||
|                 const MMU_Graph::Arc& next = get_next(p_vec, *p_arc, arc.color); | ||||
|                 size_t                next_arc_idx = &next - &graph.arcs.front(); | ||||
|                 face_lines.emplace_back(graph.nodes[next.from_idx].point, graph.nodes[next.to_idx].point); | ||||
|                 if (used_arcs[next_arc_idx]) | ||||
|                 std::vector<const MMU_Graph::Arc *> nexts = get_next_arc(graph, used_arcs, p_vec, *p_arc, arc.color); | ||||
|                 for (auto next : nexts) { | ||||
|                     size_t next_arc_idx = next - &graph.arcs.front(); | ||||
|                     if (used_arcs[next_arc_idx]) { | ||||
|                         flag = true; | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (flag) | ||||
|                     break; | ||||
| 
 | ||||
|                 used_arcs[next_arc_idx] = true; | ||||
|                 p_vec                   = Linef(graph.nodes[next.from_idx].point, graph.nodes[next.to_idx].point); | ||||
|                 p_arc                   = &next; | ||||
|                 for (auto next : nexts) { | ||||
|                     size_t next_arc_idx = next - &graph.arcs.front(); | ||||
|                     arc_id_to_face_lines.emplace_back(std::make_pair(next_arc_idx, Linef(graph.nodes[next->from_idx].point, graph.nodes[next->to_idx].point))); | ||||
|                     used_arcs[next_arc_idx] = true; | ||||
|                 } | ||||
| 
 | ||||
|                 p_vec = Linef(graph.nodes[nexts.back()->from_idx].point, graph.nodes[nexts.back()->to_idx].point); | ||||
|                 p_arc = nexts.back(); | ||||
| 
 | ||||
|             } while (graph.nodes[p_arc->to_idx].point != start_p || !all_arc_used(graph.nodes[p_arc->to_idx])); | ||||
| 
 | ||||
|             if (Polygon poly = to_polygon(face_lines); poly.is_counter_clockwise() && poly.is_valid()) | ||||
|             if (Polygon poly = to_polygon(arc_id_to_face_lines); poly.is_counter_clockwise() && poly.is_valid()) { | ||||
|                 expolygons_segments[arc.color].emplace_back(std::move(poly)); | ||||
|             } else{ | ||||
|                 while (arc_id_to_face_lines.size() > 1) | ||||
|                 { | ||||
|                     auto id_to_line = arc_id_to_face_lines.back(); | ||||
|                     used_arcs[id_to_line.first] = false; | ||||
|                     arc_id_to_face_lines.pop_back(); | ||||
|                     Linef add_line(arc_id_to_face_lines.back().second.b, arc_id_to_face_lines.front().second.a); | ||||
|                     arc_id_to_face_lines.emplace_back(std::make_pair(-1, add_line)); | ||||
|                     Polygon poly = to_polygon(arc_id_to_face_lines); | ||||
|                     if (!is_profile_self_interaction(poly) && poly.is_counter_clockwise() && poly.is_valid()) { | ||||
|                         expolygons_segments[arc.color].emplace_back(std::move(poly)); | ||||
|                         break; | ||||
|                     } | ||||
|                     arc_id_to_face_lines.pop_back(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     return expolygons_segments; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 zhimin.zeng
						zhimin.zeng