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