From 3cfb49a1b9dc2c76066ec441f1028f99a4bf99c4 Mon Sep 17 00:00:00 2001 From: "xun.zhang" Date: Mon, 30 Sep 2024 16:30:34 +0800 Subject: [PATCH] ENH: refine filament group algorithm 1.Use max flow network to handle limit 2.Support setting master extruder id 3.Fix the issue in the KMedoids algorithm where data is overwritten after each retry. jira:NONE Signed-off-by: xun.zhang Change-Id: Idd2bedf39f61e7a65eb4199852f60b8fbebe0a7d --- src/libslic3r/FilamentGroup.cpp | 112 ++++++++++++++--- src/libslic3r/FilamentGroup.hpp | 40 ++++--- src/libslic3r/GCode/ToolOrderUtils.cpp | 160 ++++++++++++++++++++++--- src/libslic3r/GCode/ToolOrderUtils.hpp | 46 ++++++- src/libslic3r/GCode/ToolOrdering.cpp | 47 +++++--- src/libslic3r/GCode/ToolOrdering.hpp | 4 +- src/libslic3r/Print.cpp | 3 +- src/libslic3r/PrintConfig.cpp | 5 + src/libslic3r/PrintConfig.hpp | 1 + 9 files changed, 345 insertions(+), 73 deletions(-) diff --git a/src/libslic3r/FilamentGroup.cpp b/src/libslic3r/FilamentGroup.cpp index af5ee6de5..55f1ebc34 100644 --- a/src/libslic3r/FilamentGroup.cpp +++ b/src/libslic3r/FilamentGroup.cpp @@ -99,6 +99,84 @@ namespace Slic3r a = hexToByte(hexstr.substr(7, 2)); } + bool can_swap_groups(const int extruder_id_0, const std::set& group_0, const int extruder_id_1, const std::set& group_1, const FilamentGroupContext& ctx) + { + std::vector>extruder_unprintables(2); + { + std::vector> physical_unprintables = ctx.physical_unprintables; + std::vector> geometric_unprintables = ctx.geometric_unprintables; + remove_intersection(physical_unprintables[0], physical_unprintables[1]); + remove_intersection(geometric_unprintables[0], geometric_unprintables[1]); + std::map>unplaceable_limts; + for (auto& unprintables : { physical_unprintables,geometric_unprintables }) { + for (auto& group_id : { extruder_id_0,extruder_id_1 }) { + for (auto f : unprintables[group_id]) { + // TODO: xcr: check whether group_id has been inside the vector ? + if (unplaceable_limts.count(f) == 0) + unplaceable_limts[f].emplace_back(group_id); + } + } + } + + for (auto& elem : unplaceable_limts) { + sort_remove_duplicates(elem.second); + } + + for (auto& elem : unplaceable_limts) { + for (auto& eid : elem.second) { + if (eid == extruder_id_0) { + extruder_unprintables[0].insert(elem.first); + } + if (eid == extruder_id_1) { + extruder_unprintables[1].insert(elem.first); + } + } + } + } + + // check printable limits + for (auto fid : group_0) { + if (extruder_unprintables[1].count(fid) > 0) + return false; + } + + for (auto fid : group_1) { + if (extruder_unprintables[0].count(fid) > 0) + return false; + } + + // check extruder capacity ,if result before exchange meets the constraints and the result after exchange does not meet the constraints, return false + if (ctx.max_group_size[extruder_id_0] >= group_0.size() && ctx.max_group_size[extruder_id_1] >= group_1.size() && (ctx.max_group_size[extruder_id_0] < group_1.size() || ctx.max_group_size[extruder_id_1] < group_0.size())) + return false; + + return true; + } + + + // only support extruder nums with 2, try to swap the master extruder id with the other extruder id + bool optimize_group_for_master_extruder(const std::vector& used_filaments,const FilamentGroupContext& ctx, std::vector& filament_map) + { + std::unordered_map> groups; + for (size_t idx = 0; idx < used_filaments.size(); ++idx) { + int filament_id = used_filaments[idx]; + int group_id = filament_map[filament_id]; + groups[group_id].insert(filament_id); + } + + int none_master_extruder_id = 1 - ctx.master_extruder_id; + assert(0 <= none_master_extruder_id && none_master_extruder_id <= 1); + + if (can_swap_groups(none_master_extruder_id, groups[none_master_extruder_id], ctx.master_extruder_id, groups[ctx.master_extruder_id], ctx) + && groups[none_master_extruder_id].size()>groups[ctx.master_extruder_id].size()) { + for (auto fid : groups[none_master_extruder_id]) + filament_map[fid] = ctx.master_extruder_id; + for (auto fid : groups[ctx.master_extruder_id]) + filament_map[fid] = none_master_extruder_id; + return true; + } + return false; + } + std::vector select_best_group_for_ams(const std::vector>& map_lists, const std::vector& used_filaments, const std::vector& used_filament_colors_str, const std::vector>& ams_filament_colors_str) { // change the color str to real colors @@ -142,7 +220,7 @@ namespace Slic3r std::vectorl_nodes(group_colors[i].size()), r_nodes(ams_filament_colors[i].size()); std::iota(l_nodes.begin(), l_nodes.end(), 0); std::iota(r_nodes.begin(), r_nodes.end(), 0); - MCMF mcmf(distance_matrix, l_nodes, r_nodes); + MinCostMaxFlow mcmf(distance_matrix, l_nodes, r_nodes); auto ams_map = mcmf.solve(); for (size_t idx = 0; idx < ams_map.size(); ++idx) { @@ -290,7 +368,7 @@ namespace Slic3r new_group_size[gid] -= 1; } else { - label = 0; + label = m_default_group_id; } } } @@ -377,6 +455,15 @@ namespace Slic3r if (m_elem_count < m_k) { m_cluster_labels = cluster_small_data(m_unplaceable_limits, m_max_cluster_size); + { + std::vectorcluster_center(m_k, -1); + for (size_t idx = 0; idx < m_cluster_labels.size(); ++idx) { + if (cluster_center[m_cluster_labels[idx]] == -1) + cluster_center[m_cluster_labels[idx]] = idx; + } + MemoryedGroup g(m_cluster_labels, calc_cost(m_cluster_labels, cluster_center), 1); + update_memoryed_groups(g, memory_threshold, memoryed_groups); + } return; } @@ -402,10 +489,7 @@ namespace Slic3r } { - MemoryedGroup g; - g.prefer_level = 1; // in non enum mode, we use the same prefer level - g.cost = new_cost; - g.group = new_labels; + MemoryedGroup g(new_labels,new_cost,1); update_memoryed_groups(g, memory_threshold, memoryed_groups); } @@ -433,10 +517,11 @@ namespace Slic3r std::vector used_filaments = collect_sorted_used_filaments(layer_filaments); int used_filament_num = used_filaments.size(); + if (used_filament_num < 10) return calc_filament_group_by_enum(layer_filaments, used_filaments, g_strategy, cost); else - return calc_filament_group_by_pam2(layer_filaments, used_filaments, g_strategy, cost, 100); + return calc_filament_group_by_pam2(layer_filaments, used_filaments, g_strategy, cost, 300); } // sorted used_filaments @@ -529,10 +614,7 @@ namespace Slic3r } { - MemoryedGroup mg; - mg.prefer_level = prefer_level; - mg.cost = total_cost; - mg.group = std::move(filament_maps); + MemoryedGroup mg(filament_maps,total_cost,prefer_level); update_memoryed_groups(mg, memory_threshold, memoryed_groups); } } @@ -553,9 +635,7 @@ namespace Slic3r // sorted used_filaments std::vector FilamentGroup::calc_filament_group_by_pam2(const std::vector>& layer_filaments, const std::vector& used_filaments, const FGStrategy& g_strategy, int*cost,int timeout_ms) { - std::vectorfilament_labels_ret(m_context.total_filament_num, 0); - if (used_filaments.size() == 1) - return filament_labels_ret; + std::vectorfilament_labels_ret(m_context.total_filament_num, m_context.master_extruder_id); std::mapunplaceable_limits; { @@ -575,13 +655,13 @@ namespace Slic3r } auto distance_evaluator = std::make_shared(m_context.flush_matrix[0], used_filaments, layer_filaments); - KMediods2 PAM((int)used_filaments.size(),distance_evaluator); + KMediods2 PAM((int)used_filaments.size(),distance_evaluator,m_context.master_extruder_id); PAM.set_max_cluster_size(m_context.max_group_size); PAM.set_unplaceable_limits(unplaceable_limits); PAM.set_memory_threshold(memory_threshold); PAM.do_clustering(g_strategy, timeout_ms); - std::vectorfilament_labels = PAM.get_cluster_labels(); + std::vectorfilament_labels = PAM.get_cluster_labels(); { auto memoryed_groups = PAM.get_memoryed_groups(); diff --git a/src/libslic3r/FilamentGroup.hpp b/src/libslic3r/FilamentGroup.hpp index 0d20b8064..024c777b4 100644 --- a/src/libslic3r/FilamentGroup.hpp +++ b/src/libslic3r/FilamentGroup.hpp @@ -33,8 +33,6 @@ namespace Slic3r Color(const std::string& hexstr); }; - std::vector select_best_group_for_ams(const std::vector>& map_lists, const std::vector& used_filaments, const std::vector& used_filament_colors, const std::vector>& ams_filament_colros); - namespace FilamentGroupUtils { struct FlushTimeMachine @@ -57,12 +55,15 @@ namespace Slic3r }; struct MemoryedGroup { - int cost{ 0 }; - int prefer_level{ 0 }; - std::vectorgroup; + MemoryedGroup() = default; + MemoryedGroup(const std::vector& group_, const int cost_, const int prefer_level_) :group(group_), cost(cost_), prefer_level(prefer_level_) {} bool operator>(const MemoryedGroup& other) const { return prefer_level < other.prefer_level || (prefer_level == other.prefer_level && cost > other.cost); } + + int cost{ 0 }; + int prefer_level{ 0 }; + std::vectorgroup; }; using MemoryedGroupHeap = std::priority_queue, std::greater>; @@ -76,8 +77,14 @@ namespace Slic3r std::vector>geometric_unprintables; std::vectormax_group_size; int total_filament_num; + int master_extruder_id; }; + std::vector select_best_group_for_ams(const std::vector>& map_lists, const std::vector& used_filaments, const std::vector& used_filament_colors, const std::vector>& ams_filament_colros); + + bool optimize_group_for_master_extruder(const std::vector& used_filaments, const FilamentGroupContext& ctx, std::vector& filament_map); + + bool can_swap_groups(const int extruder_id_0, const std::set& group_0, const int extruder_id_1, const std::set& group_1, const FilamentGroupContext& ctx); class FlushDistanceEvaluator { @@ -123,9 +130,10 @@ namespace Slic3r Farthest }; public: - KMediods2(const int elem_count, const std::shared_ptr& evaluator) : + KMediods2(const int elem_count, const std::shared_ptr& evaluator, int default_group_id = 0) : m_evaluator{ evaluator }, - m_elem_count{ elem_count } + m_elem_count{ elem_count }, + m_default_group_id{ default_group_id } { m_max_cluster_size = std::vector(m_k, DEFAULT_CLUSTER_SIZE); } @@ -138,7 +146,7 @@ namespace Slic3r void do_clustering(const FGStrategy& g_strategy,int timeout_ms = 100); - void set_memory_threshold(double threshold) { memory_threshold; } + void set_memory_threshold(double threshold) { memory_threshold = threshold; } MemoryedGroupHeap get_memoryed_groups()const { return memoryed_groups; } std::vectorget_cluster_labels()const { return m_cluster_labels; } @@ -147,17 +155,17 @@ namespace Slic3r std::vectorcluster_small_data(const std::map& unplaceable_limits, const std::vector& group_size); std::vectorassign_cluster_label(const std::vector& center, const std::map& unplaceable_limits, const std::vector& group_size, const FGStrategy& strategy); int calc_cost(const std::vector& labels, const std::vector& medoids); - private: + protected: + FilamentGroupUtils::MemoryedGroupHeap memoryed_groups; std::shared_ptr m_evaluator; std::mapm_unplaceable_limits; - std::vectorm_max_cluster_size; - int m_elem_count; - const int m_k = 2; - - double memory_threshold{ 0 }; - FilamentGroupUtils::MemoryedGroupHeap memoryed_groups; - std::vectorm_cluster_labels; + std::vectorm_max_cluster_size; + + const int m_k = 2; + int m_elem_count; + int m_default_group_id{ 0 }; + double memory_threshold{ 0 }; }; } #endif // !FILAMENT_GROUP_HPP diff --git a/src/libslic3r/GCode/ToolOrderUtils.cpp b/src/libslic3r/GCode/ToolOrderUtils.cpp index 6e44d59d3..5b65a3c85 100644 --- a/src/libslic3r/GCode/ToolOrderUtils.cpp +++ b/src/libslic3r/GCode/ToolOrderUtils.cpp @@ -8,8 +8,123 @@ namespace Slic3r { - MCMF::MCMF(const FlushMatrix& matrix_, const std::vector& u_nodes, const std::vector& v_nodes) + MaxFlow::MaxFlow(const std::vector& u_nodes, const std::vector& v_nodes, + const std::unordered_map>& uv_link_limits, + const std::unordered_map>& uv_unlink_limits, + const std::vector& u_capacity, + const std::vector& v_capacity) { + assert(u_capacity.empty() || u_capacity.size() == u_nodes.size()); + assert(v_capacity.empty() || v_capacity.size() == v_nodes.size()); + l_nodes = u_nodes; + r_nodes = v_nodes; + total_nodes = u_nodes.size() + v_nodes.size() + 2; + source_id = total_nodes - 2; + sink_id = total_nodes - 1; + + adj.resize(total_nodes); + + // add edge from source to left nodes + for (int idx = 0; idx < l_nodes.size(); ++idx) { + int capacity = u_capacity.empty() ? 1 : u_capacity[idx]; + add_edge(source_id, idx, capacity); + } + // add edge from right nodes to sink node + for (int idx = 0; idx < r_nodes.size(); ++idx) { + int capacity = v_capacity.empty() ? 1 : v_capacity[idx]; + add_edge(l_nodes.size() + idx, sink_id, capacity); + } + + // add edge from left nodes to right nodes + for (int i = 0; i < l_nodes.size(); ++i) { + int from_idx = i; + // process link limits , i can only link to uv_link_limits + if (auto iter = uv_link_limits.find(i); iter != uv_link_limits.end()) { + for (auto r_id : iter->second) + add_edge(from_idx, l_nodes.size() + r_id, 1); + continue; + } + // process unlink limits + std::optional> unlink_limits; + if (auto iter = uv_unlink_limits.find(i); iter != uv_unlink_limits.end()) + unlink_limits = iter->second; + + for (int j = 0; j < r_nodes.size(); ++j) { + // check whether i can link to j + if (unlink_limits.has_value() && std::find(unlink_limits->begin(), unlink_limits->end(), j) != unlink_limits->end()) + continue; + add_edge(from_idx, l_nodes.size() + j, 1); + } + } + } + + void MaxFlow::add_edge(int from, int to, int capacity) + { + adj[from].emplace_back(edges.size()); + edges.emplace_back(from, to, capacity); + //also add reverse edge ,set capacity to zero + adj[to].emplace_back(edges.size()); + edges.emplace_back(to, from, 0); + } + + std::vector MaxFlow::solve() { + std::vector augment; + std::vector previous(total_nodes, 0); + while (1) { + std::vector(total_nodes, 0).swap(augment); + std::queue travel; + travel.push(source_id); + augment[source_id] = INF; + while (!travel.empty()) { + int from = travel.front(); + travel.pop(); + + // traverse all linked edges + for (int i = 0; i < adj[from].size(); ++i) { + int eid = adj[from][i]; + Edge& tmp = edges[eid]; + if (augment[tmp.to] == 0 && tmp.capacity > tmp.flow) { + previous[tmp.to] = eid; + augment[tmp.to] = std::min(augment[from], tmp.capacity - tmp.flow); + travel.push(tmp.to); + } + } + + // already find an extend path, stop and do update + if (augment[sink_id] != 0) + break; + } + // no longer have extend path + if (augment[sink_id] == 0) + break; + + for (int i = sink_id; i != source_id; i = edges[previous[i]].from) { + edges[previous[i]].flow += augment[sink_id]; + edges[previous[i] ^ 1].flow -= augment[sink_id]; + } + } + + std::vector matching(l_nodes.size(), -1); + // to get the match info, just traverse the left nodes and + // check the edge with flow > 0 and linked to right nodes + for (int u = 0; u < l_nodes.size(); ++u) { + for (int eid : adj[u]) { + Edge& e = edges[eid]; + if (e.flow > 0 && e.to >= l_nodes.size() && e.to < l_nodes.size() + r_nodes.size()) + matching[e.from] = r_nodes[e.to - l_nodes.size()]; + } + } + return matching; + } + + MinCostMaxFlow::MinCostMaxFlow(const std::vector>& matrix_, const std::vector& u_nodes, const std::vector& v_nodes, + const std::unordered_map>& uv_link_limits, + const std::unordered_map>& uv_unlink_limits, + const std::vector& u_capacity, + const std::vector& v_capacity) + { + assert(u_capacity.empty() || u_capacity.size() == u_nodes.size()); + assert(v_capacity.empty() || v_capacity.size() == v_nodes.size()); matrix = matrix_; l_nodes = u_nodes; r_nodes = v_nodes; @@ -21,24 +136,39 @@ namespace Slic3r adj.resize(total_nodes); - //add edge from source to left nodes,set capacity to 1, cost to 0 - for (int i = 0; i < l_nodes.size(); ++i) - add_edge(source_id, i, 1, 0); - - //add edge from right nodes to sink,set capacity to 1, cost to 0 - for (int i = 0; i < r_nodes.size(); ++i) - add_edge(l_nodes.size() + i, sink_id, 1, 0); - + // add edge from source to left nodes,cost to 0 + for (int i = 0; i < l_nodes.size(); ++i) { + int capacity = u_capacity.empty() ? 1 : u_capacity[i]; + add_edge(source_id, i, capacity, 0); + } + // add edge from right nodes to sink,cost to 0 + for (int i = 0; i < r_nodes.size(); ++i) { + int capacity = v_capacity.empty() ? 1 : v_capacity[i]; + add_edge(l_nodes.size() + i, sink_id, capacity, 0); + } + // add edge from left node to right nodes for (int i = 0; i < l_nodes.size(); ++i) { int from_idx = i; + // process link limits, i can only link to link_limits + if (auto iter = uv_link_limits.find(i); iter != uv_link_limits.end()) { + for (auto r_id : iter->second) + add_edge(from_idx, l_nodes.size() + r_id, 1, get_distance(i, r_id)); + continue; + } + + // process unlink limits, check whether i can link to j + std::optional> unlink_limits; + if (auto iter = uv_unlink_limits.find(i); iter != uv_unlink_limits.end()) + unlink_limits = iter->second; for (int j = 0; j < r_nodes.size(); ++j) { - int to_idx = l_nodes.size() + j; - add_edge(from_idx, to_idx, 1, get_distance(i, j)); + if (unlink_limits.has_value() && std::find(unlink_limits->begin(), unlink_limits->end(), j) != unlink_limits->end()) + continue; + add_edge(from_idx, l_nodes.size() + j, 1, get_distance(i, j)); } } } - std::vector MCMF::solve() + std::vector MinCostMaxFlow::solve() { while (spfa(source_id, sink_id)); @@ -56,7 +186,7 @@ namespace Slic3r return matching; } - void MCMF::add_edge(int from, int to, int capacity, int cost) + void MinCostMaxFlow::add_edge(int from, int to, int capacity, int cost) { adj[from].emplace_back(edges.size()); edges.emplace_back(from, to, capacity, cost); @@ -65,7 +195,7 @@ namespace Slic3r edges.emplace_back(to, from, 0, -cost); } - bool MCMF::spfa(int source, int sink) + bool MinCostMaxFlow::spfa(int source, int sink) { std::vectordist(total_nodes, INF); std::vectorin_queue(total_nodes, false); @@ -111,7 +241,7 @@ namespace Slic3r return true; } - int MCMF::get_distance(int idx_in_left, int idx_in_right) + int MinCostMaxFlow::get_distance(int idx_in_left, int idx_in_right) { if (l_nodes[idx_in_left] == -1) { return 0; diff --git a/src/libslic3r/GCode/ToolOrderUtils.hpp b/src/libslic3r/GCode/ToolOrderUtils.hpp index 4cc14e1b1..d66d03e4e 100644 --- a/src/libslic3r/GCode/ToolOrderUtils.hpp +++ b/src/libslic3r/GCode/ToolOrderUtils.hpp @@ -9,7 +9,37 @@ namespace Slic3r { using FlushMatrix = std::vector>; -class MCMF +class MaxFlow +{ +private: + const int INF = std::numeric_limits::max(); + struct Edge { + int from, to, capacity, flow; + Edge(int u, int v, int cap) :from(u), to(v), capacity(cap), flow(0) {} + }; +public: + MaxFlow(const std::vector& u_nodes, const std::vector& v_nodes, + const std::unordered_map>& uv_link_limits = {}, + const std::unordered_map>& uv_unlink_limits = {}, + const std::vector& u_capacity = {}, + const std::vector& v_capacity = {} + ); + std::vector solve(); + +private: + void add_edge(int from, int to, int capacity); + + + int total_nodes; + int source_id; + int sink_id; + std::vectoredges; + std::vectorl_nodes; + std::vectorr_nodes; + std::vector>adj; +}; + +class MinCostMaxFlow { const int INF = std::numeric_limits::max(); struct Edge @@ -19,7 +49,12 @@ class MCMF }; public: - MCMF(const FlushMatrix &matrix_, const std::vector &u_nodes, const std::vector &v_nodes); + MinCostMaxFlow(const std::vector>& matrix_, const std::vector& u_nodes, const std::vector& v_nodes, + const std::unordered_map>& uv_link_limits = {}, + const std::unordered_map>& uv_unlink_limits = {}, + const std::vector& u_capacity = {}, + const std::vector& v_capacity = {} + ); std::vector solve(); private: @@ -28,16 +63,15 @@ private: int get_distance(int idx_in_left, int idx_in_right); private: - FlushMatrix matrix; + std::vector> matrix; std::vector l_nodes; std::vector r_nodes; + std::vector edges; + std::vector> adj; int total_nodes; int source_id; int sink_id; - - std::vector edges; - std::vector> adj; }; std::vector get_extruders_order(const std::vector> &wipe_volumes, diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index aa17c21e9..027acd8ae 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -35,8 +35,10 @@ static std::setget_filament_by_type(const std::vector& used_f return target_filaments; } -std::vector> ToolOrdering::get_physical_unprintables(const std::vector& used_filaments, const PrintConfig* config, int master_extruder_id) +std::vector> ToolOrdering::get_physical_unprintables(const std::vector& used_filaments, const PrintConfig* config) { + // master saved in config is 1 based,so we should transfer to 0 based here + int master_extruder_id = config->master_extruder_id.value - 1; auto tpu_filaments = get_filament_by_type(used_filaments, config, "TPU"); if (tpu_filaments.size() > 1) { throw Slic3r::RuntimeError(std::string("Only supports up to one TPU filament.")); @@ -528,9 +530,10 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto } } -bool ToolOrdering::check_tpu_group(const std::vector&used_filaments,const std::vector& filament_maps,const PrintConfig* config,int master_extruder_id) +bool ToolOrdering::check_tpu_group(const std::vector&used_filaments,const std::vector& filament_maps,const PrintConfig* config) { int check_extruder_id = -1; + int master_extruder_id = config->master_extruder_id.value - 1; // transfer to 0 based idx std::map> extruder_filament_nums; for (unsigned int filament_id : used_filaments) { int extruder_id = filament_maps[filament_id]; @@ -547,7 +550,7 @@ bool ToolOrdering::check_tpu_group(const std::vector&used_filament } // TPU can only place in master extruder, and it should have no other filaments in the same extruder - if (check_extruder_id != -1 && (check_extruder_id!=master_extruder_id || extruder_filament_nums[check_extruder_id].size() > 1)) { + if (check_extruder_id != -1 && (check_extruder_id != master_extruder_id || extruder_filament_nums[check_extruder_id].size() > 1)) { return false; } @@ -942,17 +945,21 @@ std::vector ToolOrdering::get_recommended_filament_maps(const std::vectorfirst * iter->second; } } + // When the AMS count is 0, only external filament can be used, so set the capacity to 1. + for(auto& size: group_size) + if(size == 0) + size = 1; } FilamentGroupContext context; - context.flush_matrix = std::move(nozzle_flush_mtx); - context.geometric_unprintables = geometric_unprintables; - context.physical_unprintables = physical_unprintables; - context.max_group_size = std::move(group_size); - context.total_filament_num = (int)filament_nums; - - // TODO: load master extruder id from config - int master_extruder_id = 1; + { + context.flush_matrix = std::move(nozzle_flush_mtx); + context.geometric_unprintables = geometric_unprintables; + context.physical_unprintables = physical_unprintables; + context.max_group_size = std::move(group_size); + context.total_filament_num = (int)filament_nums; + context.master_extruder_id = print_config->master_extruder_id.value - 1; // transfer to 0 based idx + } // speacially handle tpu filaments auto used_filaments = collect_sorted_used_filaments(layer_filaments); auto tpu_filaments = get_filament_by_type(used_filaments, print_config, "TPU"); @@ -960,9 +967,9 @@ std::vector ToolOrdering::get_recommended_filament_maps(const std::vector ToolOrdering::get_recommended_filament_maps(const std::vector>memoryed_maps{ ret }; + { + auto tmp_maps = fg.get_memoryed_groups(); + memoryed_maps.insert(memoryed_maps.end(), std::make_move_iterator(tmp_maps.begin()), std::make_move_iterator(tmp_maps.end())); + } std::vectorused_colors; for (size_t idx = 0; idx < used_filaments.size(); ++idx) @@ -1067,8 +1083,7 @@ void ToolOrdering::reorder_extruders_for_minimum_flush_volume(bool reorder_first } std::transform(filament_maps.begin(), filament_maps.end(), filament_maps.begin(), [](int value) { return value - 1; }); - // TODO: load the master extruder_id from config - if (!check_tpu_group(used_filaments, filament_maps, print_config, 1)) { + if (!check_tpu_group(used_filaments, filament_maps, print_config)) { if (map_mode == FilamentMapMode::fmmManual) { throw Slic3r::RuntimeError(std::string("Manual grouping error: TPU can only be placed in a nozzle alone.")); } diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index 76364ef3d..9c0f2224a 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -236,9 +236,9 @@ public: */ static std::vector get_recommended_filament_maps(const std::vector>& layer_filaments, const PrintConfig* print_config, const Print* print, const std::vector>& physical_unprintables, const std::vector>& geometric_unprintables); - static std::vector> get_physical_unprintables(const std::vector& layer_filaments, const PrintConfig* config, int master_extruder_id = 1); + static std::vector> get_physical_unprintables(const std::vector& layer_filaments, const PrintConfig* config); static std::vector> get_geometrical_unprintables(const std::vector>& unprintable_arrs, const PrintConfig* config); - static bool check_tpu_group(const std::vector&used_filaments,const std::vector& filament_maps,const PrintConfig* config,int master_extruder_id); + static bool check_tpu_group(const std::vector&used_filaments,const std::vector& filament_maps,const PrintConfig* config); // should be called after doing reorder FilamentChangeStats get_filament_change_stats(FilamentChangeMode mode); diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index af4718956..10953399d 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1885,8 +1885,7 @@ void Print::process(std::unordered_map* slice_time, bool } // check map valid both in auto and mannual mode std::transform(filament_maps.begin(), filament_maps.end(), filament_maps.begin(), [](int value) {return value - 1; }); - // TODO: load master extruder id from config - if (!ToolOrdering::check_tpu_group(used_filaments, filament_maps, &m_config, 1)) { + if (!ToolOrdering::check_tpu_group(used_filaments, filament_maps, &m_config)) { if (map_mode == FilamentMapMode::fmmManual) { throw Slic3r::RuntimeError(std::string("Manual grouping error: TPU can only be placed in a nozzle alone.")); } diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index ad4ceb282..0e4a4065b 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -3165,6 +3165,11 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionStrings { "Direct Drive Normal" }); def->cli = ConfigOptionDef::nocli; + def = this->add("master_extruder_id", coInt); + def->label = "Master extruder id"; + def->tooltip = "Default extruder id to place filament"; + def->set_default_value(new ConfigOptionInt{ 1 }); + def = this->add("print_extruder_id", coInts); def->label = "Print extruder id"; def->tooltip = "Print extruder id"; diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 7439c5d90..4e5aaeb58 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1040,6 +1040,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionEnumsGeneric, nozzle_volume_type)) ((ConfigOptionStrings, extruder_ams_count)) ((ConfigOptionInts, printer_extruder_id)) + ((ConfigOptionInt, master_extruder_id)) ((ConfigOptionStrings, printer_extruder_variant)) //Orca ((ConfigOptionBool, has_scarf_joint_seam))