From 0f70c81a7d5686d8e80396f8f865f25b72618907 Mon Sep 17 00:00:00 2001 From: "xun.zhang" Date: Fri, 9 Aug 2024 14:14:23 +0800 Subject: [PATCH] ENH: optmize code structure of tool order 1.Put reorder functions in ToolOrderUtils jira:NONE Signed-off-by: xun.zhang Change-Id: I49c7b447ba1f41f3747ba3127d842c4e3957b5ff --- src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/FilamentGroup.cpp | 323 +++++++++++--------- src/libslic3r/FilamentGroup.hpp | 41 +-- src/libslic3r/GCode/ToolOrderUtils.cpp | 382 +++++++++++++++++++++++ src/libslic3r/GCode/ToolOrderUtils.hpp | 29 ++ src/libslic3r/GCode/ToolOrdering.cpp | 406 +------------------------ src/libslic3r/GCode/ToolOrdering.hpp | 7 - 7 files changed, 612 insertions(+), 578 deletions(-) create mode 100644 src/libslic3r/GCode/ToolOrderUtils.cpp create mode 100644 src/libslic3r/GCode/ToolOrderUtils.hpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 389a67a9a..9aba05c1c 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -430,6 +430,8 @@ set(lisbslic3r_sources FlushVolPredictor.cpp FilamentGroup.hpp FilamentGroup.cpp + GCode/ToolOrderUtils.hpp + GCode/ToolOrderUtils.cpp ) if (APPLE) diff --git a/src/libslic3r/FilamentGroup.cpp b/src/libslic3r/FilamentGroup.cpp index 0f10bb953..5e65883b9 100644 --- a/src/libslic3r/FilamentGroup.cpp +++ b/src/libslic3r/FilamentGroup.cpp @@ -1,146 +1,9 @@ #include "FilamentGroup.hpp" -#include "GCode/ToolOrdering.hpp" +#include "GCode/ToolOrderUtils.hpp" +#include namespace Slic3r { - int FilamentGroup::calc_filament_group(const std::vector>& layer_filaments,const FGStrategy& g_strategy) - { - std::setused_filaments; - for (const auto& lf : layer_filaments) - for (const auto& extruder : lf) - used_filaments.insert(extruder); - - m_filament_labels.resize(used_filaments.size()); - m_used_filaments = std::vector(used_filaments.begin(), used_filaments.end()); - std::sort(m_used_filaments.begin(), m_used_filaments.end()); - - if (m_filament_num <= 1) - return 0; - if (m_filament_num < 10) - return calc_filament_group_by_enum(layer_filaments,g_strategy); - else - return calc_filament_group_by_pam(layer_filaments,g_strategy,300); - - } - - int FilamentGroup::calc_filament_group_by_enum(const std::vector>& layer_filaments,const FGStrategy& g_strategy) - { - auto bit_count_one = [](uint64_t n) - { - int count = 0; - while (n != 0) - { - n &= n - 1; - count++; - } - return count; - }; - - bool have_enough_size = (m_filament_num <= (m_max_group_size[0] + m_max_group_size[1])); - - uint64_t max_group_num = static_cast(1 << m_filament_num); - int best_cost = std::numeric_limits::max(); - std::vectorbest_label; - - for (uint64_t i = 0; i < max_group_num; ++i) { - int num_to_group_1 = bit_count_one(i); - int num_to_group_0 = m_filament_num - num_to_group_1; - bool should_accept = false; - if (have_enough_size) - should_accept = (num_to_group_0 <= m_max_group_size[0] && num_to_group_1 <= m_max_group_size[1]); - else if (g_strategy == FGStrategy::BestCost) - should_accept = true; - else if (g_strategy == FGStrategy::BestFit) - should_accept = (num_to_group_0 >= m_max_group_size[0] && num_to_group_1 >= m_max_group_size[1]); - - if (!should_accept) - continue; - - std::setgroup_0, group_1; - for (int j = 0; j < m_filament_num; ++j) { - if (i & static_cast(1 << j)) - group_1.insert(m_used_filaments[j]); - else - group_0.insert(m_used_filaments[j]); - } - - std::vectorfilament_maps(m_filament_num); - for (int i = 0; i < m_filament_num; ++i) { - if (group_0.find(m_used_filaments[i]) != group_0.end()) - filament_maps[i] = 0; - if (group_1.find(m_used_filaments[i]) != group_1.end()) - filament_maps[i] = 1; - } - - int total_cost = reorder_filaments_for_minimum_flush_volume( - m_used_filaments, - filament_maps, - layer_filaments, - m_flush_matrix, - get_custom_seq, - nullptr - ); - - if (total_cost < best_cost) { - best_cost = total_cost; - best_label = filament_maps; - } - } - - m_filament_labels = best_label; - - return best_cost; - } - - int FilamentGroup::calc_filament_group_by_pam(const std::vector>& layer_filaments,const FGStrategy& g_strategy, int timeout_ms) - { - //calc pair counts - std::vector>count_matrix(m_filament_num,std::vector(m_filament_num)); - for (const auto& lf : layer_filaments) { - for (auto iter = lf.begin(); iter != lf.end(); ++iter) { - auto idx1 = std::find(m_used_filaments.begin(), m_used_filaments.end(), *iter)-m_used_filaments.begin(); - for (auto niter = std::next(iter); niter != lf.end(); ++niter) { - auto idx2 = std::find(m_used_filaments.begin(), m_used_filaments.end(), *niter) - m_used_filaments.begin(); - count_matrix[idx1][idx2] += 1; - count_matrix[idx2][idx1] += 1; - } - } - } - - //calc distance matrix - std::vector>distance_matrix(m_filament_num, std::vector(m_filament_num)); - for (size_t i = 0; i < m_used_filaments.size(); ++i) { - for (size_t j = 0; j < m_used_filaments.size(); ++j) { - if (i == j) - distance_matrix[i][j] = 0; - else { - //TODO: check m_flush_matrix - float max_val = std::max(m_flush_matrix[0][m_used_filaments[i]][m_used_filaments[j]], m_flush_matrix[0][m_used_filaments[j]][m_used_filaments[i]]); - float min_val = std::min(m_flush_matrix[0][m_used_filaments[i]][m_used_filaments[j]], m_flush_matrix[0][m_used_filaments[j]][m_used_filaments[i]]); - - double p = 0; - distance_matrix[i][j] = (max_val * p + min_val * (1 - p)) * count_matrix[i][j]; - } - } - } - - KMediods PAM(distance_matrix, m_filament_num,m_max_group_size); - PAM.fit(g_strategy,timeout_ms); - this->m_filament_labels = PAM.get_filament_labels(); - - int cost = reorder_filaments_for_minimum_flush_volume( - m_used_filaments, - this->m_filament_labels, - layer_filaments, - m_flush_matrix, - get_custom_seq, - nullptr - ); - - return cost; - } - - void KMediods::fit(const FGStrategy&g_strategy , int timeout_ms) { std::vectorbest_medoids; @@ -182,7 +45,6 @@ namespace Slic3r } } - if (cost < best_cost) { best_cost = cost; @@ -198,7 +60,7 @@ namespace Slic3r this->m_filament_labels = best_labels; } - std::vector KMediods::assign_label(const std::vector& medoids,const FGStrategy&g_strategy) const + std::vector KMediods::assign_label(const std::vector& medoids,const FGStrategy&g_strategy) { std::vectorlabels(m_filament_num); struct Comp { @@ -250,7 +112,7 @@ namespace Slic3r return labels; } - int KMediods::calc_cost(const std::vector& labels, const std::vector& medoids) const + int KMediods::calc_cost(const std::vector& labels, const std::vector& medoids) { int total_cost = 0; for (int i = 0; i < m_filament_num; ++i) @@ -258,22 +120,22 @@ namespace Slic3r return total_cost; } - std::vector KMediods::initialize(INIT_TYPE type) const + std::vector KMediods::initialize(INIT_TYPE type) { auto hash_func = [](int n1, int n2) { return n1 * 100 + n2; - }; + }; srand(time(nullptr)); std::vectorret; if (type == INIT_TYPE::Farthest) { //get the farthest items - int target_i=0,target_j=0,target_val=std::numeric_limits::min(); - for(int i=0;itarget_val){ - target_val=m_distance_matrix[i][j]; - target_i=i; - target_j=j; + int target_i = 0, target_j = 0, target_val = std::numeric_limits::min(); + for (int i = 0; i < m_distance_matrix.size(); ++i) { + for (int j = 0; j < m_distance_matrix[0].size(); ++j) { + if (i != j && m_distance_matrix[i][j] > target_val) { + target_val = m_distance_matrix[i][j]; + target_i = i; + target_j = j; } } } @@ -283,7 +145,7 @@ namespace Slic3r else if (type == INIT_TYPE::Random) { while (true) { std::vectormedoids; - while (medoids.size() < 2) + while (medoids.size() < k) { int candidate = rand() % m_filament_num; if (std::find(medoids.begin(), medoids.end(), candidate) == medoids.end()) @@ -302,6 +164,163 @@ namespace Slic3r m_medoids_set.insert(hash_func(ret[0],ret[1])); return ret; } + + + std::vector FilamentGroup::calc_filament_group(const std::vector>& layer_filaments, const FGStrategy& g_strategy,int* cost) + { + std::setused_filaments_set; + for (const auto& lf : layer_filaments) + for (const auto& extruder : lf) + used_filaments_set.insert(extruder); + + std::vectorused_filaments = std::vector(used_filaments_set.begin(), used_filaments_set.end()); + std::sort(used_filaments.begin(), used_filaments.end()); + + int used_filament_num = used_filaments.size(); + + std::vector filament_labels(m_total_filament_num, 0); + + if (used_filament_num <= 1) { + if (cost) + *cost = 0; + return filament_labels; + } + if (used_filament_num < 10) + return calc_filament_group_by_enum(layer_filaments, used_filaments, g_strategy, cost); + else + return calc_filament_group_by_pam(layer_filaments, used_filaments, g_strategy, cost, 100); + + } + + std::vector FilamentGroup::calc_filament_group_by_enum(const std::vector>& layer_filaments, const std::vector& used_filaments, const FGStrategy& g_strategy,int*cost) + { + auto bit_count_one = [](uint64_t n) + { + int count = 0; + while (n != 0) + { + n &= n - 1; + count++; + } + return count; + }; + + int used_filament_num = used_filaments.size(); + bool have_enough_size = (used_filament_num <= (m_max_group_size[0] + m_max_group_size[1])); + + uint64_t max_group_num = static_cast(1 << used_filament_num); + int best_cost = std::numeric_limits::max(); + std::vectorbest_label; + + for (uint64_t i = 0; i < max_group_num; ++i) { + int num_to_group_1 = bit_count_one(i); + int num_to_group_0 = used_filament_num - num_to_group_1; + bool should_accept = false; + if (have_enough_size) + should_accept = (num_to_group_0 <= m_max_group_size[0] && num_to_group_1 <= m_max_group_size[1]); + else if (g_strategy == FGStrategy::BestCost) + should_accept = true; + else if (g_strategy == FGStrategy::BestFit) + should_accept = (num_to_group_0 >= m_max_group_size[0] && num_to_group_1 >= m_max_group_size[1]); + + if (!should_accept) + continue; + + std::setgroup_0, group_1; + for (int j = 0; j < used_filament_num; ++j) { + if (i & static_cast(1 << j)) + group_1.insert(used_filaments[j]); + else + group_0.insert(used_filaments[j]); + } + + std::vectorfilament_maps(used_filament_num); + for (int i = 0; i < used_filament_num; ++i) { + if (group_0.find(used_filaments[i]) != group_0.end()) + filament_maps[i] = 0; + if (group_1.find(used_filaments[i]) != group_1.end()) + filament_maps[i] = 1; + } + + int total_cost = reorder_filaments_for_minimum_flush_volume( + used_filaments, + filament_maps, + layer_filaments, + m_flush_matrix, + get_custom_seq, + nullptr + ); + + if (total_cost < best_cost) { + best_cost = total_cost; + best_label = filament_maps; + } + } + + if (cost) + *cost = best_cost; + + std::vector filament_labels(m_total_filament_num, 0); + for (int i = 0; i < best_label.size(); ++i) + filament_labels[used_filaments[i]] = best_label[i]; + + return filament_labels; + } + + std::vector FilamentGroup::calc_filament_group_by_pam(const std::vector>& layer_filaments, const std::vector& used_filaments, const FGStrategy& g_strategy, int*cost,int timeout_ms) + { + std::vectorfilament_labels_ret(m_total_filament_num, 0); + int used_filament_num = used_filaments.size(); + if (used_filaments.size() == 1) + return filament_labels_ret; + //calc pair counts + std::vector>count_matrix(used_filament_num, std::vector(used_filament_num)); + for (const auto& lf : layer_filaments) { + for (auto iter = lf.begin(); iter != lf.end(); ++iter) { + auto id_iter1 = std::find(used_filaments.begin(), used_filaments.end(), *iter); + if (id_iter1 == used_filaments.end()) + continue; + auto idx1 = id_iter1 - used_filaments.begin(); + for (auto niter = std::next(iter); niter != lf.end(); ++niter) { + auto id_iter2 = std::find(used_filaments.begin(), used_filaments.end(), *niter); + if (id_iter2 == used_filaments.end()) + continue; + auto idx2 = id_iter2 - used_filaments.begin(); + count_matrix[idx1][idx2] += 1; + count_matrix[idx2][idx1] += 1; + } + } + } + + //calc distance matrix + std::vector>distance_matrix(used_filament_num, std::vector(used_filament_num)); + for (size_t i = 0; i < used_filaments.size(); ++i) { + for (size_t j = 0; j < used_filaments.size(); ++j) { + if (i == j) + distance_matrix[i][j] = 0; + else { + //TODO: check m_flush_matrix + float max_val = std::max(m_flush_matrix[0][used_filaments[i]][used_filaments[j]], m_flush_matrix[0][used_filaments[j]][used_filaments[i]]); + float min_val = std::min(m_flush_matrix[0][used_filaments[i]][used_filaments[j]], m_flush_matrix[0][used_filaments[j]][used_filaments[i]]); + + double p = 0.65; + distance_matrix[i][j] = (max_val * p + min_val * (1 - p)) * count_matrix[i][j]; + } + } + } + + KMediods PAM(distance_matrix, used_filament_num, m_max_group_size); + PAM.fit(g_strategy, timeout_ms); + std::vectorfilament_labels = PAM.get_filament_labels(); + + if(cost) + *cost=reorder_filaments_for_minimum_flush_volume(used_filaments,filament_labels,layer_filaments,m_flush_matrix,std::nullopt,nullptr); + + for (int i = 0; i < filament_labels.size(); ++i) + filament_labels_ret[used_filaments[i]] = filament_labels[i]; + return filament_labels_ret; + } + } diff --git a/src/libslic3r/FilamentGroup.hpp b/src/libslic3r/FilamentGroup.hpp index 37090347e..20e54b40d 100644 --- a/src/libslic3r/FilamentGroup.hpp +++ b/src/libslic3r/FilamentGroup.hpp @@ -2,11 +2,11 @@ #define FILAMENT_GROUP_HPP #include +#include +#include "GCode/ToolOrderUtils.hpp" namespace Slic3r { - using FlushMatrix = std::vector>; - struct FlushTimeMachine { private: @@ -34,31 +34,22 @@ namespace Slic3r class FilamentGroup { public: - - public: - FilamentGroup(const std::vector& flush_matrix, const int filament_num, const std::vector& max_group_size) : + FilamentGroup(const std::vector& flush_matrix, const int total_filament_num, const std::vector& max_group_size) : m_flush_matrix{ flush_matrix }, - m_filament_num{ filament_num }, + m_total_filament_num{ total_filament_num }, m_max_group_size{ max_group_size } {} - int calc_filament_group(const std::vector>& layer_filaments, const FGStrategy& g_strategy = FGStrategy::BestFit); - int calc_filament_group_by_enum(const std::vector>& layer_filaments,const FGStrategy& g_strategy); - int calc_filament_group_by_pam(const std::vector>& layer_filaments,const FGStrategy& g_strategy,int timeout_ms = 300); - - std::vector get_filament_map() const {return m_filament_labels;} - + std::vector calc_filament_group(const std::vector>& layer_filaments, const FGStrategy& g_strategy = FGStrategy::BestFit, int* cost = nullptr); + private: + std::vector calc_filament_group_by_enum(const std::vector>& layer_filaments, const std::vector& used_filaments, const FGStrategy& g_strategy, int* cost = nullptr); + std::vector calc_filament_group_by_pam(const std::vector>& layer_filaments, const std::vector& used_filaments, const FGStrategy& g_strategy, int* cost = nullptr, int timeout_ms = 300); private: std::vectorm_flush_matrix; - int m_filament_num; std::vectorm_max_group_size; - std::vectorm_used_filaments; + int m_total_filament_num; public: std::optional&)>> get_custom_seq; - private: - std::vectorm_filament_labels; - std::vector>m_filament_orders; - }; class KMediods @@ -69,10 +60,10 @@ namespace Slic3r Farthest }; public: - KMediods(const std::vector>& distance_matrix, const int filament_num, const std::vector& max_group_size) : + KMediods(const std::vector>& distance_matrix, const int filament_num,const std::vector& max_group_size) : m_distance_matrix{ distance_matrix }, m_filament_num{ filament_num }, - m_max_group_size{ max_group_size } {} + m_max_group_size{ max_group_size }{} void fit(const FGStrategy& g_strategy,int timeout_ms = 300); std::vectorget_filament_labels()const { @@ -80,15 +71,15 @@ namespace Slic3r } private: - std::vectorinitialize(INIT_TYPE type)const; - std::vectorassign_label(const std::vector& medoids,const FGStrategy&g_strategy)const; - int calc_cost(const std::vector& labels, const std::vector& medoids)const; + std::vectorinitialize(INIT_TYPE type); + std::vectorassign_label(const std::vector& medoids,const FGStrategy&g_strategy); + int calc_cost(const std::vector& labels, const std::vector& medoids); private: std::vector>m_distance_matrix; int m_filament_num; std::vectorm_max_group_size; - std::vectorm_used_filaments; - mutable std::setm_medoids_set; + std::setm_medoids_set; + const int k = 2; private: std::vectorm_filament_labels; }; diff --git a/src/libslic3r/GCode/ToolOrderUtils.cpp b/src/libslic3r/GCode/ToolOrderUtils.cpp new file mode 100644 index 000000000..aaee24e89 --- /dev/null +++ b/src/libslic3r/GCode/ToolOrderUtils.cpp @@ -0,0 +1,382 @@ +#include "ToolOrderUtils.hpp" +#include +#include +#include +#include +#include + +namespace Slic3r +{ + + //solve the problem by searching the least flush of current filament + static std::vector solve_extruder_order_with_greedy(const std::vector>& wipe_volumes, + const std::vector curr_layer_extruders, + const std::optional& start_extruder_id, + float* min_cost) + { + float cost = 0; + std::vector best_seq; + std::vectoris_visited(curr_layer_extruders.size(), false); + std::optionalprev_filament = start_extruder_id; + int idx = curr_layer_extruders.size(); + while (idx > 0) { + if (!prev_filament) { + auto iter = std::find_if(is_visited.begin(), is_visited.end(), [](auto item) {return item == 0; }); + assert(iter != is_visited.end()); + prev_filament = curr_layer_extruders[iter - is_visited.begin()]; + } + int target_idx = -1; + int target_cost = std::numeric_limits::max(); + for (size_t k = 0; k < is_visited.size(); ++k) { + if (!is_visited[k]) { + if (wipe_volumes[*prev_filament][curr_layer_extruders[k]] < target_cost) { + target_idx = k; + target_cost = wipe_volumes[*prev_filament][curr_layer_extruders[k]]; + } + } + } + assert(target_idx != -1); + cost += target_cost; + best_seq.emplace_back(curr_layer_extruders[target_idx]); + prev_filament = curr_layer_extruders[target_idx]; + is_visited[target_idx] = true; + idx -= 1; + } + if (min_cost) + *min_cost = cost; + return best_seq; + } + + //solve the problem by forcasting one layer + static std::vector solve_extruder_order_with_forcast(const std::vector>& wipe_volumes, + std::vector curr_layer_extruders, + std::vector next_layer_extruders, + const std::optional& start_extruder_id, + float* min_cost) + { + std::sort(curr_layer_extruders.begin(), curr_layer_extruders.end()); + std::sort(next_layer_extruders.begin(), next_layer_extruders.end()); + float best_cost = std::numeric_limits::max(); + std::vectorbest_seq; + + do { + std::optionalprev_extruder_1 = start_extruder_id; + float curr_layer_cost = 0; + for (size_t idx = 0; idx < curr_layer_extruders.size(); ++idx) { + if (prev_extruder_1) + curr_layer_cost += wipe_volumes[*prev_extruder_1][curr_layer_extruders[idx]]; + prev_extruder_1 = curr_layer_extruders[idx]; + } + if (curr_layer_cost > best_cost) + continue; + do { + std::optionalprev_extruder_2 = prev_extruder_1; + float total_cost = curr_layer_cost; + + for (size_t idx = 0; idx < next_layer_extruders.size(); ++idx) { + if (prev_extruder_2) + total_cost += wipe_volumes[*prev_extruder_2][next_layer_extruders[idx]]; + prev_extruder_2 = next_layer_extruders[idx]; + } + + if (total_cost < best_cost) { + best_cost = total_cost; + best_seq = curr_layer_extruders; + } + } while (std::next_permutation(next_layer_extruders.begin(), next_layer_extruders.end())); + } while (std::next_permutation(curr_layer_extruders.begin(), curr_layer_extruders.end())); + + if (min_cost) { + float real_cost = 0; + std::optionalprev_extruder = start_extruder_id; + for (size_t idx = 0; idx < best_seq.size(); ++idx) { + if (prev_extruder) + real_cost += wipe_volumes[*prev_extruder][best_seq[idx]]; + prev_extruder = best_seq[idx]; + } + *min_cost = real_cost; + } + return best_seq; + } + + // Shortest hamilton path problem + static std::vector solve_extruder_order(const std::vector>& wipe_volumes, + std::vector all_extruders, + std::optional start_extruder_id, + float* min_cost) + { + bool add_start_extruder_flag = false; + + if (start_extruder_id) { + auto start_iter = std::find(all_extruders.begin(), all_extruders.end(), start_extruder_id); + if (start_iter == all_extruders.end()) + all_extruders.insert(all_extruders.begin(), *start_extruder_id), add_start_extruder_flag = true; + else + std::swap(*all_extruders.begin(), *start_iter); + } + else { + start_extruder_id = all_extruders.front(); + } + + unsigned int iterations = (1 << all_extruders.size()); + unsigned int final_state = iterations - 1; + std::vector>cache(iterations, std::vector(all_extruders.size(), 0x7fffffff)); + std::vector>prev(iterations, std::vector(all_extruders.size(), -1)); + cache[1][0] = 0.; + for (unsigned int state = 0; state < iterations; ++state) { + if (state & 1) { + for (unsigned int target = 0; target < all_extruders.size(); ++target) { + if (state >> target & 1) { + for (unsigned int mid_point = 0; mid_point < all_extruders.size(); ++mid_point) { + if (state >> mid_point & 1) { + auto tmp = cache[state - (1 << target)][mid_point] + wipe_volumes[all_extruders[mid_point]][all_extruders[target]]; + if (cache[state][target] > tmp) { + cache[state][target] = tmp; + prev[state][target] = mid_point; + } + } + } + } + } + } + } + + //get res + float cost = std::numeric_limits::max(); + int final_dst = 0; + for (unsigned int dst = 0; dst < all_extruders.size(); ++dst) { + if (all_extruders[dst] != start_extruder_id && cost > cache[final_state][dst]) { + cost = cache[final_state][dst]; + if (min_cost) + *min_cost = cost; + final_dst = dst; + } + } + + std::vectorpath; + unsigned int curr_state = final_state; + int curr_point = final_dst; + while (curr_point != -1) { + path.emplace_back(all_extruders[curr_point]); + auto mid_point = prev[curr_state][curr_point]; + curr_state -= (1 << curr_point); + curr_point = mid_point; + }; + + if (add_start_extruder_flag) + path.pop_back(); + + std::reverse(path.begin(), path.end()); + return path; + } + + + // get best filament order of single nozzle + std::vector get_extruders_order(const std::vector>& wipe_volumes, + const std::vector& curr_layer_extruders, + const std::vector& next_layer_extruders, + const std::optional& start_extruder_id, + bool use_forcast, + float* cost) + { + if (curr_layer_extruders.empty()) { + if (cost) + *cost = 0; + return curr_layer_extruders; + } + if (curr_layer_extruders.size() == 1) { + if (cost) { + *cost = 0; + if (start_extruder_id) + *cost = wipe_volumes[*start_extruder_id][curr_layer_extruders[0]]; + } + return curr_layer_extruders; + } + + if (use_forcast) + return solve_extruder_order_with_forcast(wipe_volumes, curr_layer_extruders, next_layer_extruders, start_extruder_id, cost); + else if (curr_layer_extruders.size() <= 20) + return solve_extruder_order(wipe_volumes, curr_layer_extruders, start_extruder_id, cost); + else + return solve_extruder_order_with_greedy(wipe_volumes, curr_layer_extruders, start_extruder_id, cost); + } + + + + int reorder_filaments_for_minimum_flush_volume(const std::vector& filament_lists, + const std::vector& filament_maps, + const std::vector>& layer_filaments, + const std::vector& flush_matrix, + std::optional&)>> get_custom_seq, + std::vector>* filament_sequences) + { + //only when layer filament num <= 5,we do forcast + constexpr int max_n_with_forcast = 5; + int cost = 0; + std::vector>groups(2); //save the grouped filaments + std::vector>> layer_sequences(2); //save the reordered filament sequence by group + std::map> custom_layer_filament_map; //save the custom layers,second key stores the last extruder of that layer by group + std::map> custom_layer_sequence_map; // save the filament sequences of custom layer + + // group the filament + for (int i = 0; i < filament_maps.size(); ++i) { + if (filament_maps[i] == 0) + groups[0].insert(filament_lists[i]); + if (filament_maps[i] == 1) + groups[1].insert(filament_lists[i]); + } + + // store custom layer sequence + for (size_t layer = 0; layer < layer_filaments.size(); ++layer) { + const auto& curr_lf = layer_filaments[layer]; + + std::vectorcustom_filament_seq; + if (get_custom_seq && (*get_custom_seq)(layer, custom_filament_seq) && !custom_filament_seq.empty()) { + std::vector unsign_custom_extruder_seq; + for (int extruder : custom_filament_seq) { + unsigned int unsign_extruder = static_cast(extruder) - 1; + auto it = std::find(curr_lf.begin(), curr_lf.end(), unsign_extruder); + if (it != curr_lf.end()) + unsign_custom_extruder_seq.emplace_back(unsign_extruder); + } + assert(curr_lf.size() == unsign_custom_extruder_seq.size()); + + custom_layer_sequence_map[layer] = unsign_custom_extruder_seq; + custom_layer_filament_map[layer].resize(2, -1); + + for (auto iter = unsign_custom_extruder_seq.rbegin(); iter != unsign_custom_extruder_seq.rend(); ++iter) { + if (groups[0].find(*iter) != groups[0].end() && custom_layer_filament_map[layer][0] == -1) + custom_layer_filament_map[layer][0] = *iter; + if (groups[1].find(*iter) != groups[1].end() && custom_layer_filament_map[layer][1] == -1) + custom_layer_filament_map[layer][1] = *iter; + } + } + } + + using uint128_t = boost::multiprecision::uint128_t; + auto extruders_to_hash_key = [](const std::vector& curr_layer_extruders, + const std::vector& next_layer_extruders, + const std::optional& prev_extruder, + bool use_forcast)->uint128_t + { + uint128_t hash_key = 0; + //31-0 bit define current layer extruder,63-32 bit define next layer extruder,95~64 define prev extruder + if (prev_extruder) + hash_key |= (uint128_t(1) << (64 + *prev_extruder)); + + if (use_forcast) { + for (auto item : next_layer_extruders) + hash_key |= (uint128_t(1) << (32 + item)); + } + + for (auto item : curr_layer_extruders) + hash_key |= (uint128_t(1) << item); + return hash_key; + }; + + + // get best layer sequence by group + for (size_t idx = 0; idx < groups.size(); ++idx) { + // case with one group + if (groups[idx].empty()) + continue; + std::optionalcurrent_extruder_id; + + std::unordered_map>> caches; + + for (size_t layer = 0; layer < layer_filaments.size(); ++layer) { + const auto& curr_lf = layer_filaments[layer]; + std::vectorcustom_filament_seq; + if (get_custom_seq && (*get_custom_seq)(layer, custom_filament_seq) && !custom_filament_seq.empty()) { + if (custom_layer_filament_map[layer][idx] != -1) + current_extruder_id = (unsigned int)(custom_layer_filament_map[layer][idx]); + //insert an empty array + if (filament_sequences) + layer_sequences[idx].emplace_back(std::vector()); + continue; + } + + std::vectorfilament_used_in_group; + for (const auto& filament : curr_lf) { + if (groups[idx].find(filament) != groups[idx].end()) + filament_used_in_group.emplace_back(filament); + } + + std::vectorfilament_used_in_group_next_layer; + { + std::vectornext_lf; + if (layer + 1 < layer_filaments.size()) + next_lf = layer_filaments[layer + 1]; + for (const auto& filament : next_lf) { + if (groups[idx].find(filament) != groups[idx].end()) + filament_used_in_group_next_layer.emplace_back(filament); + } + } + + bool use_forcast = (filament_used_in_group.size() <= max_n_with_forcast && filament_used_in_group_next_layer.size() <= max_n_with_forcast); + float tmp_cost = 0; + std::vectorsequence; + uint128_t hash_key = extruders_to_hash_key(filament_used_in_group, filament_used_in_group_next_layer, current_extruder_id, use_forcast); + if (auto iter = caches.find(hash_key); iter != caches.end()) { + tmp_cost = iter->second.first; + sequence = iter->second.second; + } + else { + sequence = get_extruders_order(flush_matrix[idx], filament_used_in_group, filament_used_in_group_next_layer, current_extruder_id, use_forcast, &tmp_cost); + caches[hash_key] = { tmp_cost,sequence }; + } + + assert(sequence.size() == filament_used_in_group.size()); + + if (filament_sequences) + layer_sequences[idx].emplace_back(sequence); + + if (!sequence.empty()) + current_extruder_id = sequence.back(); + cost += tmp_cost; + } + } + + // get the final layer sequences + // if only have one group,we need to check whether layer sequence[idx] is valid + if (filament_sequences) { + filament_sequences->clear(); + filament_sequences->resize(layer_filaments.size()); + + bool last_group = 0; + //if last_group == 0,print group 0 first ,else print group 1 first + if (!custom_layer_sequence_map.empty()) { + int custom_first_layer = custom_layer_sequence_map.begin()->first; + bool custom_first_group = groups[0].count(custom_first_layer) ? 0 : 1; + last_group = (custom_first_layer & 1) ? !custom_first_group : custom_first_group; + } + + for (size_t layer = 0; layer < layer_filaments.size(); ++layer) { + auto& curr_layer_seq = (*filament_sequences)[layer]; + if (custom_layer_sequence_map.find(layer) != custom_layer_sequence_map.end()) { + curr_layer_seq = custom_layer_sequence_map[layer]; + if (!curr_layer_seq.empty()) { + last_group = groups[0].count(curr_layer_seq.back()) ? 0 : 1; + } + continue; + } + if (last_group) { + if (!layer_sequences[1].empty()) + curr_layer_seq.insert(curr_layer_seq.end(), layer_sequences[1][layer].begin(), layer_sequences[1][layer].end()); + if (!layer_sequences[0].empty()) + curr_layer_seq.insert(curr_layer_seq.end(), layer_sequences[0][layer].begin(), layer_sequences[0][layer].end()); + } + else { + if (!layer_sequences[0].empty()) + curr_layer_seq.insert(curr_layer_seq.end(), layer_sequences[0][layer].begin(), layer_sequences[0][layer].end()); + if (!layer_sequences[1].empty()) + curr_layer_seq.insert(curr_layer_seq.end(), layer_sequences[1][layer].begin(), layer_sequences[1][layer].end()); + } + last_group = !last_group; + } + } + + return cost; + } + +} diff --git a/src/libslic3r/GCode/ToolOrderUtils.hpp b/src/libslic3r/GCode/ToolOrderUtils.hpp new file mode 100644 index 000000000..14ba2a7b9 --- /dev/null +++ b/src/libslic3r/GCode/ToolOrderUtils.hpp @@ -0,0 +1,29 @@ +#ifndef TOOL_ORDER_UTILS_HPP +#define TOOL_ORDER_UTILS_HPP + +#include +#include +#include + +namespace Slic3r { + +using FlushMatrix = std::vector>; + + +std::vector get_extruders_order(const std::vector> &wipe_volumes, + const std::vector &curr_layer_extruders, + const std::vector &next_layer_extruders, + const std::optional &start_extruder_id, + bool use_forcast = false, + float *cost = nullptr); + +int reorder_filaments_for_minimum_flush_volume(const std::vector &filament_lists, + const std::vector &filament_maps, + const std::vector> &layer_filaments, + const std::vector &flush_matrix, + std::optional &)>> get_custom_seq, + std::vector> *filament_sequences); + + +} +#endif // !TOOL_ORDER_UTILS_HPP diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index fb708ea98..ba76e9c51 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -3,6 +3,7 @@ #include "Layer.hpp" #include "ClipperUtils.hpp" #include "ParameterUtils.hpp" +#include "GCode/ToolOrderUtils.hpp" // #define SLIC3R_DEBUG // Make assert active if SLIC3R_DEBUG @@ -18,379 +19,11 @@ #include #include -#include namespace Slic3r { const static bool g_wipe_into_objects = false; - - -static std::vectorsolve_extruder_order_with_greedy(const std::vector>& wipe_volumes, - const std::vector curr_layer_extruders, - const std::optional&start_extruder_id, - float* min_cost) -{ - float cost = 0; - std::vector best_seq; - std::vectoris_visited(curr_layer_extruders.size(), false); - std::optionalprev_filament = start_extruder_id; - int idx = curr_layer_extruders.size(); - while (idx > 0) { - if (!prev_filament) { - auto iter = std::find_if(is_visited.begin(), is_visited.end(), [](auto item) {return item == 0; }); - assert(iter != is_visited.end()); - prev_filament = curr_layer_extruders[iter - is_visited.begin()]; - } - int target_idx = -1; - int target_cost = std::numeric_limits::max(); - for (size_t k = 0; k < is_visited.size(); ++k) { - if (!is_visited[k]) { - if (wipe_volumes[*prev_filament][curr_layer_extruders[k]] < target_cost) { - target_idx = k; - target_cost = wipe_volumes[*prev_filament][curr_layer_extruders[k]]; - } - } - } - assert(target_idx != -1); - cost += target_cost; - best_seq.emplace_back(curr_layer_extruders[target_idx]); - prev_filament = curr_layer_extruders[target_idx]; - is_visited[target_idx] = true; - idx -= 1; - } - if (min_cost) - *min_cost = cost; - return best_seq; -} - -//solve the probleme by forcasting one layer -static std::vectorsolve_extruder_order_with_forcast(const std::vector>& wipe_volumes, - std::vector curr_layer_extruders, - std::vector next_layer_extruders, - const std::optional& start_extruder_id, - float* min_cost) -{ - std::sort(curr_layer_extruders.begin(), curr_layer_extruders.end()); - std::sort(next_layer_extruders.begin(), next_layer_extruders.end()); - float best_cost = std::numeric_limits::max(); - std::vectorbest_seq; - - do { - std::optionalprev_extruder_1 = start_extruder_id; - float curr_layer_cost = 0; - for (size_t idx = 0; idx < curr_layer_extruders.size(); ++idx) { - if (prev_extruder_1) - curr_layer_cost += wipe_volumes[*prev_extruder_1][curr_layer_extruders[idx]]; - prev_extruder_1 = curr_layer_extruders[idx]; - } - if (curr_layer_cost > best_cost) - continue; - do { - std::optionalprev_extruder_2 = prev_extruder_1; - float total_cost = curr_layer_cost; - - for (size_t idx = 0; idx < next_layer_extruders.size(); ++idx) { - if (prev_extruder_2) - total_cost += wipe_volumes[*prev_extruder_2][next_layer_extruders[idx]]; - prev_extruder_2 = next_layer_extruders[idx]; - } - - if (total_cost < best_cost) { - best_cost = total_cost; - best_seq = curr_layer_extruders; - } - } while (std::next_permutation(next_layer_extruders.begin(), next_layer_extruders.end())); - } while (std::next_permutation(curr_layer_extruders.begin(),curr_layer_extruders.end())); - - if (min_cost) { - float real_cost = 0; - std::optionalprev_extruder = start_extruder_id; - for (size_t idx = 0; idx < best_seq.size(); ++idx) { - if (prev_extruder) - real_cost += wipe_volumes[*prev_extruder][best_seq[idx]]; - prev_extruder = best_seq[idx]; - } - *min_cost = real_cost; - } - return best_seq; -} - - -// Shortest hamilton path problem -static std::vector solve_extruder_order(const std::vector>& wipe_volumes, std::vector all_extruders, std::optional start_extruder_id, float* min_cost) -{ - bool add_start_extruder_flag = false; - - if (start_extruder_id) { - auto start_iter = std::find(all_extruders.begin(), all_extruders.end(), start_extruder_id); - if (start_iter == all_extruders.end()) - all_extruders.insert(all_extruders.begin(), *start_extruder_id), add_start_extruder_flag = true; - else - std::swap(*all_extruders.begin(), *start_iter); - } - else { - start_extruder_id = all_extruders.front(); - } - - unsigned int iterations = (1 << all_extruders.size()); - unsigned int final_state = iterations - 1; - std::vector>cache(iterations, std::vector(all_extruders.size(),0x7fffffff)); - std::vector>prev(iterations, std::vector(all_extruders.size(), -1)); - cache[1][0] = 0.; - for (unsigned int state = 0; state < iterations; ++state) { - if (state & 1) { - for (unsigned int target = 0; target < all_extruders.size(); ++target) { - if (state >> target & 1) { - for (unsigned int mid_point = 0; mid_point < all_extruders.size(); ++mid_point) { - if(state>>mid_point&1){ - auto tmp = cache[state - (1 << target)][mid_point] + wipe_volumes[all_extruders[mid_point]][all_extruders[target]]; - if (cache[state][target] >tmp) { - cache[state][target] = tmp; - prev[state][target] = mid_point; - } - } - } - } - } - } - } - - //get res - float cost = std::numeric_limits::max(); - int final_dst =0; - for (unsigned int dst = 0; dst < all_extruders.size(); ++dst) { - if (all_extruders[dst] != start_extruder_id && cost > cache[final_state][dst]) { - cost = cache[final_state][dst]; - if (min_cost) - *min_cost = cost; - final_dst = dst; - } - } - - std::vectorpath; - unsigned int curr_state = final_state; - int curr_point = final_dst; - while (curr_point != -1) { - path.emplace_back(all_extruders[curr_point]); - auto mid_point = prev[curr_state][curr_point]; - curr_state -= (1 << curr_point); - curr_point = mid_point; - }; - - if (add_start_extruder_flag) - path.pop_back(); - - std::reverse(path.begin(), path.end()); - return path; -} - -std::vector get_extruders_order(const std::vector> &wipe_volumes, - const std::vector& curr_layer_extruders, - const std::vector&next_layer_extruders, - const std::optional&start_extruder_id, - bool use_forcast = false, - float* cost = nullptr) -{ - if (curr_layer_extruders.empty()) { - if (cost) - *cost = 0; - return curr_layer_extruders; - } - if (curr_layer_extruders.size() == 1) { - if (cost) { - *cost = 0; - if (start_extruder_id) - *cost = wipe_volumes[*start_extruder_id][curr_layer_extruders[0]]; - } - return curr_layer_extruders; - } - - if (use_forcast) - return solve_extruder_order_with_forcast(wipe_volumes, curr_layer_extruders, next_layer_extruders, start_extruder_id, cost); - else if(curr_layer_extruders.size() <= 20) - return solve_extruder_order(wipe_volumes, curr_layer_extruders, start_extruder_id, cost); - else - return solve_extruder_order_with_greedy(wipe_volumes,curr_layer_extruders,start_extruder_id,cost); -} - -int reorder_filaments_for_minimum_flush_volume(const std::vector&filament_lists, - const std::vector&filament_maps, - const std::vector>& layer_filaments, - const std::vector& flush_matrix, - std::optional&)>> get_custom_seq, - std::vector>* filament_sequences) -{ - constexpr int max_n_with_forcast = 7; - int cost = 0; - std::vector>groups(2); //save the grouped filaments - std::vector>> layer_sequences(2); //save the reordered filament sequence by group - std::map> custom_layer_filament_map; //save the custom layers,second key stores the last extruder of that layer by group - std::map> custom_layer_sequence_map; // save the filament sequences of custom layer - - // group the filament - for (int i = 0; i < filament_maps.size(); ++i) { - if (filament_maps[i] == 0) - groups[0].insert(filament_lists[i]); - if (filament_maps[i] == 1) - groups[1].insert(filament_lists[i]); - } - - // store custom layer sequence - for (size_t layer = 0; layer < layer_filaments.size(); ++layer) { - const auto& curr_lf = layer_filaments[layer]; - - std::vectorcustom_filament_seq; - if (get_custom_seq && (*get_custom_seq)(layer, custom_filament_seq) && !custom_filament_seq.empty()) { - std::vector unsign_custom_extruder_seq; - for (int extruder : custom_filament_seq) { - unsigned int unsign_extruder = static_cast(extruder) - 1; - auto it = std::find(curr_lf.begin(), curr_lf.end(), unsign_extruder); - if (it != curr_lf.end()) - unsign_custom_extruder_seq.emplace_back(unsign_extruder); - } - assert(curr_lf.size() == unsign_custom_extruder_seq.size()); - - custom_layer_sequence_map[layer] = unsign_custom_extruder_seq; - custom_layer_filament_map[layer].resize(2, -1); - - for (auto iter = unsign_custom_extruder_seq.rbegin(); iter != unsign_custom_extruder_seq.rend(); ++iter) { - if (groups[0].find(*iter) != groups[0].end() && custom_layer_filament_map[layer][0] == -1) - custom_layer_filament_map[layer][0] = *iter; - if (groups[1].find(*iter) != groups[1].end() && custom_layer_filament_map[layer][1] == -1) - custom_layer_filament_map[layer][1] = *iter; - } - } - } - - using uint128_t = boost::multiprecision::uint128_t; - auto extruders_to_hash_key = [](const std::vector& curr_layer_extruders, - const std::vector& next_layer_extruders, - const std::optional& prev_extruder, - bool use_forcast)->uint128_t - { - uint128_t hash_key = 0; - //31-0 bit define current layer extruder,63-32 bit define next layer extruder,95~64 define prev extruder - if (prev_extruder) - hash_key |= (uint128_t(1) << (64 + *prev_extruder)); - - if (use_forcast) { - for (auto item : next_layer_extruders) - hash_key |= (uint128_t(1) << (32 + item)); - } - - for (auto item : curr_layer_extruders) - hash_key |= (uint128_t(1) << item); - return hash_key; - }; - - - // get best layer sequence by group - for (size_t idx = 0; idx < groups.size();++idx) { - // case with one group - if (groups[idx].empty()) - continue; - std::optionalcurrent_extruder_id; - - std::unordered_map>> caches; - - for(size_t layer=0;layercustom_filament_seq; - if (get_custom_seq && (*get_custom_seq)(layer, custom_filament_seq) && !custom_filament_seq.empty()) { - if (custom_layer_filament_map[layer][idx] != -1) - current_extruder_id = (unsigned int)(custom_layer_filament_map[layer][idx]); - //insert an empty array - if (filament_sequences) - layer_sequences[idx].emplace_back(std::vector()); - continue; - } - - std::vectorfilament_used_in_group; - for (const auto& filament : curr_lf) { - if (groups[idx].find(filament) != groups[idx].end()) - filament_used_in_group.emplace_back(filament); - } - - std::vectorfilament_used_in_group_next_layer; - { - std::vectornext_lf; - if (layer + 1 < layer_filaments.size()) - next_lf = layer_filaments[layer + 1]; - for (const auto& filament : next_lf) { - if (groups[idx].find(filament) != groups[idx].end()) - filament_used_in_group_next_layer.emplace_back(filament); - } - } - - bool use_forcast = (groups[0].size()<=max_n_with_forcast && groups[1].size()<=max_n_with_forcast) ; - float tmp_cost = 0; - std::vectorsequence; - uint128_t hash_key = extruders_to_hash_key(filament_used_in_group, filament_used_in_group_next_layer, current_extruder_id, use_forcast); - if (auto iter = caches.find(hash_key); iter != caches.end()) { - tmp_cost = iter->second.first; - sequence = iter->second.second; - } - else { - sequence = get_extruders_order(flush_matrix[idx], filament_used_in_group, filament_used_in_group_next_layer,current_extruder_id,use_forcast,&tmp_cost); - caches[hash_key] = { tmp_cost,sequence }; - } - - assert(sequence.size()==filament_used_in_group.size()); - - if (filament_sequences) - layer_sequences[idx].emplace_back(sequence); - - if (!sequence.empty()) - current_extruder_id = sequence.back(); - cost += tmp_cost; - } - } - - // get the final layer sequences - // if only have one group,we need to check whether layer sequence[idx] is valid - if (filament_sequences) { - filament_sequences->clear(); - filament_sequences->resize(layer_filaments.size()); - - bool last_group = 0; - //if last_group == 0,print group 0 first ,else print group 1 first - if (!custom_layer_sequence_map.empty()) { - int custom_first_layer = custom_layer_sequence_map.begin()->first; - bool custom_first_group = groups[0].count(custom_first_layer) ? 0 : 1; - last_group = (custom_first_layer & 1) ? !custom_first_group : custom_first_group; - } - - for (size_t layer = 0; layer < layer_filaments.size(); ++layer) { - auto& curr_layer_seq = (*filament_sequences)[layer]; - if (custom_layer_sequence_map.find(layer) != custom_layer_sequence_map.end()) { - curr_layer_seq = custom_layer_sequence_map[layer]; - if (!curr_layer_seq.empty()) { - last_group = groups[0].count(curr_layer_seq.back()) ? 0 : 1; - } - continue; - } - if (last_group) { - if (!layer_sequences[1].empty()) - curr_layer_seq.insert(curr_layer_seq.end(), layer_sequences[1][layer].begin(), layer_sequences[1][layer].end()); - if (!layer_sequences[0].empty()) - curr_layer_seq.insert(curr_layer_seq.end(), layer_sequences[0][layer].begin(), layer_sequences[0][layer].end()); - } - else { - if (!layer_sequences[0].empty()) - curr_layer_seq.insert(curr_layer_seq.end(), layer_sequences[0][layer].begin(), layer_sequences[0][layer].end()); - if (!layer_sequences[1].empty()) - curr_layer_seq.insert(curr_layer_seq.end(), layer_sequences[1][layer].begin(), layer_sequences[1][layer].end()); - } - last_group = !last_group; - } - } - - return cost; -} - - - // Returns true in case that extruder a comes before b (b does not have to be present). False otherwise. bool LayerTools::is_extruder_order(unsigned int a, unsigned int b) const { @@ -1181,16 +814,16 @@ std::vector ToolOrdering::get_recommended_filament_maps(const std::vector(); - const unsigned int number_of_extruders = (unsigned int) (print_config->filament_colour.values.size() + EPSILON); + const unsigned int filament_nums = (unsigned int) (print_config->filament_colour.values.size() + EPSILON); // get flush matrix std::vector nozzle_flush_mtx; - size_t nozzle_nums = print_config->nozzle_diameter.values.size(); - for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) { - std::vector flush_matrix(cast(get_flush_volumes_matrix(print_config->flush_volumes_matrix.values, nozzle_id, nozzle_nums))); + size_t extruder_nums = print_config->nozzle_diameter.values.size(); + for (size_t nozzle_id = 0; nozzle_id < extruder_nums; ++nozzle_id) { + std::vector flush_matrix(cast(get_flush_volumes_matrix(print_config->flush_volumes_matrix.values, nozzle_id, extruder_nums))); std::vector> wipe_volumes; - for (unsigned int i = 0; i < number_of_extruders; ++i) - wipe_volumes.push_back(std::vector(flush_matrix.begin() + i * number_of_extruders, flush_matrix.begin() + (i + 1) * number_of_extruders)); + for (unsigned int i = 0; i < filament_nums; ++i) + wipe_volumes.push_back(std::vector(flush_matrix.begin() + i * filament_nums, flush_matrix.begin() + (i + 1) * filament_nums)); nozzle_flush_mtx.emplace_back(wipe_volumes); } @@ -1216,18 +849,9 @@ std::vector ToolOrdering::get_recommended_filament_maps(const std::vectorused_filaments; - for (auto& one_layer_filaments : layer_filaments) { - for (unsigned int filament : one_layer_filaments) { - if (std::find(used_filaments.begin(), used_filaments.end(), filament) == used_filaments.end()) - used_filaments.emplace_back(filament); - } - } - std::sort(used_filaments.begin(), used_filaments.end()); - - std::vectorret(number_of_extruders,0); + std::vectorret(filament_nums,0); // if mutli_extruder, calc group,otherwise set to 0 - if (nozzle_nums == 2) + if (extruder_nums == 2) { std::vector extruder_ams_count_str = print_config->extruder_ams_count.values; auto extruder_ams_counts = get_extruder_ams_count(extruder_ams_count_str); @@ -1236,7 +860,7 @@ std::vector ToolOrdering::get_recommended_filament_maps(const std::vectorfirst * iter->second; } @@ -1245,17 +869,11 @@ std::vector ToolOrdering::get_recommended_filament_maps(const std::vector& filament_lists, - const std::vector& filament_maps, - const std::vector>& layer_filaments, - const std::vector& flush_matrix, - std::optional&)>> get_custom_seq, - std::vector>* filament_sequences); // Object of this class holds information about whether an extrusion is printed immediately // after a toolchange (as part of infill/perimeter wiping) or not. One extrusion can be a part // of several copies - this has to be taken into account.